commit | dc314a30ee814ed40b308375c8ff8b60a98a7661 | [log] [tgz] |
---|---|---|
author | Myles Watson <mylesgw@google.com> | Wed Mar 15 18:40:06 2017 +0000 |
committer | android-build-merger <android-build-merger@google.com> | Wed Mar 15 18:40:06 2017 +0000 |
tree | b2e62f98b78fc9a45beef8ecad0dcd14aa16b6ca | |
parent | 360cad209ab2a6f758c898b76681cf2706190e92 [diff] | |
parent | 535f43a380537e8196cd3d04c537ab58cc234b3e [diff] |
Bluetooth: Don't disable LPM at power off am: 3b2a29676b am: 2fe40fdd3c am: 535f43a380 Change-Id: I277adfa8063013545f016d5590161fd22b0fb189
diff --git a/audio/2.0/Android.bp b/audio/2.0/Android.bp new file mode 100644 index 0000000..69ff791 --- /dev/null +++ b/audio/2.0/Android.bp
@@ -0,0 +1,106 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.audio@2.0_hal", + srcs: [ + "types.hal", + "IDevice.hal", + "IDevicesFactory.hal", + "IPrimaryDevice.hal", + "IStream.hal", + "IStreamIn.hal", + "IStreamOut.hal", + "IStreamOutCallback.hal", + ], +} + +genrule { + name: "android.hardware.audio@2.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio@2.0", + srcs: [ + ":android.hardware.audio@2.0_hal", + ], + out: [ + "android/hardware/audio/2.0/types.cpp", + "android/hardware/audio/2.0/DeviceAll.cpp", + "android/hardware/audio/2.0/DevicesFactoryAll.cpp", + "android/hardware/audio/2.0/PrimaryDeviceAll.cpp", + "android/hardware/audio/2.0/StreamAll.cpp", + "android/hardware/audio/2.0/StreamInAll.cpp", + "android/hardware/audio/2.0/StreamOutAll.cpp", + "android/hardware/audio/2.0/StreamOutCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.audio@2.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio@2.0", + srcs: [ + ":android.hardware.audio@2.0_hal", + ], + out: [ + "android/hardware/audio/2.0/types.h", + "android/hardware/audio/2.0/IDevice.h", + "android/hardware/audio/2.0/IHwDevice.h", + "android/hardware/audio/2.0/BnHwDevice.h", + "android/hardware/audio/2.0/BpHwDevice.h", + "android/hardware/audio/2.0/BsDevice.h", + "android/hardware/audio/2.0/IDevicesFactory.h", + "android/hardware/audio/2.0/IHwDevicesFactory.h", + "android/hardware/audio/2.0/BnHwDevicesFactory.h", + "android/hardware/audio/2.0/BpHwDevicesFactory.h", + "android/hardware/audio/2.0/BsDevicesFactory.h", + "android/hardware/audio/2.0/IPrimaryDevice.h", + "android/hardware/audio/2.0/IHwPrimaryDevice.h", + "android/hardware/audio/2.0/BnHwPrimaryDevice.h", + "android/hardware/audio/2.0/BpHwPrimaryDevice.h", + "android/hardware/audio/2.0/BsPrimaryDevice.h", + "android/hardware/audio/2.0/IStream.h", + "android/hardware/audio/2.0/IHwStream.h", + "android/hardware/audio/2.0/BnHwStream.h", + "android/hardware/audio/2.0/BpHwStream.h", + "android/hardware/audio/2.0/BsStream.h", + "android/hardware/audio/2.0/IStreamIn.h", + "android/hardware/audio/2.0/IHwStreamIn.h", + "android/hardware/audio/2.0/BnHwStreamIn.h", + "android/hardware/audio/2.0/BpHwStreamIn.h", + "android/hardware/audio/2.0/BsStreamIn.h", + "android/hardware/audio/2.0/IStreamOut.h", + "android/hardware/audio/2.0/IHwStreamOut.h", + "android/hardware/audio/2.0/BnHwStreamOut.h", + "android/hardware/audio/2.0/BpHwStreamOut.h", + "android/hardware/audio/2.0/BsStreamOut.h", + "android/hardware/audio/2.0/IStreamOutCallback.h", + "android/hardware/audio/2.0/IHwStreamOutCallback.h", + "android/hardware/audio/2.0/BnHwStreamOutCallback.h", + "android/hardware/audio/2.0/BpHwStreamOutCallback.h", + "android/hardware/audio/2.0/BsStreamOutCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.audio@2.0", + generated_sources: ["android.hardware.audio@2.0_genc++"], + generated_headers: ["android.hardware.audio@2.0_genc++_headers"], + export_generated_headers: ["android.hardware.audio@2.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.audio.common@2.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.audio.common@2.0", + "android.hidl.base@1.0", + ], +}
diff --git a/audio/2.0/Android.mk b/audio/2.0/Android.mk new file mode 100644 index 0000000..e989364 --- /dev/null +++ b/audio/2.0/Android.mk
@@ -0,0 +1,46 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.audio@2.0-java-constants +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +# +GEN := $(intermediates)/android/hardware/audio/V2_0/Constants.java +$(GEN): $(HIDL) +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/IDevice.hal +$(GEN): $(LOCAL_PATH)/IDevicesFactory.hal +$(GEN): $(LOCAL_PATH)/IPrimaryDevice.hal +$(GEN): $(LOCAL_PATH)/IStream.hal +$(GEN): $(LOCAL_PATH)/IStreamIn.hal +$(GEN): $(LOCAL_PATH)/IStreamOut.hal +$(GEN): $(LOCAL_PATH)/IStreamOutCallback.hal + +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava-constants \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.audio@2.0 + +$(GEN): + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +# Avoid dependency cycle of framework.jar -> this-library -> framework.jar +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj + +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio/2.0/IDevice.hal b/audio/2.0/IDevice.hal new file mode 100644 index 0000000..2b5329b --- /dev/null +++ b/audio/2.0/IDevice.hal
@@ -0,0 +1,246 @@ +/* + * Copyright (C) 2016 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.audio@2.0; + +import android.hardware.audio.common@2.0; +import IStreamIn; +import IStreamOut; + +interface IDevice { + typedef android.hardware.audio@2.0::Result Result; + + /* + * Returns whether the audio hardware interface has been initialized. + * + * @return retval OK on success, NOT_INITIALIZED on failure. + */ + initCheck() generates (Result retval); + + /* + * Sets the audio volume for all audio activities other than voice call. If + * NOT_SUPPORTED is returned, the software mixer will emulate this + * capability. + * + * @param volume 1.0f means unity, 0.0f is zero. + * @return retval operation completion status. + */ + setMasterVolume(float volume) generates (Result retval); + + /* + * Get the current master volume value for the HAL, if the HAL supports + * master volume control. For example, AudioFlinger will query this value + * from the primary audio HAL when the service starts and use the value for + * setting the initial master volume across all HALs. HALs which do not + * support this method must return NOT_SUPPORTED in 'retval'. + * + * @return retval operation completion status. + * @return volume 1.0f means unity, 0.0f is zero. + */ + getMasterVolume() generates (Result retval, float volume); + + /* + * Sets microphone muting state. + * + * @param mute whether microphone is muted. + * @return retval operation completion status. + */ + setMicMute(bool mute) generates (Result retval); + + /* + * Gets whether microphone is muted. + * + * @return retval operation completion status. + * @return mute whether microphone is muted. + */ + getMicMute() generates (Result retval, bool mute); + + /* + * Set the audio mute status for all audio activities. If the return value + * is NOT_SUPPORTED, the software mixer will emulate this capability. + * + * @param mute whether audio is muted. + * @return retval operation completion status. + */ + setMasterMute(bool mute) generates (Result retval); + + /** + * Get the current master mute status for the HAL, if the HAL supports + * master mute control. AudioFlinger will query this value from the primary + * audio HAL when the service starts and use the value for setting the + * initial master mute across all HALs. HAL must indicate that the feature + * is not supported by returning NOT_SUPPORTED status. + * + * @return retval operation completion status. + * @return mute whether audio is muted. + */ + getMasterMute() generates (Result retval, bool mute); + + /* + * Returns audio input buffer size according to parameters passed or + * INVALID_ARGUMENTS if one of the parameters is not supported. + * + * @param config audio configuration. + * @return retval operation completion status. + * @return bufferSize input buffer size in bytes. + */ + getInputBufferSize(AudioConfig config) + generates (Result retval, uint64_t bufferSize); + + /* + * This method creates and opens the audio hardware output stream. + * If the stream can not be opened with the proposed audio config, + * HAL must provide suggested values for the audio config. + * + * @param ioHandle handle assigned by AudioFlinger. + * @param device device type and (if needed) address. + * @param config stream configuration. + * @param flags additional flags. + * @return retval operation completion status. + * @return outStream created output stream. + * @return suggestedConfig in case of invalid parameters, suggested config. + */ + openOutputStream( + AudioIoHandle ioHandle, + DeviceAddress device, + AudioConfig config, + AudioOutputFlag flags) generates ( + Result retval, + IStreamOut outStream, + AudioConfig suggestedConfig); + + /* + * This method creates and opens the audio hardware input stream. + * If the stream can not be opened with the proposed audio config, + * HAL must provide suggested values for the audio config. + * + * @param ioHandle handle assigned by AudioFlinger. + * @param device device type and (if needed) address. + * @param config stream configuration. + * @param flags additional flags. + * @param source source specification. + * @return retval operation completion status. + * @return inStream in case of success, created input stream. + * @return suggestedConfig in case of invalid parameters, suggested config. + */ + openInputStream( + AudioIoHandle ioHandle, + DeviceAddress device, + AudioConfig config, + AudioInputFlag flags, + AudioSource source) generates ( + Result retval, + IStreamIn inStream, + AudioConfig suggestedConfig); + + /* + * Returns whether HAL supports audio patches. + * + * @return supports true if audio patches are supported. + */ + supportsAudioPatches() generates (bool supports); + + /* + * Creates an audio patch between several source and sink ports. The handle + * is allocated by the HAL and must be unique for this audio HAL module. + * + * @param sources patch sources. + * @param sinks patch sinks. + * @return retval operation completion status. + * @return patch created patch handle. + */ + createAudioPatch(vec<AudioPortConfig> sources, vec<AudioPortConfig> sinks) + generates (Result retval, AudioPatchHandle patch); + + /* + * Release an audio patch. + * + * @param patch patch handle. + * @return retval operation completion status. + */ + releaseAudioPatch(AudioPatchHandle patch) generates (Result retval); + + /* + * Returns the list of supported attributes for a given audio port. + * + * As input, 'port' contains the information (type, role, address etc...) + * needed by the HAL to identify the port. + * + * As output, 'resultPort' contains possible attributes (sampling rates, + * formats, channel masks, gain controllers...) for this port. + * + * @param port port identifier. + * @return retval operation completion status. + * @return resultPort port descriptor with all parameters filled up. + */ + getAudioPort(AudioPort port) + generates (Result retval, AudioPort resultPort); + + /* + * Set audio port configuration. + * + * @param config audio port configuration. + * @return retval operation completion status. + */ + setAudioPortConfig(AudioPortConfig config) generates (Result retval); + + /* + * Gets the HW synchronization source of the device. Calling this method is + * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL. + * + * @return hwAvSync HW synchronization source + */ + getHwAvSync() generates (AudioHwSync hwAvSync); + + /* + * Sets whether the screen is on. Calling this method is equivalent to + * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL. + * + * @param turnedOn whether the screen is turned on. + * @return retval operation completion status. + */ + setScreenState(bool turnedOn) generates (Result retval); + + /* + * Generic method for retrieving vendor-specific parameter values. + * The framework does not interpret the parameters, they are passed + * in an opaque manner between a vendor application and HAL. + * + * @param keys parameter keys. + * @return retval operation completion status. + * @return parameters parameter key value pairs. + */ + getParameters(vec<string> keys) + generates (Result retval, vec<ParameterValue> parameters); + + /* + * Generic method for setting vendor-specific parameter values. + * The framework does not interpret the parameters, they are passed + * in an opaque manner between a vendor application and HAL. + * + * @param parameters parameter key value pairs. + * @return retval operation completion status. + */ + setParameters(vec<ParameterValue> parameters) generates (Result retval); + + /* + * Dumps information about the stream into the provided file descriptor. + * This is used for the dumpsys facility. + * + * @param fd dump file descriptor. + */ + debugDump(handle fd); +};
diff --git a/audio/2.0/IDevicesFactory.hal b/audio/2.0/IDevicesFactory.hal new file mode 100644 index 0000000..0ef6bc5 --- /dev/null +++ b/audio/2.0/IDevicesFactory.hal
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 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.audio@2.0; + +import android.hardware.audio.common@2.0; +import IDevice; + +interface IDevicesFactory { + typedef android.hardware.audio@2.0::Result Result; + + enum Device : int32_t { + PRIMARY, + A2DP, + USB, + R_SUBMIX, + STUB + }; + + /* + * Opens an audio device. To close the device, it is necessary to release + * references to the returned device object. + * + * @param device device type. + * @return retval operation completion status. Returns INVALID_ARGUMENTS + * if there is no corresponding hardware module found, + * NOT_INITIALIZED if an error occured while opening the hardware + * module. + * @return result the interface for the created device. + */ + openDevice(Device device) generates (Result retval, IDevice result); +};
diff --git a/audio/2.0/IPrimaryDevice.hal b/audio/2.0/IPrimaryDevice.hal new file mode 100644 index 0000000..f1dd56e --- /dev/null +++ b/audio/2.0/IPrimaryDevice.hal
@@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016 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.audio@2.0; + +import android.hardware.audio.common@2.0; +import IDevice; + +interface IPrimaryDevice extends IDevice { + typedef android.hardware.audio@2.0::Result Result; + + /* + * Sets the audio volume of a voice call. + * + * @param volume 1.0f means unity, 0.0f is zero. + * @return retval operation completion status. + */ + setVoiceVolume(float volume) generates (Result retval); + + /* + * This method is used to notify the HAL about audio mode changes. + * + * @param mode new mode. + * @return retval operation completion status. + */ + setMode(AudioMode mode) generates (Result retval); + + /* + * Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled. + * Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC + * on the legacy HAL. + * + * @return retval operation completion status. + * @return enabled whether BT SCO NR + EC are enabled. + */ + getBtScoNrecEnabled() generates (Result retval, bool enabled); + + /* + * Sets whether BT SCO Noise Reduction and Echo Cancellation are enabled. + * Calling this method is equivalent to setting AUDIO_PARAMETER_KEY_BT_NREC + * on the legacy HAL. + * + * @param enabled whether BT SCO NR + EC are enabled. + * @return retval operation completion status. + */ + setBtScoNrecEnabled(bool enabled) generates (Result retval); + + /* + * Gets whether BT SCO Wideband mode is enabled. Calling this method is + * equivalent to getting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL. + * + * @return retval operation completion status. + * @return enabled whether BT Wideband is enabled. + */ + getBtScoWidebandEnabled() generates (Result retval, bool enabled); + + /* + * Sets whether BT SCO Wideband mode is enabled. Calling this method is + * equivalent to setting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL. + * + * @param enabled whether BT Wideband is enabled. + * @return retval operation completion status. + */ + setBtScoWidebandEnabled(bool enabled) generates (Result retval); + + enum TtyMode : int32_t { + OFF, + VCO, + HCO, + FULL + }; + + /* + * Gets current TTY mode selection. Calling this method is equivalent to + * getting AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL. + * + * @return retval operation completion status. + * @return mode TTY mode. + */ + getTtyMode() generates (Result retval, TtyMode mode); + + /* + * Sets current TTY mode. Calling this method is equivalent to setting + * AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL. + * + * @param mode TTY mode. + * @return retval operation completion status. + */ + setTtyMode(TtyMode mode) generates (Result retval); + + /* + * Gets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is + * enabled. Calling this method is equivalent to getting + * AUDIO_PARAMETER_KEY_HAC on the legacy HAL. + * + * @return retval operation completion status. + * @return enabled whether HAC mode is enabled. + */ + getHacEnabled() generates (Result retval, bool enabled); + + /* + * Sets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is + * enabled. Calling this method is equivalent to setting + * AUDIO_PARAMETER_KEY_HAC on the legacy HAL. + * + * @param enabled whether HAC mode is enabled. + * @return retval operation completion status. + */ + setHacEnabled(bool enabled) generates (Result retval); +};
diff --git a/audio/2.0/IStream.hal b/audio/2.0/IStream.hal new file mode 100644 index 0000000..8de7851 --- /dev/null +++ b/audio/2.0/IStream.hal
@@ -0,0 +1,294 @@ +/* + * Copyright (C) 2016 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.audio@2.0; + +import android.hardware.audio.common@2.0; +import android.hardware.audio.effect@2.0::IEffect; + +interface IStream { + typedef android.hardware.audio@2.0::Result Result; + + /* + * Return the frame size (number of bytes per sample). + * + * @return frameSize frame size in bytes. + */ + getFrameSize() generates (uint64_t frameSize); + + /* + * Return the frame count of the buffer. Calling this method is equivalent + * to getting AUDIO_PARAMETER_STREAM_FRAME_COUNT on the legacy HAL. + * + * @return count frame count. + */ + getFrameCount() generates (uint64_t count); + + /* + * Return the size of input/output buffer in bytes for this stream. + * It must be a multiple of the frame size. + * + * @return buffer buffer size in bytes. + */ + getBufferSize() generates (uint64_t bufferSize); + + /* + * Return the sampling rate in Hz. + * + * @return sampleRateHz sample rate in Hz. + */ + getSampleRate() generates (uint32_t sampleRateHz); + + /* + * Return supported sampling rates of the stream. Calling this method is + * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES on the + * legacy HAL. + * + * @return sampleRateHz supported sample rates. + */ + getSupportedSampleRates() generates (vec<uint32_t> sampleRates); + + /* + * Sets the sampling rate of the stream. Calling this method is equivalent + * to setting AUDIO_PARAMETER_STREAM_SAMPLING_RATE on the legacy HAL. + * + * @param sampleRateHz sample rate in Hz. + * @return retval operation completion status. + */ + setSampleRate(uint32_t sampleRateHz) generates (Result retval); + + /* + * Return the channel mask of the stream. + * + * @return mask channel mask. + */ + getChannelMask() generates (AudioChannelMask mask); + + /* + * Return supported channel masks of the stream. Calling this method is + * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_CHANNELS on the legacy + * HAL. + * + * @return masks supported audio masks. + */ + getSupportedChannelMasks() generates (vec<AudioChannelMask> masks); + + /* + * Sets the channel mask of the stream. Calling this method is equivalent to + * setting AUDIO_PARAMETER_STREAM_CHANNELS on the legacy HAL. + * + * @param format audio format. + * @return retval operation completion status. + */ + setChannelMask(AudioChannelMask mask) generates (Result retval); + + /* + * Return the audio format of the stream. + * + * @return format audio format. + */ + getFormat() generates (AudioFormat format); + + /* + * Return supported audio formats of the stream. Calling this method is + * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy + * HAL. + * + * @return formats supported audio formats. + */ + getSupportedFormats() generates (vec<AudioFormat> formats); + + /* + * Sets the audio format of the stream. Calling this method is equivalent to + * setting AUDIO_PARAMETER_STREAM_FORMAT on the legacy HAL. + * + * @param format audio format. + * @return retval operation completion status. + */ + setFormat(AudioFormat format) generates (Result retval); + + /* + * Convenience method for retrieving several stream parameters in + * one transaction. + * + * @return sampleRateHz sample rate in Hz. + * @return mask channel mask. + * @return format audio format. + */ + getAudioProperties() generates ( + uint32_t sampleRateHz, AudioChannelMask mask, AudioFormat format); + + /* + * Applies audio effect to the stream. + * + * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of + * the effect to apply. + * @return retval operation completion status. + */ + addEffect(uint64_t effectId) generates (Result retval); + + /* + * Stops application of the effect to the stream. + * + * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of + * the effect to remove. + * @return retval operation completion status. + */ + removeEffect(uint64_t effectId) generates (Result retval); + + /* + * Put the audio hardware input/output into standby mode. + * Driver must exit from standby mode at the next I/O operation. + * + * @return retval operation completion status. + */ + standby() generates (Result retval); + + /* + * Return the set of device(s) which this stream is connected to. + * + * @return device set of device(s) which this stream is connected to. + */ + getDevice() generates (AudioDevice device); + + /* + * Connects the stream to the device. + * + * This method must only be used for HALs that do not support + * 'IDevice.createAudioPatch' method. Calling this method is + * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING in the legacy HAL + * interface. + * + * @param address device to connect the stream to. + * @return retval operation completion status. + */ + setDevice(DeviceAddress address) generates (Result retval); + + /* + * Notifies the stream about device connection state. Calling this method is + * equivalent to setting AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy + * HAL. + * + * @param address audio device specification. + * @param connected whether the device is connected. + * @return retval operation completion status. + */ + setConnectedState(DeviceAddress address, bool connected) + generates (Result retval); + + /* + * Sets the HW synchronization source. Calling this method is equivalent to + * setting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy HAL. + * + * @param hwAvSync HW synchronization source + * @return retval operation completion status. + */ + setHwAvSync(AudioHwSync hwAvSync) generates (Result retval); + + /* + * Generic method for retrieving vendor-specific parameter values. + * The framework does not interpret the parameters, they are passed + * in an opaque manner between a vendor application and HAL. + * + * @param keys parameter keys. + * @return retval operation completion status. + * @return parameters parameter key value pairs. + */ + getParameters(vec<string> keys) + generates (Result retval, vec<ParameterValue> parameters); + + /* + * Generic method for setting vendor-specific parameter values. + * The framework does not interpret the parameters, they are passed + * in an opaque manner between a vendor application and HAL. + * + * @param parameters parameter key value pairs. + * @return retval operation completion status. + */ + setParameters(vec<ParameterValue> parameters) generates (Result retval); + + /* + * Dumps information about the stream into the provided file descriptor. + * This is used for the dumpsys facility. + * + * @param fd dump file descriptor. + */ + debugDump(handle fd); + + /* + * Called by the framework to start a stream operating in mmap mode. + * createMmapBuffer() must be called before calling start(). + * Function only implemented by streams operating in mmap mode. + * + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * INVALID_STATE if called out of sequence + */ + start() generates (Result retval); + + /** + * Called by the framework to stop a stream operating in mmap mode. + * Function only implemented by streams operating in mmap mode. + * + * @return retval OK in case the succes. + * NOT_SUPPORTED on non mmap mode streams + * INVALID_STATE if called out of sequence + */ + stop() generates (Result retval) ; + + /* + * Called by the framework to retrieve information on the mmap buffer used for audio + * samples transfer. + * Function only implemented by streams operating in mmap mode. + * + * @param minSizeFrames minimum buffer size requested. The actual buffer + * size returned in struct MmapBufferInfo can be larger. + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * NOT_INITIALIZED in case of memory allocation error + * INVALID_ARGUMENTS if the requested buffer size is too large + * INVALID_STATE if called out of sequence + * @return info a MmapBufferInfo struct containing information on the MMMAP buffer created. + */ + createMmapBuffer(int32_t minSizeFrames) + generates (Result retval, MmapBufferInfo info); + + /* + * Called by the framework to read current read/write position in the mmap buffer + * with associated time stamp. + * Function only implemented by streams operating in mmap mode. + * + * @return retval OK in case the success. + * NOT_SUPPORTED on non mmap mode streams + * INVALID_STATE if called out of sequence + * @return position a MmapPosition struct containing current HW read/write position in frames + * with associated time stamp. + */ + getMmapPosition() + generates (Result retval, MmapPosition position); + + /* + * Called by the framework to deinitialize the stream and free up + * all the currently allocated resources. It is recommended to close + * the stream on the client side as soon as it is becomes unused. + * + * @return retval OK in case the success. + * NOT_SUPPORTED if called on IStream instead of input or + * output stream interface. + * INVALID_STATE if the stream was already closed. + */ + close() generates (Result retval); +};
diff --git a/audio/2.0/IStreamIn.hal b/audio/2.0/IStreamIn.hal new file mode 100644 index 0000000..6f1f9df --- /dev/null +++ b/audio/2.0/IStreamIn.hal
@@ -0,0 +1,151 @@ +/* + * Copyright (C) 2016 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.audio@2.0; + +import android.hardware.audio.common@2.0; +import IStream; + +interface IStreamIn extends IStream { + typedef android.hardware.audio@2.0::Result Result; + + /* + * Returns the source descriptor of the input stream. Calling this method is + * equivalent to getting AUDIO_PARAMETER_STREAM_INPUT_SOURCE on the legacy + * HAL. + * + * @return retval operation completion status. + * @return source audio source. + */ + getAudioSource() generates (Result retval, AudioSource source); + + /* + * Set the input gain for the audio driver. + * + * @param gain 1.0f is unity, 0.0f is zero. + * @result retval operation completion status. + */ + setGain(float gain) generates (Result retval); + + /* + * Commands that can be executed on the driver reader thread. + */ + enum ReadCommand : int32_t { + READ, + GET_CAPTURE_POSITION + }; + + /* + * Data structure passed to the driver for executing commands + * on the driver reader thread. + */ + struct ReadParameters { + ReadCommand command; // discriminator + union Params { + uint64_t read; // READ command, amount of bytes to read, >= 0. + // No parameters for GET_CAPTURE_POSITION. + } params; + }; + + /* + * Data structure passed back to the client via status message queue + * of 'read' operation. + * + * Possible values of 'retval' field: + * - OK, read operation was successful; + * - INVALID_ARGUMENTS, stream was not configured properly; + * - INVALID_STATE, stream is in a state that doesn't allow reads. + */ + struct ReadStatus { + Result retval; + ReadCommand replyTo; // discriminator + union Reply { + uint64_t read; // READ command, amount of bytes read, >= 0. + struct CapturePosition { // same as generated by getCapturePosition. + uint64_t frames; + uint64_t time; + } capturePosition; + } reply; + }; + + /* + * Set up required transports for receiving audio buffers from the driver. + * + * The transport consists of three message queues: + * -- command queue is used to instruct the reader thread what operation + * to perform; + * -- data queue is used for passing audio data from the driver + * to the client; + * -- status queue is used for reporting operation status + * (e.g. amount of bytes actually read or error code). + * + * The driver operates on a dedicated thread. The client must ensure that + * the thread is given an appropriate priority and assigned to correct + * scheduler and cgroup. For this purpose, the method returns identifiers + * of the driver thread. + * + * @param frameSize the size of a single frame, in bytes. + * @param framesCount the number of frames in a buffer. + * @param threadPriority priority of the driver thread. + * @return retval OK if both message queues were created successfully. + * INVALID_STATE if the method was already called. + * INVALID_ARGUMENTS if there was a problem setting up + * the queues. + * @return commandMQ a message queue used for passing commands. + * @return dataMQ a message queue used for passing audio data in the format + * specified at the stream opening. + * @return statusMQ a message queue used for passing status from the driver + * using ReadStatus structures. + * @return threadInfo identifiers of the driver's dedicated thread. + */ + prepareForReading(uint32_t frameSize, uint32_t framesCount) + generates ( + Result retval, + fmq_sync<ReadParameters> commandMQ, + fmq_sync<uint8_t> dataMQ, + fmq_sync<ReadStatus> statusMQ, + ThreadInfo threadInfo); + + /* + * Return the amount of input frames lost in the audio driver since the last + * call of this function. + * + * Audio driver is expected to reset the value to 0 and restart counting + * upon returning the current value by this function call. Such loss + * typically occurs when the user space process is blocked longer than the + * capacity of audio driver buffers. + * + * @return framesLost the number of input audio frames lost. + */ + getInputFramesLost() generates (uint32_t framesLost); + + /** + * Return a recent count of the number of audio frames received and the + * clock time associated with that frame count. + * + * @return retval INVALID_STATE if the device is not ready/available, + * NOT_SUPPORTED if the command is not supported, + * OK otherwise. + * @return frames the total frame count received. This must be as early in + * the capture pipeline as possible. In general, frames + * must be non-negative and must not go "backwards". + * @return time is the clock monotonic time when frames was measured. In + * general, time must be a positive quantity and must not + * go "backwards". + */ + getCapturePosition() + generates (Result retval, uint64_t frames, uint64_t time); +};
diff --git a/audio/2.0/IStreamOut.hal b/audio/2.0/IStreamOut.hal new file mode 100644 index 0000000..9ee32c5 --- /dev/null +++ b/audio/2.0/IStreamOut.hal
@@ -0,0 +1,253 @@ +/* + * Copyright (C) 2016 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.audio@2.0; + +import android.hardware.audio.common@2.0; +import IStream; +import IStreamOutCallback; + +interface IStreamOut extends IStream { + typedef android.hardware.audio@2.0::Result Result; + + /* + * Return the audio hardware driver estimated latency in milliseconds. + * + * @return latencyMs latency in milliseconds. + */ + getLatency() generates (uint32_t latencyMs); + + /* + * This method is used in situations where audio mixing is done in the + * hardware. This method serves as a direct interface with hardware, + * allowing to directly set the volume as apposed to via the framework. + * This method might produce multiple PCM outputs or hardware accelerated + * codecs, such as MP3 or AAC. + * + * @param left left channel attenuation, 1.0f is unity, 0.0f is zero. + * @param right right channel attenuation, 1.0f is unity, 0.0f is zero. + * @return retval operation completion status. + */ + setVolume(float left, float right) generates (Result retval); + + /* + * Commands that can be executed on the driver writer thread. + */ + enum WriteCommand : int32_t { + WRITE, + GET_PRESENTATION_POSITION, + GET_LATENCY + }; + + /* + * Data structure passed back to the client via status message queue + * of 'write' operation. + * + * Possible values of 'retval' field: + * - OK, write operation was successful; + * - INVALID_ARGUMENTS, stream was not configured properly; + * - INVALID_STATE, stream is in a state that doesn't allow writes; + * - INVALID_OPERATION, retrieving presentation position isn't supported. + */ + struct WriteStatus { + Result retval; + WriteCommand replyTo; // discriminator + union Reply { + uint64_t written; // WRITE command, amount of bytes written, >= 0. + struct PresentationPosition { // same as generated by + uint64_t frames; // getPresentationPosition. + TimeSpec timeStamp; + } presentationPosition; + uint32_t latencyMs; // Same as generated by getLatency. + } reply; + }; + + /* + * Set up required transports for passing audio buffers to the driver. + * + * The transport consists of three message queues: + * -- command queue is used to instruct the writer thread what operation + * to perform; + * -- data queue is used for passing audio data from the client + * to the driver; + * -- status queue is used for reporting operation status + * (e.g. amount of bytes actually written or error code). + * + * The driver operates on a dedicated thread. The client must ensure that + * the thread is given an appropriate priority and assigned to correct + * scheduler and cgroup. For this purpose, the method returns identifiers + * of the driver thread. + * + * @param frameSize the size of a single frame, in bytes. + * @param framesCount the number of frames in a buffer. + * @return retval OK if both message queues were created successfully. + * INVALID_STATE if the method was already called. + * INVALID_ARGUMENTS if there was a problem setting up + * the queues. + * @return commandMQ a message queue used for passing commands. + * @return dataMQ a message queue used for passing audio data in the format + * specified at the stream opening. + * @return statusMQ a message queue used for passing status from the driver + * using WriteStatus structures. + * @return threadInfo identifiers of the driver's dedicated thread. + */ + prepareForWriting(uint32_t frameSize, uint32_t framesCount) + generates ( + Result retval, + fmq_sync<WriteCommand> commandMQ, + fmq_sync<uint8_t> dataMQ, + fmq_sync<WriteStatus> statusMQ, + ThreadInfo threadInfo); + + /* + * Return the number of audio frames written by the audio DSP to DAC since + * the output has exited standby. + * + * @return retval operation completion status. + * @return dspFrames number of audio frames written. + */ + getRenderPosition() generates (Result retval, uint32_t dspFrames); + + /* + * Get the local time at which the next write to the audio driver will be + * presented. The units are microseconds, where the epoch is decided by the + * local audio HAL. + * + * @return retval operation completion status. + * @return timestampUs time of the next write. + */ + getNextWriteTimestamp() generates (Result retval, int64_t timestampUs); + + /* + * Set the callback interface for notifying completion of non-blocking + * write and drain. + * + * Calling this function implies that all future 'write' and 'drain' + * must be non-blocking and use the callback to signal completion. + * + * 'clearCallback' method needs to be called in order to release the local + * callback proxy on the server side and thus dereference the callback + * implementation on the client side. + * + * @return retval operation completion status. + */ + setCallback(IStreamOutCallback callback) generates (Result retval); + + /* + * Clears the callback previously set via 'setCallback' method. + * + * Warning: failure to call this method results in callback implementation + * on the client side being held until the HAL server termination. + * + * @return retval operation completion status: OK or NOT_SUPPORTED. + */ + clearCallback() generates (Result retval); + + /* + * Returns whether HAL supports pausing and resuming of streams. + * + * @return supportsPause true if pausing is supported. + * @return supportsResume true if resume is supported. + */ + supportsPauseAndResume() + generates (bool supportsPause, bool supportsResume); + + /** + * Notifies to the audio driver to stop playback however the queued buffers + * are retained by the hardware. Useful for implementing pause/resume. Empty + * implementation if not supported however must be implemented for hardware + * with non-trivial latency. In the pause state, some audio hardware may + * still be using power. Client code may consider calling 'suspend' after a + * timeout to prevent that excess power usage. + * + * Implementation of this function is mandatory for offloaded playback. + * + * @return retval operation completion status. + */ + pause() generates (Result retval); + + /* + * Notifies to the audio driver to resume playback following a pause. + * Returns error INVALID_STATE if called without matching pause. + * + * Implementation of this function is mandatory for offloaded playback. + * + * @return retval operation completion status. + */ + resume() generates (Result retval); + + /* + * Returns whether HAL supports draining of streams. + * + * @return supports true if draining is supported. + */ + supportsDrain() generates (bool supports); + + /** + * Requests notification when data buffered by the driver/hardware has been + * played. If 'setCallback' has previously been called to enable + * non-blocking mode, then 'drain' must not block, instead it must return + * quickly and completion of the drain is notified through the callback. If + * 'setCallback' has not been called, then 'drain' must block until + * completion. + * + * If 'type' is 'ALL', the drain completes when all previously written data + * has been played. + * + * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data + * for the current track has played to allow time for the framework to + * perform a gapless track switch. + * + * Drain must return immediately on 'stop' and 'flush' calls. + * + * Implementation of this function is mandatory for offloaded playback. + * + * @param type type of drain. + * @return retval operation completion status. + */ + drain(AudioDrain type) generates (Result retval); + + /* + * Notifies to the audio driver to flush the queued data. Stream must + * already be paused before calling 'flush'. + * + * Implementation of this function is mandatory for offloaded playback. + * + * @return retval operation completion status. + */ + flush() generates (Result retval); + + /* + * Return a recent count of the number of audio frames presented to an + * external observer. This excludes frames which have been written but are + * still in the pipeline. The count is not reset to zero when output enters + * standby. Also returns the value of CLOCK_MONOTONIC as of this + * presentation count. The returned count is expected to be 'recent', but + * does not need to be the most recent possible value. However, the + * associated time must correspond to whatever count is returned. + * + * Example: assume that N+M frames have been presented, where M is a 'small' + * number. Then it is permissible to return N instead of N+M, and the + * timestamp must correspond to N rather than N+M. The terms 'recent' and + * 'small' are not defined. They reflect the quality of the implementation. + * + * @return retval operation completion status. + * @return frames count of presented audio frames. + * @return timeStamp associated clock time. + */ + getPresentationPosition() + generates (Result retval, uint64_t frames, TimeSpec timeStamp); +};
diff --git a/audio/2.0/IStreamOutCallback.hal b/audio/2.0/IStreamOutCallback.hal new file mode 100644 index 0000000..cdb38de --- /dev/null +++ b/audio/2.0/IStreamOutCallback.hal
@@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 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.audio@2.0; + +/* + * Asynchronous write callback interface. + */ +interface IStreamOutCallback { + /* + * Non blocking write completed. + */ + oneway onWriteReady(); + + /* + * Drain completed. + */ + oneway onDrainReady(); + + /* + * Stream hit an error. + */ + oneway onError(); +};
diff --git a/audio/2.0/default/Android.mk b/audio/2.0/default/Android.mk new file mode 100644 index 0000000..93f7ad0 --- /dev/null +++ b/audio/2.0/default/Android.mk
@@ -0,0 +1,85 @@ +# +# Copyright (C) 2016 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. + + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.audio@2.0-impl +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_SRC_FILES := \ + Conversions.cpp \ + Device.cpp \ + DevicesFactory.cpp \ + ParametersUtil.cpp \ + PrimaryDevice.cpp \ + Stream.cpp \ + StreamIn.cpp \ + StreamOut.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils \ + libfmq \ + libhardware \ + libhidlbase \ + libhidltransport \ + liblog \ + libutils \ + android.hardware.audio@2.0 \ + android.hardware.audio.common@2.0 \ + android.hardware.audio.common@2.0-util \ + +LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper + +include $(BUILD_SHARED_LIBRARY) + +# +# Service +# + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.audio@2.0-service +LOCAL_INIT_RC := android.hardware.audio@2.0-service.rc +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_SRC_FILES := \ + service.cpp + +LOCAL_SHARED_LIBRARIES := \ + libhidlbase \ + libhidltransport \ + liblog \ + libutils \ + libhardware \ + android.hardware.audio@2.0 \ + android.hardware.audio.common@2.0 \ + android.hardware.audio.effect@2.0 \ + android.hardware.soundtrigger@2.0 \ + android.hardware.broadcastradio@1.0 \ + android.hardware.broadcastradio@1.1 + +ifeq ($(strip $(AUDIOSERVER_MULTILIB)),) +LOCAL_MULTILIB := 32 +else +LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) +endif + +ifeq ($(TARGET_USES_BCRADIO_FUTURE_FEATURES),true) +LOCAL_CFLAGS += -DTARGET_USES_BCRADIO_FUTURE_FEATURES +endif + +include $(BUILD_EXECUTABLE)
diff --git a/audio/2.0/default/Conversions.cpp b/audio/2.0/default/Conversions.cpp new file mode 100644 index 0000000..e669185 --- /dev/null +++ b/audio/2.0/default/Conversions.cpp
@@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <stdio.h> + +#include "Conversions.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +std::string deviceAddressToHal(const DeviceAddress& address) { + // HAL assumes that the address is NUL-terminated. + char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN]; + memset(halAddress, 0, sizeof(halAddress)); + uint32_t halDevice = static_cast<uint32_t>(address.device); + const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0; + if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN; + if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) + || (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) { + snprintf(halAddress, sizeof(halAddress), + "%02X:%02X:%02X:%02X:%02X:%02X", + address.address.mac[0], address.address.mac[1], address.address.mac[2], + address.address.mac[3], address.address.mac[4], address.address.mac[5]); + } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0) + || (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) { + snprintf(halAddress, sizeof(halAddress), + "%d.%d.%d.%d", + address.address.ipv4[0], address.address.ipv4[1], + address.address.ipv4[2], address.address.ipv4[3]); + } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0) + || (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) { + snprintf(halAddress, sizeof(halAddress), + "card=%d;device=%d", + address.address.alsa.card, address.address.alsa.device); + } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0) + || (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) { + snprintf(halAddress, sizeof(halAddress), + "%s", address.busAddress.c_str()); + } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 + || (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) { + snprintf(halAddress, sizeof(halAddress), + "%s", address.rSubmixAddress.c_str()); + } + return halAddress; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/2.0/default/Conversions.h b/audio/2.0/default/Conversions.h new file mode 100644 index 0000000..ebda5c5 --- /dev/null +++ b/audio/2.0/default/Conversions.h
@@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_audio_V2_0_Conversions_H_ +#define android_hardware_audio_V2_0_Conversions_H_ + +#include <string> + +#include <android/hardware/audio/2.0/types.h> +#include <system/audio.h> + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::V2_0::DeviceAddress; + +std::string deviceAddressToHal(const DeviceAddress& address); + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // android_hardware_audio_V2_0_Conversions_H_
diff --git a/audio/2.0/default/Device.cpp b/audio/2.0/default/Device.cpp new file mode 100644 index 0000000..8a51cd7 --- /dev/null +++ b/audio/2.0/default/Device.cpp
@@ -0,0 +1,297 @@ + /* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "DeviceHAL" +//#define LOG_NDEBUG 0 + +#include <algorithm> +#include <memory.h> +#include <string.h> + +#include <android/log.h> + +#include "Conversions.h" +#include "Device.h" +#include "HidlUtils.h" +#include "StreamIn.h" +#include "StreamOut.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +Device::Device(audio_hw_device_t* device) + : mDevice(device) { +} + +Device::~Device() { + int status = audio_hw_device_close(mDevice); + ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice, strerror(-status)); + mDevice = nullptr; +} + +Result Device::analyzeStatus(const char* funcName, int status) { + if (status != 0) { + ALOGW("Device %p %s: %s", mDevice, funcName, strerror(-status)); + } + switch (status) { + case 0: return Result::OK; + case -EINVAL: return Result::INVALID_ARGUMENTS; + case -ENODATA: return Result::INVALID_STATE; + case -ENODEV: return Result::NOT_INITIALIZED; + case -ENOSYS: return Result::NOT_SUPPORTED; + default: return Result::INVALID_STATE; + } +} + +char* Device::halGetParameters(const char* keys) { + return mDevice->get_parameters(mDevice, keys); +} + +int Device::halSetParameters(const char* keysAndValues) { + return mDevice->set_parameters(mDevice, keysAndValues); +} + +// Methods from ::android::hardware::audio::V2_0::IDevice follow. +Return<Result> Device::initCheck() { + return analyzeStatus("init_check", mDevice->init_check(mDevice)); +} + +Return<Result> Device::setMasterVolume(float volume) { + Result retval(Result::NOT_SUPPORTED); + if (mDevice->set_master_volume != NULL) { + retval = analyzeStatus("set_master_volume", mDevice->set_master_volume(mDevice, volume)); + } + return retval; +} + +Return<void> Device::getMasterVolume(getMasterVolume_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + float volume = 0; + if (mDevice->get_master_volume != NULL) { + retval = analyzeStatus("get_master_volume", mDevice->get_master_volume(mDevice, &volume)); + } + _hidl_cb(retval, volume); + return Void(); +} + +Return<Result> Device::setMicMute(bool mute) { + return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute)); +} + +Return<void> Device::getMicMute(getMicMute_cb _hidl_cb) { + bool mute = false; + Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute)); + _hidl_cb(retval, mute); + return Void(); +} + +Return<Result> Device::setMasterMute(bool mute) { + Result retval(Result::NOT_SUPPORTED); + if (mDevice->set_master_mute != NULL) { + retval = analyzeStatus("set_master_mute", mDevice->set_master_mute(mDevice, mute)); + } + return retval; +} + +Return<void> Device::getMasterMute(getMasterMute_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + bool mute = false; + if (mDevice->get_master_mute != NULL) { + retval = analyzeStatus("get_master_mute", mDevice->get_master_mute(mDevice, &mute)); + } + _hidl_cb(retval, mute); + return Void(); +} + +Return<void> Device::getInputBufferSize( + const AudioConfig& config, getInputBufferSize_cb _hidl_cb) { + audio_config_t halConfig; + HidlUtils::audioConfigToHal(config, &halConfig); + size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig); + Result retval(Result::INVALID_ARGUMENTS); + uint64_t bufferSize = 0; + if (halBufferSize != 0) { + retval = Result::OK; + bufferSize = halBufferSize; + } + _hidl_cb(retval, bufferSize); + return Void(); +} + +Return<void> Device::openOutputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlag flags, + openOutputStream_cb _hidl_cb) { + audio_config_t halConfig; + HidlUtils::audioConfigToHal(config, &halConfig); + audio_stream_out_t *halStream; + ALOGV("open_output_stream handle: %d devices: %x flags: %#x " + "srate: %d format %#x channels %x address %s", + ioHandle, + static_cast<audio_devices_t>(device.device), static_cast<audio_output_flags_t>(flags), + halConfig.sample_rate, halConfig.format, halConfig.channel_mask, + deviceAddressToHal(device).c_str()); + int status = mDevice->open_output_stream( + mDevice, + ioHandle, + static_cast<audio_devices_t>(device.device), + static_cast<audio_output_flags_t>(flags), + &halConfig, + &halStream, + deviceAddressToHal(device).c_str()); + ALOGV("open_output_stream status %d stream %p", status, halStream); + sp<IStreamOut> streamOut; + if (status == OK) { + streamOut = new StreamOut(mDevice, halStream); + } + AudioConfig suggestedConfig; + HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig); + _hidl_cb(analyzeStatus("open_output_stream", status), streamOut, suggestedConfig); + return Void(); +} + +Return<void> Device::openInputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioInputFlag flags, + AudioSource source, + openInputStream_cb _hidl_cb) { + audio_config_t halConfig; + HidlUtils::audioConfigToHal(config, &halConfig); + audio_stream_in_t *halStream; + ALOGV("open_input_stream handle: %d devices: %x flags: %#x " + "srate: %d format %#x channels %x address %s source %d", + ioHandle, + static_cast<audio_devices_t>(device.device), static_cast<audio_input_flags_t>(flags), + halConfig.sample_rate, halConfig.format, halConfig.channel_mask, + deviceAddressToHal(device).c_str(), static_cast<audio_source_t>(source)); + int status = mDevice->open_input_stream( + mDevice, + ioHandle, + static_cast<audio_devices_t>(device.device), + &halConfig, + &halStream, + static_cast<audio_input_flags_t>(flags), + deviceAddressToHal(device).c_str(), + static_cast<audio_source_t>(source)); + ALOGV("open_input_stream status %d stream %p", status, halStream); + sp<IStreamIn> streamIn; + if (status == OK) { + streamIn = new StreamIn(mDevice, halStream); + } + AudioConfig suggestedConfig; + HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig); + _hidl_cb(analyzeStatus("open_input_stream", status), streamIn, suggestedConfig); + return Void(); +} + +Return<bool> Device::supportsAudioPatches() { + return version() >= AUDIO_DEVICE_API_VERSION_3_0; +} + +Return<void> Device::createAudioPatch( + const hidl_vec<AudioPortConfig>& sources, + const hidl_vec<AudioPortConfig>& sinks, + createAudioPatch_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + AudioPatchHandle patch = 0; + if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { + std::unique_ptr<audio_port_config[]> halSources(HidlUtils::audioPortConfigsToHal(sources)); + std::unique_ptr<audio_port_config[]> halSinks(HidlUtils::audioPortConfigsToHal(sinks)); + audio_patch_handle_t halPatch; + retval = analyzeStatus( + "create_audio_patch", + mDevice->create_audio_patch( + mDevice, + sources.size(), &halSources[0], + sinks.size(), &halSinks[0], + &halPatch)); + if (retval == Result::OK) { + patch = static_cast<AudioPatchHandle>(halPatch); + } + } + _hidl_cb(retval, patch); + return Void(); +} + +Return<Result> Device::releaseAudioPatch(int32_t patch) { + if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { + return analyzeStatus( + "release_audio_patch", + mDevice->release_audio_patch(mDevice, static_cast<audio_patch_handle_t>(patch))); + } + return Result::NOT_SUPPORTED; +} + +Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) { + audio_port halPort; + HidlUtils::audioPortToHal(port, &halPort); + Result retval = analyzeStatus("get_audio_port", mDevice->get_audio_port(mDevice, &halPort)); + AudioPort resultPort = port; + if (retval == Result::OK) { + HidlUtils::audioPortFromHal(halPort, &resultPort); + } + _hidl_cb(retval, resultPort); + return Void(); +} + +Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) { + if (version() >= AUDIO_DEVICE_API_VERSION_3_0) { + struct audio_port_config halPortConfig; + HidlUtils::audioPortConfigToHal(config, &halPortConfig); + return analyzeStatus( + "set_audio_port_config", mDevice->set_audio_port_config(mDevice, &halPortConfig)); + } + return Result::NOT_SUPPORTED; +} + +Return<AudioHwSync> Device::getHwAvSync() { + int halHwAvSync; + Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync); + return retval == Result::OK ? halHwAvSync : AUDIO_HW_SYNC_INVALID; +} + +Return<Result> Device::setScreenState(bool turnedOn) { + return setParam(AudioParameter::keyScreenState, turnedOn); +} + +Return<void> Device::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { + getParametersImpl(keys, _hidl_cb); + return Void(); +} + +Return<Result> Device::setParameters(const hidl_vec<ParameterValue>& parameters) { + return setParametersImpl(parameters); +} + +Return<void> Device::debugDump(const hidl_handle& fd) { + if (fd->numFds == 1) { + analyzeStatus("dump", mDevice->dump(mDevice, fd->data[0])); + } + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/2.0/default/Device.h b/audio/2.0/default/Device.h new file mode 100644 index 0000000..46177fc --- /dev/null +++ b/audio/2.0/default/Device.h
@@ -0,0 +1,121 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H +#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H + +#include <memory> + +#include <media/AudioParameter.h> +#include <hardware/audio.h> + +#include <android/hardware/audio/2.0/IDevice.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "ParametersUtil.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioConfig; +using ::android::hardware::audio::common::V2_0::AudioHwSync; +using ::android::hardware::audio::common::V2_0::AudioInputFlag; +using ::android::hardware::audio::common::V2_0::AudioOutputFlag; +using ::android::hardware::audio::common::V2_0::AudioPatchHandle; +using ::android::hardware::audio::common::V2_0::AudioPort; +using ::android::hardware::audio::common::V2_0::AudioPortConfig; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IDevice; +using ::android::hardware::audio::V2_0::IStreamIn; +using ::android::hardware::audio::V2_0::IStreamOut; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Device : public IDevice, public ParametersUtil { + explicit Device(audio_hw_device_t* device); + + // Methods from ::android::hardware::audio::V2_0::IDevice follow. + Return<Result> initCheck() override; + Return<Result> setMasterVolume(float volume) override; + Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb) override; + Return<Result> setMicMute(bool mute) override; + Return<void> getMicMute(getMicMute_cb _hidl_cb) override; + Return<Result> setMasterMute(bool mute) override; + Return<void> getMasterMute(getMasterMute_cb _hidl_cb) override; + Return<void> getInputBufferSize( + const AudioConfig& config, getInputBufferSize_cb _hidl_cb) override; + Return<void> openOutputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlag flags, + openOutputStream_cb _hidl_cb) override; + Return<void> openInputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioInputFlag flags, + AudioSource source, + openInputStream_cb _hidl_cb) override; + Return<bool> supportsAudioPatches() override; + Return<void> createAudioPatch( + const hidl_vec<AudioPortConfig>& sources, + const hidl_vec<AudioPortConfig>& sinks, + createAudioPatch_cb _hidl_cb) override; + Return<Result> releaseAudioPatch(int32_t patch) override; + Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override; + Return<Result> setAudioPortConfig(const AudioPortConfig& config) override; + Return<AudioHwSync> getHwAvSync() override; + Return<Result> setScreenState(bool turnedOn) override; + Return<void> getParameters( + const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; + Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; + Return<void> debugDump(const hidl_handle& fd) override; + + // Utility methods for extending interfaces. + Result analyzeStatus(const char* funcName, int status); + audio_hw_device_t* device() const { return mDevice; } + + private: + audio_hw_device_t *mDevice; + + virtual ~Device(); + + // Methods from ParametersUtil. + char* halGetParameters(const char* keys) override; + int halSetParameters(const char* keysAndValues) override; + + uint32_t version() const { return mDevice->common.version; } +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H
diff --git a/audio/2.0/default/DevicesFactory.cpp b/audio/2.0/default/DevicesFactory.cpp new file mode 100644 index 0000000..8825107 --- /dev/null +++ b/audio/2.0/default/DevicesFactory.cpp
@@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "DevicesFactoryHAL" + +#include <string.h> + +#include <android/log.h> + +#include "Device.h" +#include "DevicesFactory.h" +#include "PrimaryDevice.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +// static +const char* DevicesFactory::deviceToString(IDevicesFactory::Device device) { + switch (device) { + case IDevicesFactory::Device::PRIMARY: return AUDIO_HARDWARE_MODULE_ID_PRIMARY; + case IDevicesFactory::Device::A2DP: return AUDIO_HARDWARE_MODULE_ID_A2DP; + case IDevicesFactory::Device::USB: return AUDIO_HARDWARE_MODULE_ID_USB; + case IDevicesFactory::Device::R_SUBMIX: return AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX; + case IDevicesFactory::Device::STUB: return AUDIO_HARDWARE_MODULE_ID_STUB; + } +} + +// static +int DevicesFactory::loadAudioInterface(const char *if_name, audio_hw_device_t **dev) +{ + const hw_module_t *mod; + int rc; + + rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod); + if (rc) { + ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__, + AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc)); + goto out; + } + rc = audio_hw_device_open(mod, dev); + if (rc) { + ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__, + AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc)); + goto out; + } + if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) { + ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version); + rc = -EINVAL; + audio_hw_device_close(*dev); + goto out; + } + return OK; + +out: + *dev = NULL; + return rc; +} + +// Methods from ::android::hardware::audio::V2_0::IDevicesFactory follow. +Return<void> DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) { + audio_hw_device_t *halDevice; + int halStatus = loadAudioInterface(deviceToString(device), &halDevice); + Result retval(Result::OK); + sp<IDevice> result; + if (halStatus == OK) { + if (device == IDevicesFactory::Device::PRIMARY) { + result = new PrimaryDevice(halDevice); + } else { + result = new ::android::hardware::audio::V2_0::implementation::Device(halDevice); + } + } else if (halStatus == -EINVAL) { + retval = Result::NOT_INITIALIZED; + } else { + retval = Result::INVALID_ARGUMENTS; + } + _hidl_cb(retval, result); + return Void(); +} + +IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* /* name */) { + return new DevicesFactory(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/2.0/default/DevicesFactory.h b/audio/2.0/default/DevicesFactory.h new file mode 100644 index 0000000..b046f9f --- /dev/null +++ b/audio/2.0/default/DevicesFactory.h
@@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H +#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H + +#include <hardware/audio.h> + +#include <android/hardware/audio/2.0/IDevicesFactory.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::V2_0::IDevice; +using ::android::hardware::audio::V2_0::IDevicesFactory; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct DevicesFactory : public IDevicesFactory { + // Methods from ::android::hardware::audio::V2_0::IDevicesFactory follow. + Return<void> openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) override; + + private: + static const char* deviceToString(IDevicesFactory::Device device); + static int loadAudioInterface(const char *if_name, audio_hw_device_t **dev); + +}; + +extern "C" IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name); + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H
diff --git a/audio/2.0/default/ParametersUtil.cpp b/audio/2.0/default/ParametersUtil.cpp new file mode 100644 index 0000000..75a60b9 --- /dev/null +++ b/audio/2.0/default/ParametersUtil.cpp
@@ -0,0 +1,134 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "ParametersUtil.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +Result ParametersUtil::getParam(const char* name, bool* value) { + String8 halValue; + Result retval = getParam(name, &halValue); + *value = false; + if (retval == Result::OK) { + *value = !(halValue == AudioParameter::valueOff); + } + return retval; +} + +Result ParametersUtil::getParam(const char* name, int* value) { + const String8 halName(name); + AudioParameter keys; + keys.addKey(halName); + std::unique_ptr<AudioParameter> params = getParams(keys); + status_t halStatus = params->getInt(halName, *value); + return halStatus == OK ? Result::OK : Result::INVALID_ARGUMENTS; +} + +Result ParametersUtil::getParam(const char* name, String8* value) { + const String8 halName(name); + AudioParameter keys; + keys.addKey(halName); + std::unique_ptr<AudioParameter> params = getParams(keys); + status_t halStatus = params->get(halName, *value); + return halStatus == OK ? Result::OK : Result::INVALID_ARGUMENTS; +} + +void ParametersUtil::getParametersImpl( + const hidl_vec<hidl_string>& keys, + std::function<void(Result retval, const hidl_vec<ParameterValue>& parameters)> cb) { + AudioParameter halKeys; + for (size_t i = 0; i < keys.size(); ++i) { + halKeys.addKey(String8(keys[i].c_str())); + } + std::unique_ptr<AudioParameter> halValues = getParams(halKeys); + Result retval(Result::INVALID_ARGUMENTS); + hidl_vec<ParameterValue> result; + if (halValues->size() > 0) { + result.resize(halValues->size()); + String8 halKey, halValue; + for (size_t i = 0; i < halValues->size(); ++i) { + status_t status = halValues->getAt(i, halKey, halValue); + if (status != OK) { + result.resize(0); + break; + } + result[i].key = halKey.string(); + result[i].value = halValue.string(); + } + if (result.size() != 0) { + retval = Result::OK; + } + } + cb(retval, result); +} + +std::unique_ptr<AudioParameter> ParametersUtil::getParams(const AudioParameter& keys) { + String8 paramsAndValues; + char *halValues = halGetParameters(keys.keysToString().string()); + if (halValues != NULL) { + paramsAndValues.setTo(halValues); + free(halValues); + } else { + paramsAndValues.clear(); + } + return std::unique_ptr<AudioParameter>(new AudioParameter(paramsAndValues)); +} + +Result ParametersUtil::setParam(const char* name, bool value) { + AudioParameter param; + param.add(String8(name), String8(value ? AudioParameter::valueOn : AudioParameter::valueOff)); + return setParams(param); +} + +Result ParametersUtil::setParam(const char* name, int value) { + AudioParameter param; + param.addInt(String8(name), value); + return setParams(param); +} + +Result ParametersUtil::setParam(const char* name, const char* value) { + AudioParameter param; + param.add(String8(name), String8(value)); + return setParams(param); +} + +Result ParametersUtil::setParametersImpl(const hidl_vec<ParameterValue>& parameters) { + AudioParameter params; + for (size_t i = 0; i < parameters.size(); ++i) { + params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str())); + } + return setParams(params); +} + +Result ParametersUtil::setParams(const AudioParameter& param) { + int halStatus = halSetParameters(param.toString().string()); + if (halStatus == OK) + return Result::OK; + else if (halStatus == -ENOSYS) + return Result::INVALID_STATE; + else + return Result::INVALID_ARGUMENTS; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/2.0/default/ParametersUtil.h b/audio/2.0/default/ParametersUtil.h new file mode 100644 index 0000000..49036dc --- /dev/null +++ b/audio/2.0/default/ParametersUtil.h
@@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_audio_V2_0_ParametersUtil_H_ +#define android_hardware_audio_V2_0_ParametersUtil_H_ + +#include <functional> +#include <memory> + +#include <android/hardware/audio/2.0/types.h> +#include <hidl/HidlSupport.h> +#include <media/AudioParameter.h> + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; + +class ParametersUtil { + public: + Result getParam(const char* name, bool* value); + Result getParam(const char* name, int* value); + Result getParam(const char* name, String8* value); + void getParametersImpl( + const hidl_vec<hidl_string>& keys, + std::function<void(Result retval, const hidl_vec<ParameterValue>& parameters)> cb); + std::unique_ptr<AudioParameter> getParams(const AudioParameter& keys); + Result setParam(const char* name, bool value); + Result setParam(const char* name, int value); + Result setParam(const char* name, const char* value); + Result setParametersImpl(const hidl_vec<ParameterValue>& parameters); + Result setParams(const AudioParameter& param); + + protected: + virtual ~ParametersUtil() {} + + virtual char* halGetParameters(const char* keys) = 0; + virtual int halSetParameters(const char* keysAndValues) = 0; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // android_hardware_audio_V2_0_ParametersUtil_H_
diff --git a/audio/2.0/default/PrimaryDevice.cpp b/audio/2.0/default/PrimaryDevice.cpp new file mode 100644 index 0000000..905203b --- /dev/null +++ b/audio/2.0/default/PrimaryDevice.cpp
@@ -0,0 +1,193 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "PrimaryDeviceHAL" + +#include "PrimaryDevice.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +PrimaryDevice::PrimaryDevice(audio_hw_device_t* device) + : mDevice(new Device(device)) { +} + +PrimaryDevice::~PrimaryDevice() {} + +// Methods from ::android::hardware::audio::V2_0::IDevice follow. +Return<Result> PrimaryDevice::initCheck() { + return mDevice->initCheck(); +} + +Return<Result> PrimaryDevice::setMasterVolume(float volume) { + return mDevice->setMasterVolume(volume); +} + +Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) { + return mDevice->getMasterVolume(_hidl_cb); +} + +Return<Result> PrimaryDevice::setMicMute(bool mute) { + return mDevice->setMicMute(mute); +} + +Return<void> PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) { + return mDevice->getMicMute(_hidl_cb); +} + +Return<Result> PrimaryDevice::setMasterMute(bool mute) { + return mDevice->setMasterMute(mute); +} + +Return<void> PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) { + return mDevice->getMasterMute(_hidl_cb); +} + +Return<void> PrimaryDevice::getInputBufferSize( + const AudioConfig& config, getInputBufferSize_cb _hidl_cb) { + return mDevice->getInputBufferSize(config, _hidl_cb); +} + +Return<void> PrimaryDevice::openOutputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlag flags, + openOutputStream_cb _hidl_cb) { + return mDevice->openOutputStream(ioHandle, device, config, flags, _hidl_cb); +} + +Return<void> PrimaryDevice::openInputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioInputFlag flags, + AudioSource source, + openInputStream_cb _hidl_cb) { + return mDevice->openInputStream(ioHandle, device, config, flags, source, _hidl_cb); +} + +Return<bool> PrimaryDevice::supportsAudioPatches() { + return mDevice->supportsAudioPatches(); +} + +Return<void> PrimaryDevice::createAudioPatch( + const hidl_vec<AudioPortConfig>& sources, + const hidl_vec<AudioPortConfig>& sinks, + createAudioPatch_cb _hidl_cb) { + return mDevice->createAudioPatch(sources, sinks, _hidl_cb); +} + +Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) { + return mDevice->releaseAudioPatch(patch); +} + +Return<void> PrimaryDevice::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) { + return mDevice->getAudioPort(port, _hidl_cb); +} + +Return<Result> PrimaryDevice::setAudioPortConfig(const AudioPortConfig& config) { + return mDevice->setAudioPortConfig(config); +} + +Return<AudioHwSync> PrimaryDevice::getHwAvSync() { + return mDevice->getHwAvSync(); +} + +Return<Result> PrimaryDevice::setScreenState(bool turnedOn) { + return mDevice->setScreenState(turnedOn); +} + +Return<void> PrimaryDevice::getParameters( + const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { + return mDevice->getParameters(keys, _hidl_cb); +} + +Return<Result> PrimaryDevice::setParameters(const hidl_vec<ParameterValue>& parameters) { + return mDevice->setParameters(parameters); +} + +Return<void> PrimaryDevice::debugDump(const hidl_handle& fd) { + return mDevice->debugDump(fd); +} + + +// Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow. +Return<Result> PrimaryDevice::setVoiceVolume(float volume) { + return mDevice->analyzeStatus( + "set_voice_volume", + mDevice->device()->set_voice_volume(mDevice->device(), volume)); +} + +Return<Result> PrimaryDevice::setMode(AudioMode mode) { + return mDevice->analyzeStatus( + "set_mode", + mDevice->device()->set_mode(mDevice->device(), static_cast<audio_mode_t>(mode))); +} + +Return<void> PrimaryDevice::getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) { + bool enabled; + Result retval = mDevice->getParam(AudioParameter::keyBtNrec, &enabled); + _hidl_cb(retval, enabled); + return Void(); +} + +Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) { + return mDevice->setParam(AudioParameter::keyBtNrec, enabled); +} + +Return<void> PrimaryDevice::getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) { + bool enabled; + Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, &enabled); + _hidl_cb(retval, enabled); + return Void(); +} + +Return<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) { + return mDevice->setParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, enabled); +} + +Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) { + int halMode; + Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_TTY_MODE, &halMode); + TtyMode mode = retval == Result::OK ? TtyMode(halMode) : TtyMode::OFF; + _hidl_cb(retval, mode); + return Void(); +} + +Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) { + return mDevice->setParam(AUDIO_PARAMETER_KEY_TTY_MODE, static_cast<int>(mode)); +} + +Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) { + bool enabled; + Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_HAC, &enabled); + _hidl_cb(retval, enabled); + return Void(); +} + +Return<Result> PrimaryDevice::setHacEnabled(bool enabled) { + return mDevice->setParam(AUDIO_PARAMETER_KEY_HAC, enabled); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/2.0/default/PrimaryDevice.h b/audio/2.0/default/PrimaryDevice.h new file mode 100644 index 0000000..d95511b --- /dev/null +++ b/audio/2.0/default/PrimaryDevice.h
@@ -0,0 +1,118 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H +#define ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H + +#include <android/hardware/audio/2.0/IPrimaryDevice.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Device.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioConfig; +using ::android::hardware::audio::common::V2_0::AudioInputFlag; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioOutputFlag; +using ::android::hardware::audio::common::V2_0::AudioPort; +using ::android::hardware::audio::common::V2_0::AudioPortConfig; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IDevice; +using ::android::hardware::audio::V2_0::IPrimaryDevice; +using ::android::hardware::audio::V2_0::IStreamIn; +using ::android::hardware::audio::V2_0::IStreamOut; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct PrimaryDevice : public IPrimaryDevice { + explicit PrimaryDevice(audio_hw_device_t* device); + + // Methods from ::android::hardware::audio::V2_0::IDevice follow. + Return<Result> initCheck() override; + Return<Result> setMasterVolume(float volume) override; + Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb) override; + Return<Result> setMicMute(bool mute) override; + Return<void> getMicMute(getMicMute_cb _hidl_cb) override; + Return<Result> setMasterMute(bool mute) override; + Return<void> getMasterMute(getMasterMute_cb _hidl_cb) override; + Return<void> getInputBufferSize( + const AudioConfig& config, getInputBufferSize_cb _hidl_cb) override; + Return<void> openOutputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioOutputFlag flags, + openOutputStream_cb _hidl_cb) override; + Return<void> openInputStream( + int32_t ioHandle, + const DeviceAddress& device, + const AudioConfig& config, + AudioInputFlag flags, + AudioSource source, + openInputStream_cb _hidl_cb) override; + Return<bool> supportsAudioPatches() override; + Return<void> createAudioPatch( + const hidl_vec<AudioPortConfig>& sources, + const hidl_vec<AudioPortConfig>& sinks, + createAudioPatch_cb _hidl_cb) override; + Return<Result> releaseAudioPatch(int32_t patch) override; + Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override; + Return<Result> setAudioPortConfig(const AudioPortConfig& config) override; + Return<AudioHwSync> getHwAvSync() override; + Return<Result> setScreenState(bool turnedOn) override; + Return<void> getParameters( + const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; + Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; + Return<void> debugDump(const hidl_handle& fd) override; + + // Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow. + Return<Result> setVoiceVolume(float volume) override; + Return<Result> setMode(AudioMode mode) override; + Return<void> getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) override; + Return<Result> setBtScoNrecEnabled(bool enabled) override; + Return<void> getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) override; + Return<Result> setBtScoWidebandEnabled(bool enabled) override; + Return<void> getTtyMode(getTtyMode_cb _hidl_cb) override; + Return<Result> setTtyMode(IPrimaryDevice::TtyMode mode) override; + Return<void> getHacEnabled(getHacEnabled_cb _hidl_cb) override; + Return<Result> setHacEnabled(bool enabled) override; + + private: + sp<Device> mDevice; + + virtual ~PrimaryDevice(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H
diff --git a/audio/2.0/default/Stream.cpp b/audio/2.0/default/Stream.cpp new file mode 100644 index 0000000..29946fe --- /dev/null +++ b/audio/2.0/default/Stream.cpp
@@ -0,0 +1,266 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <inttypes.h> + +#define LOG_TAG "StreamHAL" + +#include <hardware/audio.h> +#include <hardware/audio_effect.h> +#include <media/TypeConverter.h> +#include <android/log.h> +#include <utils/SortedVector.h> +#include <utils/Vector.h> + +#include "Conversions.h" +#include "EffectMap.h" +#include "Stream.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +Stream::Stream(audio_stream_t* stream) + : mStream(stream) { +} + +Stream::~Stream() { + mStream = nullptr; +} + +// static +Result Stream::analyzeStatus(const char* funcName, int status, int ignoreError, int ignoreError2) { + if (status != 0 && status != -ignoreError && status != -ignoreError2) { + ALOGW("Error from HAL stream in function %s: %s", funcName, strerror(-status)); + } + switch (status) { + case 0: return Result::OK; + case -EINVAL: return Result::INVALID_ARGUMENTS; + case -ENODATA: return Result::INVALID_STATE; + case -ENODEV: return Result::NOT_INITIALIZED; + case -ENOSYS: return Result::NOT_SUPPORTED; + default: return Result::INVALID_STATE; + } +} + +char* Stream::halGetParameters(const char* keys) { + return mStream->get_parameters(mStream, keys); +} + +int Stream::halSetParameters(const char* keysAndValues) { + return mStream->set_parameters(mStream, keysAndValues); +} + +// Methods from ::android::hardware::audio::V2_0::IStream follow. +Return<uint64_t> Stream::getFrameSize() { + // Needs to be implemented by interface subclasses. But can't be declared as pure virtual, + // since interface subclasses implementation do not inherit from this class. + LOG_ALWAYS_FATAL("Stream::getFrameSize is pure abstract"); + return uint64_t {}; +} + +Return<uint64_t> Stream::getFrameCount() { + int halFrameCount; + Result retval = getParam(AudioParameter::keyFrameCount, &halFrameCount); + return retval == Result::OK ? halFrameCount : 0; +} + +Return<uint64_t> Stream::getBufferSize() { + return mStream->get_buffer_size(mStream); +} + +Return<uint32_t> Stream::getSampleRate() { + return mStream->get_sample_rate(mStream); +} + +Return<void> Stream::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { + String8 halListValue; + Result result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue); + hidl_vec<uint32_t> sampleRates; + SortedVector<uint32_t> halSampleRates; + if (result == Result::OK) { + halSampleRates = samplingRatesFromString( + halListValue.string(), AudioParameter::valueListSeparator); + sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size()); + } + _hidl_cb(sampleRates); + return Void(); +} + +Return<Result> Stream::setSampleRate(uint32_t sampleRateHz) { + return setParam(AudioParameter::keySamplingRate, static_cast<int>(sampleRateHz)); +} + +Return<AudioChannelMask> Stream::getChannelMask() { + return AudioChannelMask(mStream->get_channels(mStream)); +} + +Return<void> Stream::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { + String8 halListValue; + Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue); + hidl_vec<AudioChannelMask> channelMasks; + SortedVector<audio_channel_mask_t> halChannelMasks; + if (result == Result::OK) { + halChannelMasks = channelMasksFromString( + halListValue.string(), AudioParameter::valueListSeparator); + channelMasks.resize(halChannelMasks.size()); + for (size_t i = 0; i < halChannelMasks.size(); ++i) { + channelMasks[i] = AudioChannelMask(halChannelMasks[i]); + } + } + _hidl_cb(channelMasks); + return Void(); +} + +Return<Result> Stream::setChannelMask(AudioChannelMask mask) { + return setParam(AudioParameter::keyChannels, static_cast<int>(mask)); +} + +Return<AudioFormat> Stream::getFormat() { + return AudioFormat(mStream->get_format(mStream)); +} + +Return<void> Stream::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { + String8 halListValue; + Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue); + hidl_vec<AudioFormat> formats; + Vector<audio_format_t> halFormats; + if (result == Result::OK) { + halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator); + formats.resize(halFormats.size()); + for (size_t i = 0; i < halFormats.size(); ++i) { + formats[i] = AudioFormat(halFormats[i]); + } + } + _hidl_cb(formats); + return Void(); +} + +Return<Result> Stream::setFormat(AudioFormat format) { + return setParam(AudioParameter::keyFormat, static_cast<int>(format)); +} + +Return<void> Stream::getAudioProperties(getAudioProperties_cb _hidl_cb) { + uint32_t halSampleRate = mStream->get_sample_rate(mStream); + audio_channel_mask_t halMask = mStream->get_channels(mStream); + audio_format_t halFormat = mStream->get_format(mStream); + _hidl_cb(halSampleRate, AudioChannelMask(halMask), AudioFormat(halFormat)); + return Void(); +} + +Return<Result> Stream::addEffect(uint64_t effectId) { + effect_handle_t halEffect = EffectMap::getInstance().get(effectId); + if (halEffect != NULL) { + return analyzeStatus("add_audio_effect", mStream->add_audio_effect(mStream, halEffect)); + } else { + ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId); + return Result::INVALID_ARGUMENTS; + } +} + +Return<Result> Stream::removeEffect(uint64_t effectId) { + effect_handle_t halEffect = EffectMap::getInstance().get(effectId); + if (halEffect != NULL) { + return analyzeStatus( + "remove_audio_effect", mStream->remove_audio_effect(mStream, halEffect)); + } else { + ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId); + return Result::INVALID_ARGUMENTS; + } +} + +Return<Result> Stream::standby() { + return analyzeStatus("standby", mStream->standby(mStream)); +} + +Return<AudioDevice> Stream::getDevice() { + int device; + Result retval = getParam(AudioParameter::keyRouting, &device); + return retval == Result::OK ? static_cast<AudioDevice>(device) : AudioDevice::NONE; +} + +Return<Result> Stream::setDevice(const DeviceAddress& address) { + char* halDeviceAddress = + audio_device_address_to_parameter( + static_cast<audio_devices_t>(address.device), + deviceAddressToHal(address).c_str()); + AudioParameter params((String8(halDeviceAddress))); + free(halDeviceAddress); + params.addInt( + String8(AudioParameter::keyRouting), static_cast<audio_devices_t>(address.device)); + return setParams(params); +} + +Return<Result> Stream::setConnectedState(const DeviceAddress& address, bool connected) { + return setParam( + connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect, + deviceAddressToHal(address).c_str()); +} + +Return<Result> Stream::setHwAvSync(uint32_t hwAvSync) { + return setParam(AudioParameter::keyStreamHwAvSync, static_cast<int>(hwAvSync)); +} + +Return<void> Stream::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { + getParametersImpl(keys, _hidl_cb); + return Void(); +} + +Return<Result> Stream::setParameters(const hidl_vec<ParameterValue>& parameters) { + return setParametersImpl(parameters); +} + +Return<void> Stream::debugDump(const hidl_handle& fd) { + if (fd->numFds == 1) { + analyzeStatus("dump", mStream->dump(mStream, fd->data[0])); + } + return Void(); +} + +Return<Result> Stream::start() { + return Result::NOT_SUPPORTED; +} + +Return<Result> Stream::stop() { + return Result::NOT_SUPPORTED; +} + +Return<void> Stream::createMmapBuffer(int32_t minSizeFrames __unused, + createMmapBuffer_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + MmapBufferInfo info; + _hidl_cb(retval, info); + return Void(); +} + +Return<void> Stream::getMmapPosition(getMmapPosition_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + MmapPosition position; + _hidl_cb(retval, position); + return Void(); +} + +Return<Result> Stream::close() { + return Result::NOT_SUPPORTED; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h new file mode 100644 index 0000000..b49e658 --- /dev/null +++ b/audio/2.0/default/Stream.h
@@ -0,0 +1,179 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H +#define ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H + +#include <android/hardware/audio/2.0/IStream.h> +#include <hardware/audio.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "ParametersUtil.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioFormat; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IStream; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Stream : public IStream, public ParametersUtil { + explicit Stream(audio_stream_t* stream); + + // Methods from ::android::hardware::audio::V2_0::IStream follow. + Return<uint64_t> getFrameSize() override; + Return<uint64_t> getFrameCount() override; + Return<uint64_t> getBufferSize() override; + Return<uint32_t> getSampleRate() override; + Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; + Return<Result> setSampleRate(uint32_t sampleRateHz) override; + Return<AudioChannelMask> getChannelMask() override; + Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; + Return<Result> setChannelMask(AudioChannelMask mask) override; + Return<AudioFormat> getFormat() override; + Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb) override; + Return<Result> setFormat(AudioFormat format) override; + Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb) override; + Return<Result> addEffect(uint64_t effectId) override; + Return<Result> removeEffect(uint64_t effectId) override; + Return<Result> standby() override; + Return<AudioDevice> getDevice() override; + Return<Result> setDevice(const DeviceAddress& address) override; + Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override; + Return<Result> setHwAvSync(uint32_t hwAvSync) override; + Return<void> getParameters( + const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; + Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; + Return<void> debugDump(const hidl_handle& fd) override; + Return<Result> start() override; + Return<Result> stop() override; + Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; + Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override; + Return<Result> close() override; + + // Utility methods for extending interfaces. + static Result analyzeStatus( + const char* funcName, int status, int ignoreError = OK, int ignoreError2 = OK); + + private: + audio_stream_t *mStream; + + virtual ~Stream(); + + // Methods from ParametersUtil. + char* halGetParameters(const char* keys) override; + int halSetParameters(const char* keysAndValues) override; +}; + + +template <typename T> +struct StreamMmap : public RefBase { + explicit StreamMmap(T* stream) : mStream(stream) {} + + Return<Result> start(); + Return<Result> stop(); + Return<void> createMmapBuffer( + int32_t minSizeFrames, size_t frameSize, IStream::createMmapBuffer_cb _hidl_cb); + Return<void> getMmapPosition(IStream::getMmapPosition_cb _hidl_cb); + + private: + StreamMmap() {} + + T *mStream; +}; + +template <typename T> +Return<Result> StreamMmap<T>::start() { + if (mStream->start == NULL) return Result::NOT_SUPPORTED; + int result = mStream->start(mStream); + return Stream::analyzeStatus("start", result); +} + +template <typename T> +Return<Result> StreamMmap<T>::stop() { + if (mStream->stop == NULL) return Result::NOT_SUPPORTED; + int result = mStream->stop(mStream); + return Stream::analyzeStatus("stop", result); +} + +template <typename T> +Return<void> StreamMmap<T>::createMmapBuffer(int32_t minSizeFrames, size_t frameSize, + IStream::createMmapBuffer_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + MmapBufferInfo info; + native_handle_t* hidlHandle = nullptr; + + if (mStream->create_mmap_buffer != NULL) { + struct audio_mmap_buffer_info halInfo; + retval = Stream::analyzeStatus( + "create_mmap_buffer", + mStream->create_mmap_buffer(mStream, minSizeFrames, &halInfo)); + if (retval == Result::OK) { + hidlHandle = native_handle_create(1, 0); + hidlHandle->data[0] = halInfo.shared_memory_fd; + info.sharedMemory = hidl_memory("audio_buffer", hidlHandle, + frameSize *halInfo.buffer_size_frames); + info.bufferSizeFrames = halInfo.buffer_size_frames; + info.burstSizeFrames = halInfo.burst_size_frames; + } + } + _hidl_cb(retval, info); + if (hidlHandle != nullptr) { + native_handle_delete(hidlHandle); + } + return Void(); +} + +template <typename T> +Return<void> StreamMmap<T>::getMmapPosition(IStream::getMmapPosition_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + MmapPosition position; + + if (mStream->get_mmap_position != NULL) { + struct audio_mmap_position halPosition; + retval = Stream::analyzeStatus( + "get_mmap_position", + mStream->get_mmap_position(mStream, &halPosition)); + if (retval == Result::OK) { + position.timeNanoseconds = halPosition.time_nanoseconds; + position.positionFrames = halPosition.position_frames; + } + } + _hidl_cb(retval, position); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H
diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp new file mode 100644 index 0000000..a8229d3 --- /dev/null +++ b/audio/2.0/default/StreamIn.cpp
@@ -0,0 +1,394 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "StreamInHAL" +//#define LOG_NDEBUG 0 +#define ATRACE_TAG ATRACE_TAG_AUDIO + +#include <android/log.h> +#include <hardware/audio.h> +#include <utils/Trace.h> + +#include "StreamIn.h" + +using ::android::hardware::audio::V2_0::MessageQueueFlagBits; + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::ThreadInfo; + +namespace { + +class ReadThread : public Thread { + public: + // ReadThread's lifespan never exceeds StreamIn's lifespan. + ReadThread(std::atomic<bool>* stop, + audio_stream_in_t* stream, + StreamIn::CommandMQ* commandMQ, + StreamIn::DataMQ* dataMQ, + StreamIn::StatusMQ* statusMQ, + EventFlag* efGroup) + : Thread(false /*canCallJava*/), + mStop(stop), + mStream(stream), + mCommandMQ(commandMQ), + mDataMQ(dataMQ), + mStatusMQ(statusMQ), + mEfGroup(efGroup), + mBuffer(new uint8_t[dataMQ->getQuantumCount()]) { + } + virtual ~ReadThread() {} + + private: + std::atomic<bool>* mStop; + audio_stream_in_t* mStream; + StreamIn::CommandMQ* mCommandMQ; + StreamIn::DataMQ* mDataMQ; + StreamIn::StatusMQ* mStatusMQ; + EventFlag* mEfGroup; + std::unique_ptr<uint8_t[]> mBuffer; + IStreamIn::ReadParameters mParameters; + IStreamIn::ReadStatus mStatus; + + bool threadLoop() override; + + void doGetCapturePosition(); + void doRead(); +}; + +void ReadThread::doRead() { + size_t availableToWrite = mDataMQ->availableToWrite(); + size_t requestedToRead = mParameters.params.read; + if (requestedToRead > availableToWrite) { + ALOGW("truncating read data from %d to %d due to insufficient data queue space", + (int32_t)requestedToRead, (int32_t)availableToWrite); + requestedToRead = availableToWrite; + } + ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead); + mStatus.retval = Result::OK; + uint64_t read = 0; + if (readResult >= 0) { + mStatus.reply.read = readResult; + if (!mDataMQ->write(&mBuffer[0], readResult)) { + ALOGW("data message queue write failed"); + } + } else { + mStatus.retval = Stream::analyzeStatus("read", readResult); + } +} + +void ReadThread::doGetCapturePosition() { + mStatus.retval = StreamIn::getCapturePositionImpl( + mStream, &mStatus.reply.capturePosition.frames, &mStatus.reply.capturePosition.time); +} + +bool ReadThread::threadLoop() { + // This implementation doesn't return control back to the Thread until it decides to stop, + // as the Thread uses mutexes, and this can lead to priority inversion. + while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) { + // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 + uint32_t efState = 0; + mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState); + if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) { + continue; // Nothing to do. + } + if (!mCommandMQ->read(&mParameters)) { + continue; // Nothing to do. + } + mStatus.replyTo = mParameters.command; + switch (mParameters.command) { + case IStreamIn::ReadCommand::READ: + doRead(); + break; + case IStreamIn::ReadCommand::GET_CAPTURE_POSITION: + doGetCapturePosition(); + break; + default: + ALOGE("Unknown read thread command code %d", mParameters.command); + mStatus.retval = Result::NOT_SUPPORTED; + break; + } + if (!mStatusMQ->write(&mStatus)) { + ALOGW("status message queue write failed"); + } + mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)); + } + + return false; +} + +} // namespace + +StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream) + : mIsClosed(false), mDevice(device), mStream(stream), + mStreamCommon(new Stream(&stream->common)), + mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)), + mEfGroup(nullptr), mStopReadThread(false) { +} + +StreamIn::~StreamIn() { + ATRACE_CALL(); + close(); + if (mReadThread.get()) { + ATRACE_NAME("mReadThread->join"); + status_t status = mReadThread->join(); + ALOGE_IF(status, "read thread exit error: %s", strerror(-status)); + } + if (mEfGroup) { + status_t status = EventFlag::deleteEventFlag(&mEfGroup); + ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status)); + } + mDevice->close_input_stream(mDevice, mStream); + mStream = nullptr; + mDevice = nullptr; +} + +// Methods from ::android::hardware::audio::V2_0::IStream follow. +Return<uint64_t> StreamIn::getFrameSize() { + return audio_stream_in_frame_size(mStream); +} + +Return<uint64_t> StreamIn::getFrameCount() { + return mStreamCommon->getFrameCount(); +} + +Return<uint64_t> StreamIn::getBufferSize() { + return mStreamCommon->getBufferSize(); +} + +Return<uint32_t> StreamIn::getSampleRate() { + return mStreamCommon->getSampleRate(); +} + +Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { + return mStreamCommon->getSupportedSampleRates(_hidl_cb); +} + +Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) { + return mStreamCommon->setSampleRate(sampleRateHz); +} + +Return<AudioChannelMask> StreamIn::getChannelMask() { + return mStreamCommon->getChannelMask(); +} + +Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { + return mStreamCommon->getSupportedChannelMasks(_hidl_cb); +} + +Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) { + return mStreamCommon->setChannelMask(mask); +} + +Return<AudioFormat> StreamIn::getFormat() { + return mStreamCommon->getFormat(); +} + +Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { + return mStreamCommon->getSupportedFormats(_hidl_cb); +} + +Return<Result> StreamIn::setFormat(AudioFormat format) { + return mStreamCommon->setFormat(format); +} + +Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) { + return mStreamCommon->getAudioProperties(_hidl_cb); +} + +Return<Result> StreamIn::addEffect(uint64_t effectId) { + return mStreamCommon->addEffect(effectId); +} + +Return<Result> StreamIn::removeEffect(uint64_t effectId) { + return mStreamCommon->removeEffect(effectId); +} + +Return<Result> StreamIn::standby() { + return mStreamCommon->standby(); +} + +Return<AudioDevice> StreamIn::getDevice() { + return mStreamCommon->getDevice(); +} + +Return<Result> StreamIn::setDevice(const DeviceAddress& address) { + return mStreamCommon->setDevice(address); +} + +Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) { + return mStreamCommon->setConnectedState(address, connected); +} + +Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) { + return mStreamCommon->setHwAvSync(hwAvSync); +} + +Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { + return mStreamCommon->getParameters(keys, _hidl_cb); +} + +Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) { + return mStreamCommon->setParameters(parameters); +} + +Return<void> StreamIn::debugDump(const hidl_handle& fd) { + return mStreamCommon->debugDump(fd); +} + +Return<Result> StreamIn::start() { + return mStreamMmap->start(); +} + +Return<Result> StreamIn::stop() { + return mStreamMmap->stop(); +} + +Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) { + return mStreamMmap->createMmapBuffer( + minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb); +} + +Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) { + return mStreamMmap->getMmapPosition(_hidl_cb); +} + +Return<Result> StreamIn::close() { + if (mIsClosed) return Result::INVALID_STATE; + mIsClosed = true; + if (mReadThread.get()) { + mStopReadThread.store(true, std::memory_order_release); + } + if (mEfGroup) { + mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); + } + return Result::OK; +} + +// Methods from ::android::hardware::audio::V2_0::IStreamIn follow. +Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) { + int halSource; + Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource); + AudioSource source(AudioSource::DEFAULT); + if (retval == Result::OK) { + source = AudioSource(halSource); + } + _hidl_cb(retval, source); + return Void(); +} + +Return<Result> StreamIn::setGain(float gain) { + return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain)); +} + +Return<void> StreamIn::prepareForReading( + uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) { + status_t status; + ThreadInfo threadInfo = { 0, 0 }; + // Create message queues. + if (mDataMQ) { + ALOGE("the client attempts to call prepareForReading twice"); + _hidl_cb(Result::INVALID_STATE, + CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); + return Void(); + } + std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1)); + std::unique_ptr<DataMQ> tempDataMQ( + new DataMQ(frameSize * framesCount, true /* EventFlag */)); + std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1)); + if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) { + ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid"); + ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid"); + ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid"); + _hidl_cb(Result::INVALID_ARGUMENTS, + CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); + return Void(); + } + // TODO: Remove event flag management once blocking MQ is implemented. b/33815422 + status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); + if (status != OK || !mEfGroup) { + ALOGE("failed creating event flag for data MQ: %s", strerror(-status)); + _hidl_cb(Result::INVALID_ARGUMENTS, + CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); + return Void(); + } + + // Create and launch the thread. + mReadThread = new ReadThread( + &mStopReadThread, + mStream, + tempCommandMQ.get(), + tempDataMQ.get(), + tempStatusMQ.get(), + mEfGroup); + status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO); + if (status != OK) { + ALOGW("failed to start reader thread: %s", strerror(-status)); + _hidl_cb(Result::INVALID_ARGUMENTS, + CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); + return Void(); + } + + mCommandMQ = std::move(tempCommandMQ); + mDataMQ = std::move(tempDataMQ); + mStatusMQ = std::move(tempStatusMQ); + threadInfo.pid = getpid(); + threadInfo.tid = mReadThread->getTid(); + _hidl_cb(Result::OK, + *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(), + threadInfo); + return Void(); +} + +Return<uint32_t> StreamIn::getInputFramesLost() { + return mStream->get_input_frames_lost(mStream); +} + +// static +Result StreamIn::getCapturePositionImpl( + audio_stream_in_t *stream, uint64_t *frames, uint64_t *time) { + Result retval(Result::NOT_SUPPORTED); + if (stream->get_capture_position != NULL) return retval; + int64_t halFrames, halTime; + retval = Stream::analyzeStatus( + "get_capture_position", + stream->get_capture_position(stream, &halFrames, &halTime), + // HAL may have a stub function, always returning ENOSYS, don't + // spam the log in this case. + ENOSYS); + if (retval == Result::OK) { + *frames = halFrames; + *time = halTime; + } + return retval; +}; + +Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) { + uint64_t frames = 0, time = 0; + Result retval = getCapturePositionImpl(mStream, &frames, &time); + _hidl_cb(retval, frames, time); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/2.0/default/StreamIn.h b/audio/2.0/default/StreamIn.h new file mode 100644 index 0000000..b867387 --- /dev/null +++ b/audio/2.0/default/StreamIn.h
@@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H +#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H + +#include <atomic> +#include <memory> + +#include <android/hardware/audio/2.0/IStreamIn.h> +#include <hidl/MQDescriptor.h> +#include <fmq/EventFlag.h> +#include <fmq/MessageQueue.h> +#include <hidl/Status.h> +#include <utils/Thread.h> + +#include "Stream.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioFormat; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IStream; +using ::android::hardware::audio::V2_0::IStreamIn; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct StreamIn : public IStreamIn { + typedef MessageQueue<ReadParameters, kSynchronizedReadWrite> CommandMQ; + typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ; + typedef MessageQueue<ReadStatus, kSynchronizedReadWrite> StatusMQ; + + StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream); + + // Methods from ::android::hardware::audio::V2_0::IStream follow. + Return<uint64_t> getFrameSize() override; + Return<uint64_t> getFrameCount() override; + Return<uint64_t> getBufferSize() override; + Return<uint32_t> getSampleRate() override; + Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; + Return<Result> setSampleRate(uint32_t sampleRateHz) override; + Return<AudioChannelMask> getChannelMask() override; + Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; + Return<Result> setChannelMask(AudioChannelMask mask) override; + Return<AudioFormat> getFormat() override; + Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb) override; + Return<Result> setFormat(AudioFormat format) override; + Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb) override; + Return<Result> addEffect(uint64_t effectId) override; + Return<Result> removeEffect(uint64_t effectId) override; + Return<Result> standby() override; + Return<AudioDevice> getDevice() override; + Return<Result> setDevice(const DeviceAddress& address) override; + Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override; + Return<Result> setHwAvSync(uint32_t hwAvSync) override; + Return<void> getParameters( + const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; + Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; + Return<void> debugDump(const hidl_handle& fd) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::V2_0::IStreamIn follow. + Return<void> getAudioSource(getAudioSource_cb _hidl_cb) override; + Return<Result> setGain(float gain) override; + Return<void> prepareForReading( + uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb) override; + Return<uint32_t> getInputFramesLost() override; + Return<void> getCapturePosition(getCapturePosition_cb _hidl_cb) override; + Return<Result> start() override; + Return<Result> stop() override; + Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; + Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override; + + static Result getCapturePositionImpl( + audio_stream_in_t *stream, uint64_t *frames, uint64_t *time); + + private: + bool mIsClosed; + audio_hw_device_t *mDevice; + audio_stream_in_t *mStream; + sp<Stream> mStreamCommon; + sp<StreamMmap<audio_stream_in_t>> mStreamMmap; + std::unique_ptr<CommandMQ> mCommandMQ; + std::unique_ptr<DataMQ> mDataMQ; + std::unique_ptr<StatusMQ> mStatusMQ; + EventFlag* mEfGroup; + std::atomic<bool> mStopReadThread; + sp<Thread> mReadThread; + + virtual ~StreamIn(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp new file mode 100644 index 0000000..6ccdbcd --- /dev/null +++ b/audio/2.0/default/StreamOut.cpp
@@ -0,0 +1,484 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "StreamOutHAL" +//#define LOG_NDEBUG 0 +#define ATRACE_TAG ATRACE_TAG_AUDIO + +#include <android/log.h> +#include <hardware/audio.h> +#include <utils/Trace.h> + +#include "StreamOut.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::ThreadInfo; + +namespace { + +class WriteThread : public Thread { + public: + // WriteThread's lifespan never exceeds StreamOut's lifespan. + WriteThread(std::atomic<bool>* stop, + audio_stream_out_t* stream, + StreamOut::CommandMQ* commandMQ, + StreamOut::DataMQ* dataMQ, + StreamOut::StatusMQ* statusMQ, + EventFlag* efGroup) + : Thread(false /*canCallJava*/), + mStop(stop), + mStream(stream), + mCommandMQ(commandMQ), + mDataMQ(dataMQ), + mStatusMQ(statusMQ), + mEfGroup(efGroup), + mBuffer(new uint8_t[dataMQ->getQuantumCount()]) { + } + virtual ~WriteThread() {} + + private: + std::atomic<bool>* mStop; + audio_stream_out_t* mStream; + StreamOut::CommandMQ* mCommandMQ; + StreamOut::DataMQ* mDataMQ; + StreamOut::StatusMQ* mStatusMQ; + EventFlag* mEfGroup; + std::unique_ptr<uint8_t[]> mBuffer; + IStreamOut::WriteStatus mStatus; + + bool threadLoop() override; + + void doGetLatency(); + void doGetPresentationPosition(); + void doWrite(); +}; + +void WriteThread::doWrite() { + const size_t availToRead = mDataMQ->availableToRead(); + mStatus.retval = Result::OK; + mStatus.reply.written = 0; + if (mDataMQ->read(&mBuffer[0], availToRead)) { + ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead); + if (writeResult >= 0) { + mStatus.reply.written = writeResult; + } else { + mStatus.retval = Stream::analyzeStatus("write", writeResult); + } + } +} + +void WriteThread::doGetPresentationPosition() { + mStatus.retval = StreamOut::getPresentationPositionImpl( + mStream, + &mStatus.reply.presentationPosition.frames, + &mStatus.reply.presentationPosition.timeStamp); +} + +void WriteThread::doGetLatency() { + mStatus.retval = Result::OK; + mStatus.reply.latencyMs = mStream->get_latency(mStream); +} + +bool WriteThread::threadLoop() { + // This implementation doesn't return control back to the Thread until it decides to stop, + // as the Thread uses mutexes, and this can lead to priority inversion. + while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) { + // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422 + uint32_t efState = 0; + mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState); + if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) { + continue; // Nothing to do. + } + if (!mCommandMQ->read(&mStatus.replyTo)) { + continue; // Nothing to do. + } + switch (mStatus.replyTo) { + case IStreamOut::WriteCommand::WRITE: + doWrite(); + break; + case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION: + doGetPresentationPosition(); + break; + case IStreamOut::WriteCommand::GET_LATENCY: + doGetLatency(); + break; + default: + ALOGE("Unknown write thread command code %d", mStatus.replyTo); + mStatus.retval = Result::NOT_SUPPORTED; + break; + } + if (!mStatusMQ->write(&mStatus)) { + ALOGE("status message queue write failed"); + } + mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)); + } + + return false; +} + +} // namespace + +StreamOut::StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream) + : mIsClosed(false), mDevice(device), mStream(stream), + mStreamCommon(new Stream(&stream->common)), + mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)), + mEfGroup(nullptr), mStopWriteThread(false) { +} + +StreamOut::~StreamOut() { + ATRACE_CALL(); + close(); + if (mWriteThread.get()) { + ATRACE_NAME("mWriteThread->join"); + status_t status = mWriteThread->join(); + ALOGE_IF(status, "write thread exit error: %s", strerror(-status)); + } + if (mEfGroup) { + status_t status = EventFlag::deleteEventFlag(&mEfGroup); + ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status)); + } + mCallback.clear(); + mDevice->close_output_stream(mDevice, mStream); + mStream = nullptr; + mDevice = nullptr; +} + +// Methods from ::android::hardware::audio::V2_0::IStream follow. +Return<uint64_t> StreamOut::getFrameSize() { + return audio_stream_out_frame_size(mStream); +} + +Return<uint64_t> StreamOut::getFrameCount() { + return mStreamCommon->getFrameCount(); +} + +Return<uint64_t> StreamOut::getBufferSize() { + return mStreamCommon->getBufferSize(); +} + +Return<uint32_t> StreamOut::getSampleRate() { + return mStreamCommon->getSampleRate(); +} + +Return<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) { + return mStreamCommon->getSupportedSampleRates(_hidl_cb); +} + +Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) { + return mStreamCommon->setSampleRate(sampleRateHz); +} + +Return<AudioChannelMask> StreamOut::getChannelMask() { + return mStreamCommon->getChannelMask(); +} + +Return<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) { + return mStreamCommon->getSupportedChannelMasks(_hidl_cb); +} + +Return<Result> StreamOut::setChannelMask(AudioChannelMask mask) { + return mStreamCommon->setChannelMask(mask); +} + +Return<AudioFormat> StreamOut::getFormat() { + return mStreamCommon->getFormat(); +} + +Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) { + return mStreamCommon->getSupportedFormats(_hidl_cb); +} + +Return<Result> StreamOut::setFormat(AudioFormat format) { + return mStreamCommon->setFormat(format); +} + +Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) { + return mStreamCommon->getAudioProperties(_hidl_cb); +} + +Return<Result> StreamOut::addEffect(uint64_t effectId) { + return mStreamCommon->addEffect(effectId); +} + +Return<Result> StreamOut::removeEffect(uint64_t effectId) { + return mStreamCommon->removeEffect(effectId); +} + +Return<Result> StreamOut::standby() { + return mStreamCommon->standby(); +} + +Return<AudioDevice> StreamOut::getDevice() { + return mStreamCommon->getDevice(); +} + +Return<Result> StreamOut::setDevice(const DeviceAddress& address) { + return mStreamCommon->setDevice(address); +} + +Return<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) { + return mStreamCommon->setConnectedState(address, connected); +} + +Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) { + return mStreamCommon->setHwAvSync(hwAvSync); +} + +Return<void> StreamOut::getParameters( + const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) { + return mStreamCommon->getParameters(keys, _hidl_cb); +} + +Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) { + return mStreamCommon->setParameters(parameters); +} + +Return<void> StreamOut::debugDump(const hidl_handle& fd) { + return mStreamCommon->debugDump(fd); +} + +Return<Result> StreamOut::close() { + if (mIsClosed) return Result::INVALID_STATE; + mIsClosed = true; + if (mWriteThread.get()) { + mStopWriteThread.store(true, std::memory_order_release); + } + if (mEfGroup) { + mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)); + } + return Result::OK; +} + +// Methods from ::android::hardware::audio::V2_0::IStreamOut follow. +Return<uint32_t> StreamOut::getLatency() { + return mStream->get_latency(mStream); +} + +Return<Result> StreamOut::setVolume(float left, float right) { + Result retval(Result::NOT_SUPPORTED); + if (mStream->set_volume != NULL) { + retval = Stream::analyzeStatus( + "set_volume", mStream->set_volume(mStream, left, right)); + } + return retval; +} + +Return<void> StreamOut::prepareForWriting( + uint32_t frameSize, uint32_t framesCount, prepareForWriting_cb _hidl_cb) { + status_t status; + ThreadInfo threadInfo = { 0, 0 }; + // Create message queues. + if (mDataMQ) { + ALOGE("the client attempts to call prepareForWriting twice"); + _hidl_cb(Result::INVALID_STATE, + CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); + return Void(); + } + std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1)); + std::unique_ptr<DataMQ> tempDataMQ( + new DataMQ(frameSize * framesCount, true /* EventFlag */)); + std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1)); + if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) { + ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid"); + ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid"); + ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid"); + _hidl_cb(Result::INVALID_ARGUMENTS, + CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); + return Void(); + } + // TODO: Remove event flag management once blocking MQ is implemented. b/33815422 + status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup); + if (status != OK || !mEfGroup) { + ALOGE("failed creating event flag for data MQ: %s", strerror(-status)); + _hidl_cb(Result::INVALID_ARGUMENTS, + CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); + return Void(); + } + + // Create and launch the thread. + mWriteThread = new WriteThread( + &mStopWriteThread, + mStream, + tempCommandMQ.get(), + tempDataMQ.get(), + tempStatusMQ.get(), + mEfGroup); + status = mWriteThread->run("writer", PRIORITY_URGENT_AUDIO); + if (status != OK) { + ALOGW("failed to start writer thread: %s", strerror(-status)); + _hidl_cb(Result::INVALID_ARGUMENTS, + CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(), threadInfo); + return Void(); + } + + mCommandMQ = std::move(tempCommandMQ); + mDataMQ = std::move(tempDataMQ); + mStatusMQ = std::move(tempStatusMQ); + threadInfo.pid = getpid(); + threadInfo.tid = mWriteThread->getTid(); + _hidl_cb(Result::OK, + *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(), + threadInfo); + return Void(); +} + +Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) { + uint32_t halDspFrames; + Result retval = Stream::analyzeStatus( + "get_render_position", mStream->get_render_position(mStream, &halDspFrames)); + _hidl_cb(retval, halDspFrames); + return Void(); +} + +Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) { + Result retval(Result::NOT_SUPPORTED); + int64_t timestampUs = 0; + if (mStream->get_next_write_timestamp != NULL) { + retval = Stream::analyzeStatus( + "get_next_write_timestamp", + mStream->get_next_write_timestamp(mStream, ×tampUs)); + } + _hidl_cb(retval, timestampUs); + return Void(); +} + +Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) { + if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; + int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this); + if (result == 0) { + mCallback = callback; + } + return Stream::analyzeStatus("set_callback", result); +} + +Return<Result> StreamOut::clearCallback() { + if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; + mCallback.clear(); + return Result::OK; +} + +// static +int StreamOut::asyncCallback(stream_callback_event_t event, void*, void *cookie) { + wp<StreamOut> weakSelf(reinterpret_cast<StreamOut*>(cookie)); + sp<StreamOut> self = weakSelf.promote(); + if (self == nullptr || self->mCallback == nullptr) return 0; + ALOGV("asyncCallback() event %d", event); + switch (event) { + case STREAM_CBK_EVENT_WRITE_READY: + self->mCallback->onWriteReady(); + break; + case STREAM_CBK_EVENT_DRAIN_READY: + self->mCallback->onDrainReady(); + break; + case STREAM_CBK_EVENT_ERROR: + self->mCallback->onError(); + break; + default: + ALOGW("asyncCallback() unknown event %d", event); + break; + } + return 0; +} + +Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) { + _hidl_cb(mStream->pause != NULL, mStream->resume != NULL); + return Void(); +} + +Return<Result> StreamOut::pause() { + return mStream->pause != NULL ? + Stream::analyzeStatus("pause", mStream->pause(mStream)) : + Result::NOT_SUPPORTED; +} + +Return<Result> StreamOut::resume() { + return mStream->resume != NULL ? + Stream::analyzeStatus("resume", mStream->resume(mStream)) : + Result::NOT_SUPPORTED; +} + +Return<bool> StreamOut::supportsDrain() { + return mStream->drain != NULL; +} + +Return<Result> StreamOut::drain(AudioDrain type) { + return mStream->drain != NULL ? + Stream::analyzeStatus( + "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type))) : + Result::NOT_SUPPORTED; +} + +Return<Result> StreamOut::flush() { + return mStream->flush != NULL ? + Stream::analyzeStatus("flush", mStream->flush(mStream)) : + Result::NOT_SUPPORTED; +} + +// static +Result StreamOut::getPresentationPositionImpl( + audio_stream_out_t *stream, uint64_t *frames, TimeSpec *timeStamp) { + Result retval(Result::NOT_SUPPORTED); + if (stream->get_presentation_position == NULL) return retval; + struct timespec halTimeStamp; + retval = Stream::analyzeStatus( + "get_presentation_position", + stream->get_presentation_position(stream, frames, &halTimeStamp), + // Don't logspam on EINVAL--it's normal for get_presentation_position + // to return it sometimes. EAGAIN may be returned by A2DP audio HAL + // implementation. + EINVAL, EAGAIN); + if (retval == Result::OK) { + timeStamp->tvSec = halTimeStamp.tv_sec; + timeStamp->tvNSec = halTimeStamp.tv_nsec; + } + return retval; +} + +Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) { + uint64_t frames = 0; + TimeSpec timeStamp = { 0, 0 }; + Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp); + _hidl_cb(retval, frames, timeStamp); + return Void(); +} + +Return<Result> StreamOut::start() { + return mStreamMmap->start(); +} + +Return<Result> StreamOut::stop() { + return mStreamMmap->stop(); +} + +Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) { + return mStreamMmap->createMmapBuffer( + minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb); +} + +Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) { + return mStreamMmap->getMmapPosition(_hidl_cb); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/2.0/default/StreamOut.h b/audio/2.0/default/StreamOut.h new file mode 100644 index 0000000..bbe64a1 --- /dev/null +++ b/audio/2.0/default/StreamOut.h
@@ -0,0 +1,138 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H +#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H + +#include <atomic> +#include <memory> + +#include <android/hardware/audio/2.0/IStreamOut.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <fmq/EventFlag.h> +#include <fmq/MessageQueue.h> +#include <utils/Thread.h> + +#include "Stream.h" + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioFormat; +using ::android::hardware::audio::V2_0::AudioDrain; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IStream; +using ::android::hardware::audio::V2_0::IStreamOut; +using ::android::hardware::audio::V2_0::IStreamOutCallback; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::audio::V2_0::TimeSpec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct StreamOut : public IStreamOut { + typedef MessageQueue<WriteCommand, kSynchronizedReadWrite> CommandMQ; + typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ; + typedef MessageQueue<WriteStatus, kSynchronizedReadWrite> StatusMQ; + + StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream); + + // Methods from ::android::hardware::audio::V2_0::IStream follow. + Return<uint64_t> getFrameSize() override; + Return<uint64_t> getFrameCount() override; + Return<uint64_t> getBufferSize() override; + Return<uint32_t> getSampleRate() override; + Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override; + Return<Result> setSampleRate(uint32_t sampleRateHz) override; + Return<AudioChannelMask> getChannelMask() override; + Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override; + Return<Result> setChannelMask(AudioChannelMask mask) override; + Return<AudioFormat> getFormat() override; + Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb) override; + Return<Result> setFormat(AudioFormat format) override; + Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb) override; + Return<Result> addEffect(uint64_t effectId) override; + Return<Result> removeEffect(uint64_t effectId) override; + Return<Result> standby() override; + Return<AudioDevice> getDevice() override; + Return<Result> setDevice(const DeviceAddress& address) override; + Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override; + Return<Result> setHwAvSync(uint32_t hwAvSync) override; + Return<void> getParameters( + const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override; + Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override; + Return<void> debugDump(const hidl_handle& fd) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::V2_0::IStreamOut follow. + Return<uint32_t> getLatency() override; + Return<Result> setVolume(float left, float right) override; + Return<void> prepareForWriting( + uint32_t frameSize, uint32_t framesCount, prepareForWriting_cb _hidl_cb) override; + Return<void> getRenderPosition(getRenderPosition_cb _hidl_cb) override; + Return<void> getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) override; + Return<Result> setCallback(const sp<IStreamOutCallback>& callback) override; + Return<Result> clearCallback() override; + Return<void> supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) override; + Return<Result> pause() override; + Return<Result> resume() override; + Return<bool> supportsDrain() override; + Return<Result> drain(AudioDrain type) override; + Return<Result> flush() override; + Return<void> getPresentationPosition(getPresentationPosition_cb _hidl_cb) override; + Return<Result> start() override; + Return<Result> stop() override; + Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override; + Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override; + + static Result getPresentationPositionImpl( + audio_stream_out_t *stream, uint64_t *frames, TimeSpec *timeStamp); + + private: + bool mIsClosed; + audio_hw_device_t *mDevice; + audio_stream_out_t *mStream; + sp<Stream> mStreamCommon; + sp<StreamMmap<audio_stream_out_t>> mStreamMmap; + sp<IStreamOutCallback> mCallback; + std::unique_ptr<CommandMQ> mCommandMQ; + std::unique_ptr<DataMQ> mDataMQ; + std::unique_ptr<StatusMQ> mStatusMQ; + EventFlag* mEfGroup; + std::atomic<bool> mStopWriteThread; + sp<Thread> mWriteThread; + + virtual ~StreamOut(); + + static int asyncCallback(stream_callback_event_t event, void *param, void *cookie); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
diff --git a/audio/2.0/default/android.hardware.audio@2.0-service.rc b/audio/2.0/default/android.hardware.audio@2.0-service.rc new file mode 100644 index 0000000..eeaf71b --- /dev/null +++ b/audio/2.0/default/android.hardware.audio@2.0-service.rc
@@ -0,0 +1,11 @@ +service audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service + class hal + user audioserver + # media gid needed for /dev/fm (radio) and for /data/misc/media (tee) + group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks + # audioflinger restarts itself when it loses connection with the hal + # and its .rc file has an "onrestart restart audio-hal" rule, thus + # an additional auto-restart from the init process isn't needed. + oneshot
diff --git a/audio/2.0/default/service.cpp b/audio/2.0/default/service.cpp new file mode 100644 index 0000000..f3a858a --- /dev/null +++ b/audio/2.0/default/service.cpp
@@ -0,0 +1,65 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "audiohalservice" + +#include <hidl/HidlTransportSupport.h> +#include <hidl/LegacySupport.h> +#include <android/hardware/audio/2.0/IDevicesFactory.h> +#include <android/hardware/audio/effect/2.0/IEffectsFactory.h> +#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h> +#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h> +#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h> + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::registerPassthroughServiceImplementation; + +using android::hardware::audio::effect::V2_0::IEffectsFactory; +using android::hardware::audio::V2_0::IDevicesFactory; +using android::hardware::soundtrigger::V2_0::ISoundTriggerHw; +using android::hardware::registerPassthroughServiceImplementation; +namespace broadcastradio = android::hardware::broadcastradio; + +#ifdef TARGET_USES_BCRADIO_FUTURE_FEATURES +static const bool useBroadcastRadioFutureFeatures = true; +#else +static const bool useBroadcastRadioFutureFeatures = false; +#endif + +using android::OK; + +int main(int /* argc */, char* /* argv */ []) { + configureRpcThreadpool(16, true /*callerWillJoin*/); + android::status_t status; + status = registerPassthroughServiceImplementation<IDevicesFactory>(); + LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio service: %d", status); + status = registerPassthroughServiceImplementation<IEffectsFactory>(); + LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio effects service: %d", status); + // Soundtrigger and FM radio might be not present. + status = registerPassthroughServiceImplementation<ISoundTriggerHw>("sound_trigger.primary"); + ALOGE_IF(status != OK, "Error while registering soundtrigger service: %d", status); + if (useBroadcastRadioFutureFeatures) { + status = registerPassthroughServiceImplementation< + broadcastradio::V1_1::IBroadcastRadioFactory>(); + } else { + status = registerPassthroughServiceImplementation< + broadcastradio::V1_0::IBroadcastRadioFactory>(); + } + ALOGE_IF(status != OK, "Error while registering fm radio service: %d", status); + joinRpcThreadpool(); + return status; +}
diff --git a/audio/2.0/types.hal b/audio/2.0/types.hal new file mode 100644 index 0000000..8e9ff14 --- /dev/null +++ b/audio/2.0/types.hal
@@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 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.audio@2.0; + +import android.hardware.audio.common@2.0; + +enum Result : int32_t { + OK, + NOT_INITIALIZED, + INVALID_ARGUMENTS, + INVALID_STATE, + NOT_SUPPORTED +}; + +@export(name="audio_drain_type_t", value_prefix="AUDIO_DRAIN_") +enum AudioDrain : int32_t { + /* drain() returns when all data has been played. */ + ALL, + /* drain() returns a short time before all data from the current track has + been played to give time for gapless track switch. */ + EARLY_NOTIFY +}; + +/* + * A substitute for POSIX timespec. + */ +struct TimeSpec { + uint64_t tvSec; // seconds + uint64_t tvNSec; // nanoseconds +}; + +/* + * IEEE 802 MAC address. + */ +typedef uint8_t[6] MacAddress; + +struct ParameterValue { + string key; + string value; +}; + +/* + * Specifies a device in case when several devices of the same type + * can be connected (e.g. BT A2DP, USB). + */ +struct DeviceAddress { + AudioDevice device; // discriminator + union Address { + MacAddress mac; // used for BLUETOOTH_A2DP_* + uint8_t[4] ipv4; // used for IP + struct Alsa { + int32_t card; + int32_t device; + } alsa; // used for USB_* + } address; + string busAddress; // used for BUS + string rSubmixAddress; // used for REMOTE_SUBMIX +}; + +/* + * Mmap buffer descriptor returned by IStream.createMmapBuffer(). + * Used by streams opened in mmap mode. + */ +struct MmapBufferInfo { + memory sharedMemory; // mmap memory buffer + int32_t bufferSizeFrames; // total buffer size in frames + int32_t burstSizeFrames; // transfer size granularity in frames +}; + +/* + * Mmap buffer read/write position returned by IStream.getMmapPosition(). + * Used by streams opened in mmap mode. + */ +struct MmapPosition { + int64_t timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC + int32_t positionFrames; // increasing 32 bit frame count reset when IStream.stop() is called +}; + +/* + * The message queue flags used to synchronize reads and writes from + * message queues used by StreamIn and StreamOut. + */ +enum MessageQueueFlagBits : uint32_t { + NOT_EMPTY = 1 << 0, + NOT_FULL = 1 << 1 +};
diff --git a/audio/2.0/vts/functional/Android.bp b/audio/2.0/vts/functional/Android.bp new file mode 100644 index 0000000..02f9330 --- /dev/null +++ b/audio/2.0/vts/functional/Android.bp
@@ -0,0 +1,38 @@ +// +// Copyright (C) 2017 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. +// + +cc_test { + name: "VtsHalAudioV2_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["AudioPrimaryHidlHalTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libhidlbase", + "libutils", + "libcutils", + "android.hardware.audio@2.0", + "android.hardware.audio.common@2.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + "-Wall", + "-Wextra", + "-Werror", + ], +}
diff --git a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp new file mode 100644 index 0000000..e50b912 --- /dev/null +++ b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,986 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "VtsHalAudioV2_0TargetTest" + +#include <algorithm> +#include <cmath> +#include <cstddef> +#include <cstdio> +#include <limits> +#include <list> +#include <string> +#include <type_traits> +#include <vector> + +#include <VtsHalHidlTargetTestBase.h> + +#include <android-base/logging.h> + +#include <android/hardware/audio/2.0/IDevice.h> +#include <android/hardware/audio/2.0/IDevicesFactory.h> +#include <android/hardware/audio/2.0/IPrimaryDevice.h> +#include <android/hardware/audio/2.0/types.h> +#include <android/hardware/audio/common/2.0/types.h> + +#include "utility/ReturnIn.h" +#include "utility/AssertOk.h" +#include "utility/PrettyPrintAudioTypes.h" + +using std::string; +using std::to_string; +using std::vector; + +using ::android::sp; +using ::android::hardware::Return; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::MQDescriptorSync; +using ::android::hardware::audio::V2_0::DeviceAddress; +using ::android::hardware::audio::V2_0::IDevice; +using ::android::hardware::audio::V2_0::IPrimaryDevice; +using TtyMode = ::android::hardware::audio::V2_0::IPrimaryDevice::TtyMode; +using ::android::hardware::audio::V2_0::IDevicesFactory; +using ::android::hardware::audio::V2_0::IStream; +using ::android::hardware::audio::V2_0::IStreamIn; +using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters; +using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus; +using ::android::hardware::audio::V2_0::IStreamOut; +using ::android::hardware::audio::V2_0::MmapBufferInfo; +using ::android::hardware::audio::V2_0::MmapPosition; +using ::android::hardware::audio::V2_0::ParameterValue; +using ::android::hardware::audio::V2_0::Result; +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioConfig; +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioFormat; +using ::android::hardware::audio::common::V2_0::AudioHandleConsts; +using ::android::hardware::audio::common::V2_0::AudioInputFlag; +using ::android::hardware::audio::common::V2_0::AudioIoHandle; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioOffloadInfo; +using ::android::hardware::audio::common::V2_0::AudioOutputFlag; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::common::V2_0::ThreadInfo; + +using utility::returnIn; + +namespace doc { +/** Document the current test case. + * Eg: calling `doc::test("Dump the state of the hal")` in the "debugDump" test will output: + * <testcase name="debugDump" status="run" time="6" classname="AudioPrimaryHidlTest" + description="Dump the state of the hal." /> + * see https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#logging-additional-information + */ +void test(const std::string& testCaseDocumentation) { + ::testing::Test::RecordProperty("description", testCaseDocumentation); +} + +/** Document why a test was not fully run. Usually due to an optional feature not implemented. */ +void partialTest(const std::string& reason) { + ::testing::Test::RecordProperty("partialyRunTest", reason); +} +} + +// Register callback for static object destruction +// Avoid destroying static objects after main return. +// Post main return destruction leads to incorrect gtest timing measurements as well as harder +// debuging if anything goes wrong during destruction. +class Environment : public ::testing::Environment { +public: + using TearDownFunc = std::function<void ()>; + void registerTearDown(TearDownFunc&& tearDown) { + tearDowns.push_back(std::move(tearDown)); + } + +private: + void TearDown() override { + // Call the tear downs in reverse order of insertion + for (auto& tearDown : tearDowns) { + tearDown(); + } + } + std::list<TearDownFunc> tearDowns; +}; +// Instance to register global tearDown +static Environment* environment; + +class HidlTest : public ::testing::VtsHalHidlTargetTestBase { +protected: + // Convenient member to store results + Result res; +}; + +////////////////////////////////////////////////////////////////////////////// +////////////////////// getService audio_devices_factory ////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// Test all audio devices +class AudioHidlTest : public HidlTest { +public: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base + + if (devicesFactory == nullptr) { + environment->registerTearDown([]{ devicesFactory.clear(); }); + devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(); + } + ASSERT_TRUE(devicesFactory != nullptr); + } + +protected: + // Cache the devicesFactory retrieval to speed up each test by ~0.5s + static sp<IDevicesFactory> devicesFactory; +}; +sp<IDevicesFactory> AudioHidlTest::devicesFactory; + +TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) { + doc::test("test the getService (called in SetUp)"); +} + +////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// openDevice primary /////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// Test the primary device +class AudioPrimaryHidlTest : public AudioHidlTest { +public: + /** Primary HAL test are NOT thread safe. */ + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base + + if (device == nullptr) { + IDevicesFactory::Result result; + sp<IDevice> baseDevice; + ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY, + returnIn(result, baseDevice))); + ASSERT_TRUE(baseDevice != nullptr); + + environment->registerTearDown([]{ device.clear(); }); + device = IPrimaryDevice::castFrom(baseDevice); + ASSERT_TRUE(device != nullptr); + } + } + +protected: + // Cache the device opening to speed up each test by ~0.5s + static sp<IPrimaryDevice> device; +}; +sp<IPrimaryDevice> AudioPrimaryHidlTest::device; + +TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) { + doc::test("Test the openDevice (called in SetUp)"); +} + +TEST_F(AudioPrimaryHidlTest, Init) { + doc::test("Test that the audio primary hal initialized correctly"); + ASSERT_OK(device->initCheck()); +} + +////////////////////////////////////////////////////////////////////////////// +///////////////////// {set,get}{Master,Mic}{Mute,Volume} ///////////////////// +////////////////////////////////////////////////////////////////////////////// + +template <class Property> +class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest { +protected: + + /** Test a property getter and setter. */ + template <class Getter, class Setter> + void testAccessors(const string& propertyName, const vector<Property>& valuesToTest, + Setter setter, Getter getter, + const vector<Property>& invalidValues = {}) { + + Property initialValue; // Save initial value to restore it at the end of the test + ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue))); + ASSERT_OK(res); + + for (Property setValue : valuesToTest) { + SCOPED_TRACE("Test " + propertyName + " getter and setter for " + + testing::PrintToString(setValue)); + ASSERT_OK((device.get()->*setter)(setValue)); + Property getValue; + // Make sure the getter returns the same value just set + ASSERT_OK((device.get()->*getter)(returnIn(res, getValue))); + ASSERT_OK(res); + EXPECT_EQ(setValue, getValue); + } + + for (Property invalidValue : invalidValues) { + SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " + + testing::PrintToString(invalidValue)); + EXPECT_RESULT(Result::INVALID_ARGUMENTS, (device.get()->*setter)(invalidValue)); + } + + ASSERT_OK((device.get()->*setter)(initialValue)); // restore initial value + } + + /** Test the getter and setter of an optional feature. */ + template <class Getter, class Setter> + void testOptionalAccessors(const string& propertyName, const vector<Property>& valuesToTest, + Setter setter, Getter getter, + const vector<Property>& invalidValues = {}) { + doc::test("Test the optional " + propertyName + " getters and setter"); + { + SCOPED_TRACE("Test feature support by calling the getter"); + Property initialValue; + ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue))); + if (res == Result::NOT_SUPPORTED) { + doc::partialTest(propertyName + " getter is not supported"); + return; + } + ASSERT_OK(res); // If it is supported it must succeed + } + // The feature is supported, test it + testAccessors(propertyName, valuesToTest, setter, getter, invalidValues); + } +}; + +using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>; + +TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) { + doc::test("Check that the mic can be muted and unmuted"); + testAccessors("mic mute", {true, false, true}, &IDevice::setMicMute, &IDevice::getMicMute); + // TODO: check that the mic is really muted (all sample are 0) +} + +TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) { + doc::test("If master mute is supported, try to mute and unmute the master output"); + testOptionalAccessors("master mute", {true, false, true}, + &IDevice::setMasterMute, &IDevice::getMasterMute); + // TODO: check that the master volume is really muted +} + +using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>; +TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) { + doc::test("Test the master volume if supported"); + testOptionalAccessors("master volume", {0, 0.5, 1}, + &IDevice::setMasterVolume, &IDevice::getMasterVolume, + {-0.1, 1.1, NAN, INFINITY, -INFINITY, + 1 + std::numeric_limits<float>::epsilon()}); + // TODO: check that the master volume is really changed +} + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////////// AudioPatches //////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest { +protected: + bool areAudioPatchesSupported() { + auto result = device->supportsAudioPatches(); + EXPECT_TRUE(result.isOk()); + return result; + } +}; + +TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) { + doc::test("Test if audio patches are supported"); + if (!areAudioPatchesSupported()) { + doc::partialTest("Audio patches are not supported"); + return; + } + // TODO: test audio patches +} + + +////////////////////////////////////////////////////////////////////////////// +//////////////// Required and recommended audio format support /////////////// +// From: https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording +// From: https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback +/////////// TODO: move to the beginning of the file for easier update //////// +////////////////////////////////////////////////////////////////////////////// + +class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest { +public: + // Cache result ? + static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() { + return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, + {8000, 11025, 16000, 22050, 32000, 44100}, + {AudioFormat::PCM_16_BIT}); + } + + static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() { + return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO}, + {24000, 48000}, + {AudioFormat::PCM_16_BIT}); + } + + static const vector<AudioConfig> getSupportedPlaybackAudioConfig() { + // TODO: retrieve audio config supported by the platform + // as declared in the policy configuration + return {}; + } + + static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() { + return combineAudioConfig({AudioChannelMask::IN_MONO}, + {8000, 11025, 16000, 44100}, + {AudioFormat::PCM_16_BIT}); + } + static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() { + return combineAudioConfig({AudioChannelMask::IN_STEREO}, + {22050, 48000}, + {AudioFormat::PCM_16_BIT}); + } + static const vector<AudioConfig> getSupportedCaptureAudioConfig() { + // TODO: retrieve audio config supported by the platform + // as declared in the policy configuration + return {}; + } +private: + static const vector<AudioConfig> combineAudioConfig( + vector<AudioChannelMask> channelMasks, + vector<uint32_t> sampleRates, + vector<AudioFormat> formats) { + vector<AudioConfig> configs; + for (auto channelMask: channelMasks) { + for (auto sampleRate : sampleRates) { + for (auto format : formats) { + AudioConfig config{}; + // leave offloadInfo to 0 + config.channelMask = channelMask; + config.sampleRateHz = sampleRate; + config.format = format; + // FIXME: leave frameCount to 0 ? + configs.push_back(config); + } + } + } + return configs; + } +}; + +/** Generate a test name based on an audio config. + * + * As the only parameter changing are channel mask and sample rate, + * only print those ones in the test name. + */ +static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) { + const AudioConfig& config = info.param; + return to_string(info.index) + "__" + to_string(config.sampleRateHz)+ "_" + + // "MONO" is more clear than "FRONT_LEFT" + ((config.channelMask == AudioChannelMask::OUT_MONO || + config.channelMask == AudioChannelMask::IN_MONO) ? + "MONO" : toString(config.channelMask)); +} + +////////////////////////////////////////////////////////////////////////////// +///////////////////////////// getInputBufferSize ///////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// FIXME: execute input test only if platform declares android.hardware.microphone +// how to get this value ? is it a property ??? + +class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest, + public ::testing::WithParamInterface<AudioConfig> { +protected: + void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) { + uint64_t bufferSize; + ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize))); + + switch (res) { + case Result::INVALID_ARGUMENTS: + EXPECT_FALSE(supportRequired); + break; + case Result::OK: + // Check that the buffer is of a sane size + // For now only that it is > 0 + EXPECT_GT(bufferSize, uint64_t(0)); + break; + default: + FAIL() << "Invalid return status: " << ::testing::PrintToString(res); + } + } +}; + +// Test that the required capture config and those declared in the policy are indeed supported +class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {}; +TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) { + doc::test("Input buffer size must be retrievable for a format with required support."); + inputBufferSizeTest(GetParam(), true); +} +INSTANTIATE_TEST_CASE_P( + RequiredInputBufferSize, RequiredInputBufferSizeTest, + ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()), + &generateTestName); +INSTANTIATE_TEST_CASE_P( + SupportedInputBufferSize, RequiredInputBufferSizeTest, + ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()), + &generateTestName); + +// Test that the recommended capture config are supported or lead to a INVALID_ARGUMENTS return +class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {}; +TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) { + doc::test("Input buffer size should be retrievable for a format with recommended support."); + inputBufferSizeTest(GetParam(), false); +} +INSTANTIATE_TEST_CASE_P( + RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest, + ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()), + &generateTestName); + +////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// setScreenState /////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +TEST_F(AudioPrimaryHidlTest, setScreenState) { + doc::test("Check that the hal can receive the screen state"); + for (bool turnedOn : {false, true, true, false, false}) { + auto ret = device->setScreenState(turnedOn); + ASSERT_TRUE(ret.isOk()); + Result result = ret; + ASSERT_TRUE(result == Result::OK || result == Result::NOT_SUPPORTED) << toString(result); + } +} + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////// {get,set}Parameters ///////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +TEST_F(AudioPrimaryHidlTest, getParameters) { + doc::test("Check that the hal can set and get parameters"); + hidl_vec<hidl_string> keys; + hidl_vec<ParameterValue> values; + ASSERT_OK(device->getParameters(keys, returnIn(res, values))); + ASSERT_OK(device->setParameters(values)); + values.resize(0); + ASSERT_OK(device->setParameters(values)); +} + +////////////////////////////////////////////////////////////////////////////// +//////////////////////////////// debugDebug ////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +template <class DebugDump> +static void testDebugDump(DebugDump debugDump) { + FILE* file = tmpfile(); + ASSERT_NE(nullptr, file) << errno; + + auto* nativeHandle = native_handle_create(1, 0); + ASSERT_NE(nullptr, nativeHandle); + nativeHandle->data[0] = fileno(file); + + hidl_handle handle; + handle.setTo(nativeHandle, true /*take ownership*/); + + // TODO: debugDump does not return a Result. + // This mean that the hal can not report that it not implementing the function. + ASSERT_OK(debugDump(handle)); + + rewind(file); // can not fail + + // Check that at least one bit was written by the hal + char buff; + ASSERT_EQ(size_t{1}, fread(&buff, sizeof(buff), 1, file)); + EXPECT_EQ(0, fclose(file)) << errno; +} + +TEST_F(AudioPrimaryHidlTest, debugDump) { + doc::test("Check that the hal can dump its state without error"); + testDebugDump([this](const auto& handle){ return device->debugDump(handle); }); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////// open{Output,Input}Stream ////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +template <class Stream> +class OpenStreamTest : public AudioConfigPrimaryTest, + public ::testing::WithParamInterface<AudioConfig> { +protected: + template <class Open> + void testOpen(Open openStream, const AudioConfig& config) { + // FIXME: Open a stream without an IOHandle + // This is not required to be accepted by hal implementations + AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE; + AudioConfig suggestedConfig{}; + ASSERT_OK(openStream(ioHandle, config, returnIn(res, stream, suggestedConfig))); + + // TODO: only allow failure for RecommendedPlaybackAudioConfig + switch (res) { + case Result::OK: + ASSERT_TRUE(stream != nullptr); + audioConfig = config; + break; + case Result::INVALID_ARGUMENTS: + ASSERT_TRUE(stream == nullptr); + AudioConfig suggestedConfigRetry; + // Could not open stream with config, try again with the suggested one + ASSERT_OK(openStream(ioHandle, suggestedConfig, + returnIn(res, stream, suggestedConfigRetry))); + // This time it must succeed + ASSERT_OK(res); + ASSERT_TRUE(stream == nullptr); + audioConfig = suggestedConfig; + break; + default: + FAIL() << "Invalid return status: " << ::testing::PrintToString(res); + } + open = true; + } + + Return<Result> closeStream() { + open = false; + return stream->close(); + } +private: + void TearDown() override { + if (open) { + ASSERT_OK(stream->close()); + } + } + +protected: + + AudioConfig audioConfig; + DeviceAddress address = {}; + sp<Stream> stream; + bool open = false; +}; + +////////////////////////////// openOutputStream ////////////////////////////// + +class OutputStreamTest : public OpenStreamTest<IStreamOut> { + virtual void SetUp() override { + ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base + address.device = AudioDevice::OUT_DEFAULT; + const AudioConfig& config = GetParam(); + AudioOutputFlag flags = AudioOutputFlag::NONE; // TODO: test all flag combination + testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb) + { return device->openOutputStream(handle, address, config, flags, cb); }, + config); + } +}; +TEST_P(OutputStreamTest, OpenOutputStreamTest) { + doc::test("Check that output streams can be open with the required and recommended config"); + // Open done in SetUp +} +INSTANTIATE_TEST_CASE_P( + RequiredOutputStreamConfigSupport, OutputStreamTest, + ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()), + &generateTestName); +INSTANTIATE_TEST_CASE_P( + SupportedOutputStreamConfig, OutputStreamTest, + ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()), + &generateTestName); + +INSTANTIATE_TEST_CASE_P( + RecommendedOutputStreamConfigSupport, OutputStreamTest, + ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()), + &generateTestName); + +////////////////////////////// openInputStream ////////////////////////////// + +class InputStreamTest : public OpenStreamTest<IStreamIn> { + + virtual void SetUp() override { + ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base + address.device = AudioDevice::IN_DEFAULT; + const AudioConfig& config = GetParam(); + AudioInputFlag flags = AudioInputFlag::NONE; // TODO: test all flag combination + AudioSource source = AudioSource::DEFAULT; // TODO: test all flag combination + testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb) + { return device->openInputStream(handle, address, config, flags, source, cb); }, + config); + } +}; + +TEST_P(InputStreamTest, OpenInputStreamTest) { + doc::test("Check that input streams can be open with the required and recommended config"); + // Open done in setup +} +INSTANTIATE_TEST_CASE_P( + RequiredInputStreamConfigSupport, InputStreamTest, + ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()), + &generateTestName); +INSTANTIATE_TEST_CASE_P( + SupportedInputStreamConfig, InputStreamTest, + ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()), + &generateTestName); + +INSTANTIATE_TEST_CASE_P( + RecommendedInputStreamConfigSupport, InputStreamTest, + ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()), + &generateTestName); + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// IStream getters /////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +/** Unpack the provided result. + * If the result is not OK, register a failure and return an undefined value. */ +template <class R> +static R extract(Return<R> ret) { + if (!ret.isOk()) { + ADD_FAILURE(); + return R{}; + } + return ret; +} + +/* Could not find a way to write a test for two parametrized class fixure + * thus use this macro do duplicate tests for Input and Output stream */ +#define TEST_IO_STREAM(test_name, documentation, code) \ + TEST_P(InputStreamTest, test_name) { \ + doc::test(documentation); \ + code; \ + } \ + TEST_P(OutputStreamTest, test_name) { \ + doc::test(documentation); \ + code; \ + } + +TEST_IO_STREAM(GetFrameCount, "Check that the stream frame count == the one it was opened with", + ASSERT_EQ(audioConfig.frameCount, extract(stream->getFrameCount()))) + +TEST_IO_STREAM(GetSampleRate, "Check that the stream sample rate == the one it was opened with", + ASSERT_EQ(audioConfig.sampleRateHz, extract(stream->getSampleRate()))) + +TEST_IO_STREAM(GetChannelMask, "Check that the stream channel mask == the one it was opened with", + ASSERT_EQ(audioConfig.channelMask, extract(stream->getChannelMask()))) + +TEST_IO_STREAM(GetFormat, "Check that the stream format == the one it was opened with", + ASSERT_EQ(audioConfig.format, extract(stream->getFormat()))) + +// TODO: for now only check that the framesize is not incoherent +TEST_IO_STREAM(GetFrameSize, "Check that the stream frame size == the one it was opened with", + ASSERT_GT(extract(stream->getFrameSize()), 0U)) + +TEST_IO_STREAM(GetBufferSize, "Check that the stream buffer size== the one it was opened with", + ASSERT_GE(extract(stream->getBufferSize()), \ + extract(stream->getFrameSize()))); + +template <class Property, class CapabilityGetter, class Getter, class Setter> +static void testCapabilityGetter(const string& name, IStream* stream, Property currentValue, + CapabilityGetter capablityGetter, Getter getter, Setter setter) { + hidl_vec<Property> capabilities; + ASSERT_OK((stream->*capablityGetter)(returnIn(capabilities))); + if (capabilities.size() == 0) { + // The default hal should probably return a NOT_SUPPORTED if the hal does not expose + // capability retrieval. For now it returns an empty list if not implemented + doc::partialTest(name + " is not supported"); + return; + }; + // TODO: This code has never been tested on a hal that supports getSupportedSampleRates + EXPECT_NE(std::find(capabilities.begin(), capabilities.end(), currentValue), + capabilities.end()) + << "current " << name << " is not in the list of the supported ones " + << toString(capabilities); + + // Check that all declared supported values are indeed supported + for (auto capability : capabilities) { + ASSERT_OK((stream->*setter)(capability)); + ASSERT_EQ(capability, extract((stream->*getter)())); + } +} + +TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported", + testCapabilityGetter("getSupportedSampleRate", stream.get(), \ + extract(stream->getSampleRate()), \ + &IStream::getSupportedSampleRates, \ + &IStream::getSampleRate, &IStream::setSampleRate)) + +TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported", + testCapabilityGetter("getSupportedChannelMask", stream.get(), \ + extract(stream->getChannelMask()), \ + &IStream::getSupportedChannelMasks, \ + &IStream::getChannelMask, &IStream::setChannelMask)) + +TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported", + testCapabilityGetter("getSupportedFormat", stream.get(), \ + extract(stream->getFormat()), \ + &IStream::getSupportedFormats, \ + &IStream::getFormat, &IStream::setFormat)) + +static void testGetDevice(IStream* stream, AudioDevice expectedDevice) { + auto ret = stream->getDevice(); + ASSERT_TRUE(ret.isOk()); + AudioDevice device = ret; + ASSERT_EQ(expectedDevice, device); +} + +TEST_IO_STREAM(GetDevice, "Check that the stream device == the one it was opened with", + areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") : \ + testGetDevice(stream.get(), address.device)) + +static void testSetDevice(IStream* stream, const DeviceAddress& address) { + DeviceAddress otherAddress = address; + otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? + AudioDevice::OUT_SPEAKER : AudioDevice::IN_BUILTIN_MIC; + EXPECT_OK(stream->setDevice(otherAddress)); + + ASSERT_OK(stream->setDevice(address)); // Go back to the original value +} + +TEST_IO_STREAM(SetDevice, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC", + areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported") : \ + testSetDevice(stream.get(), address)) + +static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) { + uint32_t sampleRateHz; + AudioChannelMask mask; + AudioFormat format; + + stream->getAudioProperties(returnIn(sampleRateHz, mask, format)); + + // FIXME: the qcom hal it does not currently negotiate the sampleRate & channel mask + EXPECT_EQ(expectedConfig.sampleRateHz, sampleRateHz); + EXPECT_EQ(expectedConfig.channelMask, mask); + EXPECT_EQ(expectedConfig.format, format); +} + +TEST_IO_STREAM(GetAudioProperties, + "Check that the stream audio properties == the ones it was opened with", + testGetAudioProperties(stream.get(), audioConfig)) + +static void testConnectedState(IStream* stream) { + DeviceAddress address = {}; + using AD = AudioDevice; + for (auto device : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) { + address.device = device; + + ASSERT_OK(stream->setConnectedState(address, true)); + ASSERT_OK(stream->setConnectedState(address, false)); + } +} +TEST_IO_STREAM(SetConnectedState, + "Check that the stream can be notified of device connection and deconnection", + testConnectedState(stream.get())) + + +static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED}; +TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value", + ASSERT_RESULT(invalidArgsOrNotSupported, stream->setHwAvSync(666))) + +static void checkGetParameter(IStream* stream, hidl_vec<hidl_string> keys, + vector<Result> expectedResults) { + hidl_vec<ParameterValue> parameters; + Result res; + ASSERT_OK(stream->getParameters(keys, returnIn(res, parameters))); + ASSERT_RESULT(expectedResults, res); + if (res == Result::OK) { + ASSERT_EQ(0U, parameters.size()); + } +} + +/* Get/Set parameter is intended to be an opaque channel between vendors app and their HALs. + * Thus can not be meaningfully tested. + * TODO: Doc missing. Should asking for an empty set of params raise an error ? + */ +TEST_IO_STREAM(getEmptySetParameter, "Retrieve the values of an empty set", + checkGetParameter(stream.get(), {} /* keys */, + {Result::OK, Result::INVALID_ARGUMENTS})) + + +TEST_IO_STREAM(getNonExistingParameter, "Retrieve the values of an non existing parameter", + checkGetParameter(stream.get(), {"Non existing key"} /* keys */, + {Result::INVALID_ARGUMENTS})) + +static vector<Result> okOrNotSupported = {Result::OK, Result::INVALID_ARGUMENTS}; +TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters", + ASSERT_RESULT(okOrNotSupported, stream->setParameters({}))) + +TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter", + ASSERT_RESULT(Result::INVALID_ARGUMENTS, + stream->setParameters({{"non existing key", "0"}}))) + +TEST_IO_STREAM(DebugDump, + "Check that a stream can dump its state without error", + testDebugDump([this](const auto& handle){ return stream->debugDump(handle); })) + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////// addRemoveEffect /////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +TEST_IO_STREAM(AddNonExistingEffect, "Adding a non existing effect should fail", + ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->addEffect(666))) +TEST_IO_STREAM(RemoveNonExistingEffect, "Removing a non existing effect should fail", + ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->removeEffect(666))) + +//TODO: positive tests + +////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// Control //////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +TEST_IO_STREAM(standby, "Make sure the stream can be put in stanby", + ASSERT_OK(stream->standby())) // can not fail + +static vector<Result> invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED}; + +TEST_IO_STREAM(startNoMmap, "Starting a mmaped stream before mapping it should fail", + ASSERT_RESULT(invalidStateOrNotSupported, stream->start())) + +TEST_IO_STREAM(stopNoMmap, "Stopping a mmaped stream before mapping it should fail", + ASSERT_RESULT(invalidStateOrNotSupported, stream->stop())) + +TEST_IO_STREAM(getMmapPositionNoMmap, "Get a stream Mmap position before mapping it should fail", + ASSERT_RESULT(invalidStateOrNotSupported, stream->stop())) + +TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream())) +TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", + ASSERT_OK(closeStream()); \ + ASSERT_RESULT(Result::INVALID_STATE, closeStream())) + +static void testCreateTooBigMmapBuffer(IStream* stream) { + MmapBufferInfo info; + Result res; + // Assume that int max is a value too big to be allocated + // This is true currently with a 32bit media server, but might not when it will run in 64 bit + auto minSizeFrames = std::numeric_limits<int32_t>::max(); + ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info))); + ASSERT_RESULT(invalidArgsOrNotSupported, res); +} + +TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail", + testCreateTooBigMmapBuffer(stream.get())) + + +static void testGetMmapPositionOfNonMmapedStream(IStream* stream) { + Result res; + MmapPosition position; + ASSERT_OK(stream->getMmapPosition(returnIn(res, position))); + ASSERT_RESULT(invalidArgsOrNotSupported, res); +} + +TEST_IO_STREAM(GetMmapPositionOfNonMmapedStream, + "Retrieving the mmap position of a non mmaped stream should fail", + testGetMmapPositionOfNonMmapedStream(stream.get())) + +////////////////////////////////////////////////////////////////////////////// +///////////////////////////////// StreamIn /////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +TEST_P(InputStreamTest, GetAudioSource) { + doc::test("Retrieving the audio source of an input stream should always succeed"); + AudioSource source; + ASSERT_OK(stream->getAudioSource(returnIn(res, source))); + ASSERT_OK(res); + ASSERT_EQ(AudioSource::DEFAULT, source); +} + +static void testUnitaryGain(std::function<Return<Result> (float)> setGain) { + for (float value : {0.0, 0.01, 0.5, 0.09, 1.0}) { + SCOPED_TRACE("value=" + to_string(value)); + ASSERT_OK(setGain(value)); + } + for (float value : (float[]){-INFINITY,-1.0, -0.0, + 1.0 + std::numeric_limits<float>::epsilon(), 2.0, INFINITY, + NAN}) { + SCOPED_TRACE("value=" + to_string(value)); + // FIXME: NAN should never be accepted + // FIXME: Missing api doc. What should the impl do if the volume is outside [0,1] ? + ASSERT_RESULT(Result::INVALID_ARGUMENTS, setGain(value)); + } +} + +TEST_P(InputStreamTest, SetGain) { + doc::test("The gain of an input stream should only be set between [0,1]"); + testUnitaryGain([this](float volume) { return stream->setGain(volume); }); +} + +static void testPrepareForReading(IStreamIn* stream, uint32_t frameSize, uint32_t framesCount) { + Result res; + // Ignore output parameters as the call should fail + ASSERT_OK(stream->prepareForReading(frameSize, framesCount, + [&res](auto r, auto&, auto&, auto&, auto&) { res = r; })); + EXPECT_RESULT(invalidArgsOrNotSupported, res); +} + +TEST_P(InputStreamTest, PrepareForReadingWithHugeBuffer) { + doc::test("Preparing a stream for reading with a 2^32 sized buffer should fail"); + testPrepareForReading(stream.get(), 1, std::numeric_limits<uint32_t>::max()); +} + +TEST_P(InputStreamTest, PrepareForReadingCheckOverflow) { + doc::test("Preparing a stream for reading with a overflowing sized buffer should fail"); + auto uintMax = std::numeric_limits<uint32_t>::max(); + testPrepareForReading(stream.get(), uintMax, uintMax); +} + +TEST_P(InputStreamTest, getCapturePosition) { + doc::test("The capture position of a non prepared stream should not be retrievable"); + uint64_t frames; + uint64_t time; + ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time))); + ASSERT_RESULT(invalidStateOrNotSupported, res); +} + +////////////////////////////////////////////////////////////////////////////// +/////////////////////////////// PrimaryDevice //////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + + +TEST_F(AudioPrimaryHidlTest, setVoiceVolume) { + doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]"); + testUnitaryGain([this](float volume) { return device->setVoiceVolume(volume); }); +} + +TEST_F(AudioPrimaryHidlTest, setMode) { + doc::test("Make sure setMode always succeeds if mode is valid"); + for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, + AudioMode::RINGTONE, AudioMode::CURRENT, + AudioMode::NORMAL /* Make sure to leave the test in normal mode */ }) { + SCOPED_TRACE("mode=" + toString(mode)); + ASSERT_OK(device->setMode(mode)); + } + + // FIXME: Missing api doc. What should the impl do if the mode is invalid ? + ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode::INVALID)); +} + + +TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) { + doc::test("Query and set the BT SCO NR&EC state"); + testOptionalAccessors("BtScoNrecEnabled", {true, false, true}, + &IPrimaryDevice::setBtScoNrecEnabled, + &IPrimaryDevice::getBtScoNrecEnabled); +} + +TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) { + doc::test("Query and set the SCO whideband state"); + testOptionalAccessors("BtScoWideband", {true, false, true}, + &IPrimaryDevice::setBtScoWidebandEnabled, + &IPrimaryDevice::getBtScoWidebandEnabled); +} + +using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<TtyMode>; +TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) { + doc::test("Query and set the TTY mode state"); + testOptionalAccessors("TTY mode", {TtyMode::OFF, TtyMode::HCO, TtyMode::VCO, TtyMode::FULL}, + &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode); +} + +TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) { + doc::test("Query and set the HAC state"); + testAccessors("HAC", {true, false, true}, + &IPrimaryDevice::setHacEnabled, + &IPrimaryDevice::getHacEnabled); +} + +////////////////////////////////////////////////////////////////////////////// +//////////////////// Clean caches on global tear down //////////////////////// +////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char** argv) { + environment = new Environment; + ::testing::AddGlobalTestEnvironment(environment); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +}
diff --git a/audio/2.0/vts/functional/utility/AssertOk.h b/audio/2.0/vts/functional/utility/AssertOk.h new file mode 100644 index 0000000..39c9a1d --- /dev/null +++ b/audio/2.0/vts/functional/utility/AssertOk.h
@@ -0,0 +1,71 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <vector> +#include <algorithm> + +#include <hidl/Status.h> + +namespace detail { + +// This is a detail namespace, thus it is OK to import a class as nobody else is allowed to use it +using ::android::hardware::Return; +using ::android::hardware::audio::V2_0::Result; + +inline void assertResult(Result expected, Result result) { + ASSERT_EQ(expected, result); +} + +inline void assertResult(Result expected, Return<Result> ret) { + ASSERT_TRUE(ret.isOk()); + Result result = ret; + assertResult(expected, result); +} + +inline void assertResult(std::vector<Result> expected, Result result) { + if (std::find(expected.begin(), expected.end(), result) != expected.end()) { + return; // result is in expected + } + FAIL() << "Expected result " << ::testing::PrintToString(result) + << " to be one of " << ::testing::PrintToString(expected); +} + +inline void assertResult(std::vector<Result> expected, Return<Result> ret) { + ASSERT_TRUE(ret.isOk()); + Result result = ret; + assertResult(expected, result); +} + +inline void assertOk(Return<void> ret) { + ASSERT_TRUE(ret.isOk()); +} + +inline void assertOk(Result result) { + assertResult(Result::OK, result); +} + +inline void assertOk(Return<Result> ret) { + assertResult(Result::OK, std::move(ret)); +} + +} + +// Test anything provided is and contains only OK +#define ASSERT_OK(ret) ASSERT_NO_FATAL_FAILURE(detail::assertOk(ret)) +#define EXPECT_OK(ret) EXPECT_NO_FATAL_FAILURE(detail::assertOk(ret)) + +#define ASSERT_RESULT(expected, ret) ASSERT_NO_FATAL_FAILURE(detail::assertResult(expected, ret)) +#define EXPECT_RESULT(expected, ret) ASSERT_NO_FATAL_FAILURE(detail::assertResult(expected, ret))
diff --git a/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h new file mode 100644 index 0000000..025cd1c --- /dev/null +++ b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
@@ -0,0 +1,62 @@ +/* + * Copyright (C) 2017 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. + */ +#include <type_traits> + +/** @file Use HIDL generated toString methods to pretty print gtest errors */ + +namespace detail { + +// Print the value of an enum as hex +template <class Enum> +inline void printUnderlyingValue(Enum value, ::std::ostream* os) { + *os << std::hex << " (0x" << static_cast<std::underlying_type_t<Enum>>(value) << ")"; +} + +} // namespace detail + +namespace android { +namespace hardware { +namespace audio { +namespace V2_0 { + +inline void PrintTo(const Result& result, ::std::ostream* os) { + *os << toString(result); + detail::printUnderlyingValue(result, os); +} + +} // namespace V2_0 +namespace common { +namespace V2_0 { + +inline void PrintTo(const AudioConfig& config, ::std::ostream* os) { + *os << toString(config); +} + +inline void PrintTo(const AudioDevice& device, ::std::ostream* os) { + *os << toString(device); + detail::printUnderlyingValue(device, os); +} + +inline void PrintTo(const AudioChannelMask& channelMask, ::std::ostream* os) { + *os << toString(channelMask); + detail::printUnderlyingValue(channelMask, os); +} + +} // namespace V2_0 +} // namespace common +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/2.0/vts/functional/utility/ReturnIn.h b/audio/2.0/vts/functional/utility/ReturnIn.h new file mode 100644 index 0000000..bb2389a --- /dev/null +++ b/audio/2.0/vts/functional/utility/ReturnIn.h
@@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <tuple> + +namespace utility { + +namespace detail { +// Helper class to generate the HIDL synchronous callback +template <class... ResultStore> +class ReturnIn { + public: + // Provide to the constructor the variables where the output parameters must be copied + // TODO: take pointers to match google output parameter style ? + ReturnIn(ResultStore&... ts) : results(ts...) {} + // Synchronous callback + template <class... Results> + void operator() (Results&&...results) { + set(std::forward<Results>(results)...); + } + private: + // Recursively set all output parameters + template <class Head, class... Tail> + void set(Head&& head, Tail&&... tail) { + std::get<sizeof...(ResultStore) - sizeof...(Tail) - 1>(results) + = std::forward<Head>(head); + set(tail...); + } + // Trivial case + void set() {} + + // All variables to set are stored here + std::tuple<ResultStore&...> results; +}; +} // namespace detail + +// Generate the HIDL synchronous callback with a copy policy +// Input: the variables (lvalue reference) where to save the return values +// Output: the callback to provide to a HIDL call with a synchronous callback +// The output parameters *will be copied* do not use this function if you have +// a zero copy policy +template <class... ResultStore> +detail::ReturnIn<ResultStore...> returnIn(ResultStore&... ts) { return {ts...};} + +}
diff --git a/audio/Android.bp b/audio/Android.bp new file mode 100644 index 0000000..8a1e892 --- /dev/null +++ b/audio/Android.bp
@@ -0,0 +1,8 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "2.0", + "2.0/vts/functional", + "common/2.0", + "effect/2.0", + "effect/2.0/vts/functional", +]
diff --git a/audio/common/2.0/Android.bp b/audio/common/2.0/Android.bp new file mode 100644 index 0000000..5330086 --- /dev/null +++ b/audio/common/2.0/Android.bp
@@ -0,0 +1,53 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.audio.common@2.0_hal", + srcs: [ + "types.hal", + ], +} + +genrule { + name: "android.hardware.audio.common@2.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio.common@2.0", + srcs: [ + ":android.hardware.audio.common@2.0_hal", + ], + out: [ + "android/hardware/audio/common/2.0/types.cpp", + ], +} + +genrule { + name: "android.hardware.audio.common@2.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio.common@2.0", + srcs: [ + ":android.hardware.audio.common@2.0_hal", + ], + out: [ + "android/hardware/audio/common/2.0/types.h", + ], +} + +cc_library_shared { + name: "android.hardware.audio.common@2.0", + generated_sources: ["android.hardware.audio.common@2.0_genc++"], + generated_headers: ["android.hardware.audio.common@2.0_genc++_headers"], + export_generated_headers: ["android.hardware.audio.common@2.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + ], +}
diff --git a/audio/common/2.0/Android.mk b/audio/common/2.0/Android.mk new file mode 100644 index 0000000..7d62779 --- /dev/null +++ b/audio/common/2.0/Android.mk
@@ -0,0 +1,39 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.audio.common@2.0-java-constants +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +# +GEN := $(intermediates)/android/hardware/audio/common/V2_0/Constants.java +$(GEN): $(HIDL) +$(GEN): $(LOCAL_PATH)/types.hal + +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava-constants \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.audio.common@2.0 + +$(GEN): + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +# Avoid dependency cycle of framework.jar -> this-library -> framework.jar +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj + +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio/common/2.0/default/Android.mk b/audio/common/2.0/default/Android.mk new file mode 100644 index 0000000..8e2fed4 --- /dev/null +++ b/audio/common/2.0/default/Android.mk
@@ -0,0 +1,32 @@ +# +# Copyright (C) 2016 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. + + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.audio.common@2.0-util +LOCAL_SRC_FILES := \ + EffectMap.cpp \ + HidlUtils.cpp \ + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libhidlbase \ + android.hardware.audio.common@2.0 \ + +include $(BUILD_SHARED_LIBRARY)
diff --git a/audio/common/2.0/default/EffectMap.cpp b/audio/common/2.0/default/EffectMap.cpp new file mode 100644 index 0000000..703b91c --- /dev/null +++ b/audio/common/2.0/default/EffectMap.cpp
@@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <atomic> + +#include "EffectMap.h" + +namespace android { + +ANDROID_SINGLETON_STATIC_INSTANCE(EffectMap); + +// static +const uint64_t EffectMap::INVALID_ID = 0; + +// static +uint64_t EffectMap::makeUniqueId() { + static std::atomic<uint64_t> counter{INVALID_ID + 1}; + return counter++; +} + +uint64_t EffectMap::add(effect_handle_t handle) { + uint64_t newId = makeUniqueId(); + std::lock_guard<std::mutex> lock(mLock); + mEffects.add(newId, handle); + return newId; +} + +effect_handle_t EffectMap::get(const uint64_t& id) { + std::lock_guard<std::mutex> lock(mLock); + ssize_t idx = mEffects.indexOfKey(id); + return idx >= 0 ? mEffects[idx] : NULL; +} + +void EffectMap::remove(effect_handle_t handle) { + std::lock_guard<std::mutex> lock(mLock); + for (size_t i = 0; i < mEffects.size(); ++i) { + if (mEffects[i] == handle) { + mEffects.removeItemsAt(i); + break; + } + } +} + +} // namespace android
diff --git a/audio/common/2.0/default/EffectMap.h b/audio/common/2.0/default/EffectMap.h new file mode 100644 index 0000000..82bbb1f --- /dev/null +++ b/audio/common/2.0/default/EffectMap.h
@@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_audio_V2_0_EffectMap_H_ +#define android_hardware_audio_V2_0_EffectMap_H_ + +#include <mutex> + +#include <hardware/audio_effect.h> +#include <utils/KeyedVector.h> +#include <utils/Singleton.h> + +namespace android { + +// This class needs to be in 'android' ns because Singleton macros require that. +class EffectMap : public Singleton<EffectMap> { + public: + static const uint64_t INVALID_ID; + + uint64_t add(effect_handle_t handle); + effect_handle_t get(const uint64_t& id); + void remove(effect_handle_t handle); + + private: + static uint64_t makeUniqueId(); + + std::mutex mLock; + KeyedVector<uint64_t, effect_handle_t> mEffects; +}; + +} // namespace android + +#endif // android_hardware_audio_V2_0_EffectMap_H_
diff --git a/audio/common/2.0/default/HidlUtils.cpp b/audio/common/2.0/default/HidlUtils.cpp new file mode 100644 index 0000000..241ca90 --- /dev/null +++ b/audio/common/2.0/default/HidlUtils.cpp
@@ -0,0 +1,333 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <string.h> + +#include "HidlUtils.h" + +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioFormat; +using ::android::hardware::audio::common::V2_0::AudioGainMode; +using ::android::hardware::audio::common::V2_0::AudioMixLatencyClass; +using ::android::hardware::audio::common::V2_0::AudioPortConfigMask; +using ::android::hardware::audio::common::V2_0::AudioPortRole; +using ::android::hardware::audio::common::V2_0::AudioPortType; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::common::V2_0::AudioStreamType; + +namespace android { + +void HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) { + config->sampleRateHz = halConfig.sample_rate; + config->channelMask = AudioChannelMask(halConfig.channel_mask); + config->format = AudioFormat(halConfig.format); + audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo); + config->frameCount = halConfig.frame_count; +} + +void HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) { + memset(halConfig, 0, sizeof(audio_config_t)); + halConfig->sample_rate = config.sampleRateHz; + halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask); + halConfig->format = static_cast<audio_format_t>(config.format); + audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info); + halConfig->frame_count = config.frameCount; +} + +void HidlUtils::audioGainConfigFromHal( + const struct audio_gain_config& halConfig, AudioGainConfig* config) { + config->index = halConfig.index; + config->mode = AudioGainMode(halConfig.mode); + config->channelMask = AudioChannelMask(halConfig.channel_mask); + for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) { + config->values[i] = halConfig.values[i]; + } + config->rampDurationMs = halConfig.ramp_duration_ms; +} + +void HidlUtils::audioGainConfigToHal( + const AudioGainConfig& config, struct audio_gain_config* halConfig) { + halConfig->index = config.index; + halConfig->mode = static_cast<audio_gain_mode_t>(config.mode); + halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask); + memset(halConfig->values, 0, sizeof(halConfig->values)); + for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) { + halConfig->values[i] = config.values[i]; + } + halConfig->ramp_duration_ms = config.rampDurationMs; +} + +void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) { + gain->mode = AudioGainMode(halGain.mode); + gain->channelMask = AudioChannelMask(halGain.channel_mask); + gain->minValue = halGain.min_value; + gain->maxValue = halGain.max_value; + gain->defaultValue = halGain.default_value; + gain->stepValue = halGain.step_value; + gain->minRampMs = halGain.min_ramp_ms; + gain->maxRampMs = halGain.max_ramp_ms; +} + +void HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) { + halGain->mode = static_cast<audio_gain_mode_t>(gain.mode); + halGain->channel_mask = static_cast<audio_channel_mask_t>(gain.channelMask); + halGain->min_value = gain.minValue; + halGain->max_value = gain.maxValue; + halGain->default_value = gain.defaultValue; + halGain->step_value = gain.stepValue; + halGain->min_ramp_ms = gain.minRampMs; + halGain->max_ramp_ms = gain.maxRampMs; +} + +void HidlUtils::audioOffloadInfoFromHal( + const audio_offload_info_t& halOffload, AudioOffloadInfo* offload) { + offload->sampleRateHz = halOffload.sample_rate; + offload->channelMask = AudioChannelMask(halOffload.channel_mask); + offload->format = AudioFormat(halOffload.format); + offload->streamType = AudioStreamType(halOffload.stream_type); + offload->bitRatePerSecond = halOffload.bit_rate; + offload->durationMicroseconds = halOffload.duration_us; + offload->hasVideo = halOffload.has_video; + offload->isStreaming = halOffload.is_streaming; +} + +void HidlUtils::audioOffloadInfoToHal( + const AudioOffloadInfo& offload, audio_offload_info_t* halOffload) { + *halOffload = AUDIO_INFO_INITIALIZER; + halOffload->sample_rate = offload.sampleRateHz; + halOffload->channel_mask = static_cast<audio_channel_mask_t>(offload.channelMask); + halOffload->format = static_cast<audio_format_t>(offload.format); + halOffload->stream_type = static_cast<audio_stream_type_t>(offload.streamType); + halOffload->bit_rate = offload.bitRatePerSecond; + halOffload->duration_us = offload.durationMicroseconds; + halOffload->has_video = offload.hasVideo; + halOffload->is_streaming = offload.isStreaming; + halOffload->bit_width = offload.bitWidth; + halOffload->offload_buffer_size = offload.bufferSize; + halOffload->usage = static_cast<audio_usage_t>(offload.usage); +} + +void HidlUtils::audioPortConfigFromHal( + const struct audio_port_config& halConfig, AudioPortConfig* config) { + config->id = halConfig.id; + config->role = AudioPortRole(halConfig.role); + config->type = AudioPortType(halConfig.type); + config->configMask = AudioPortConfigMask(halConfig.config_mask); + config->sampleRateHz = halConfig.sample_rate; + config->channelMask = AudioChannelMask(halConfig.channel_mask); + config->format = AudioFormat(halConfig.format); + audioGainConfigFromHal(halConfig.gain, &config->gain); + switch (halConfig.type) { + case AUDIO_PORT_TYPE_NONE: break; + case AUDIO_PORT_TYPE_DEVICE: { + config->ext.device.hwModule = halConfig.ext.device.hw_module; + config->ext.device.type = AudioDevice(halConfig.ext.device.type); + memcpy(config->ext.device.address.data(), + halConfig.ext.device.address, + AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + } + case AUDIO_PORT_TYPE_MIX: { + config->ext.mix.hwModule = halConfig.ext.mix.hw_module; + config->ext.mix.ioHandle = halConfig.ext.mix.handle; + if (halConfig.role == AUDIO_PORT_ROLE_SOURCE) { + config->ext.mix.useCase.source = AudioSource(halConfig.ext.mix.usecase.source); + } else if (halConfig.role == AUDIO_PORT_ROLE_SINK) { + config->ext.mix.useCase.stream = AudioStreamType(halConfig.ext.mix.usecase.stream); + } + break; + } + case AUDIO_PORT_TYPE_SESSION: { + config->ext.session.session = halConfig.ext.session.session; + break; + } + } +} + +void HidlUtils::audioPortConfigToHal( + const AudioPortConfig& config, struct audio_port_config* halConfig) { + memset(halConfig, 0, sizeof(audio_port_config)); + halConfig->id = config.id; + halConfig->role = static_cast<audio_port_role_t>(config.role); + halConfig->type = static_cast<audio_port_type_t>(config.type); + halConfig->config_mask = static_cast<unsigned int>(config.configMask); + halConfig->sample_rate = config.sampleRateHz; + halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask); + halConfig->format = static_cast<audio_format_t>(config.format); + audioGainConfigToHal(config.gain, &halConfig->gain); + switch (config.type) { + case AudioPortType::NONE: break; + case AudioPortType::DEVICE: { + halConfig->ext.device.hw_module = config.ext.device.hwModule; + halConfig->ext.device.type = static_cast<audio_devices_t>(config.ext.device.type); + memcpy(halConfig->ext.device.address, + config.ext.device.address.data(), + AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + } + case AudioPortType::MIX: { + halConfig->ext.mix.hw_module = config.ext.mix.hwModule; + halConfig->ext.mix.handle = config.ext.mix.ioHandle; + if (config.role == AudioPortRole::SOURCE) { + halConfig->ext.mix.usecase.source = + static_cast<audio_source_t>(config.ext.mix.useCase.source); + } else if (config.role == AudioPortRole::SINK) { + halConfig->ext.mix.usecase.stream = + static_cast<audio_stream_type_t>(config.ext.mix.useCase.stream); + } + break; + } + case AudioPortType::SESSION: { + halConfig->ext.session.session = + static_cast<audio_session_t>(config.ext.session.session); + break; + } + } +} + +void HidlUtils::audioPortConfigsFromHal( + unsigned int numHalConfigs, const struct audio_port_config *halConfigs, + hidl_vec<AudioPortConfig> *configs) { + configs->resize(numHalConfigs); + for (unsigned int i = 0; i < numHalConfigs; ++i) { + audioPortConfigFromHal(halConfigs[i], &(*configs)[i]); + } +} + +std::unique_ptr<audio_port_config[]> HidlUtils::audioPortConfigsToHal( + const hidl_vec<AudioPortConfig>& configs) { + std::unique_ptr<audio_port_config[]> halConfigs(new audio_port_config[configs.size()]); + for (size_t i = 0; i < configs.size(); ++i) { + audioPortConfigToHal(configs[i], &halConfigs[i]); + } + return halConfigs; +} + +void HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) { + port->id = halPort.id; + port->role = AudioPortRole(halPort.role); + port->type = AudioPortType(halPort.type); + port->name.setToExternal(halPort.name, strlen(halPort.name)); + port->sampleRates.resize(halPort.num_sample_rates); + for (size_t i = 0; i < halPort.num_sample_rates; ++i) { + port->sampleRates[i] = halPort.sample_rates[i]; + } + port->channelMasks.resize(halPort.num_channel_masks); + for (size_t i = 0; i < halPort.num_channel_masks; ++i) { + port->channelMasks[i] = AudioChannelMask(halPort.channel_masks[i]); + } + port->formats.resize(halPort.num_formats); + for (size_t i = 0; i < halPort.num_formats; ++i) { + port->formats[i] = AudioFormat(halPort.formats[i]); + } + port->gains.resize(halPort.num_gains); + for (size_t i = 0; i < halPort.num_gains; ++i) { + audioGainFromHal(halPort.gains[i], &port->gains[i]); + } + audioPortConfigFromHal(halPort.active_config, &port->activeConfig); + switch (halPort.type) { + case AUDIO_PORT_TYPE_NONE: break; + case AUDIO_PORT_TYPE_DEVICE: { + port->ext.device.hwModule = halPort.ext.device.hw_module; + port->ext.device.type = AudioDevice(halPort.ext.device.type); + memcpy(port->ext.device.address.data(), + halPort.ext.device.address, + AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + } + case AUDIO_PORT_TYPE_MIX: { + port->ext.mix.hwModule = halPort.ext.mix.hw_module; + port->ext.mix.ioHandle = halPort.ext.mix.handle; + port->ext.mix.latencyClass = AudioMixLatencyClass(halPort.ext.mix.latency_class); + break; + } + case AUDIO_PORT_TYPE_SESSION: { + port->ext.session.session = halPort.ext.session.session; + break; + } + } +} + +void HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) { + memset(halPort, 0, sizeof(audio_port)); + halPort->id = port.id; + halPort->role = static_cast<audio_port_role_t>(port.role); + halPort->type = static_cast<audio_port_type_t>(port.type); + memcpy(halPort->name, + port.name.c_str(), + std::min(port.name.size(), static_cast<size_t>(AUDIO_PORT_MAX_NAME_LEN))); + halPort->num_sample_rates = + std::min(port.sampleRates.size(), static_cast<size_t>(AUDIO_PORT_MAX_SAMPLING_RATES)); + for (size_t i = 0; i < halPort->num_sample_rates; ++i) { + halPort->sample_rates[i] = port.sampleRates[i]; + } + halPort->num_channel_masks = + std::min(port.channelMasks.size(), static_cast<size_t>(AUDIO_PORT_MAX_CHANNEL_MASKS)); + for (size_t i = 0; i < halPort->num_channel_masks; ++i) { + halPort->channel_masks[i] = static_cast<audio_channel_mask_t>(port.channelMasks[i]); + } + halPort->num_formats = + std::min(port.formats.size(), static_cast<size_t>(AUDIO_PORT_MAX_FORMATS)); + for (size_t i = 0; i < halPort->num_formats; ++i) { + halPort->formats[i] = static_cast<audio_format_t>(port.formats[i]); + } + halPort->num_gains = std::min(port.gains.size(), static_cast<size_t>(AUDIO_PORT_MAX_GAINS)); + for (size_t i = 0; i < halPort->num_gains; ++i) { + audioGainToHal(port.gains[i], &halPort->gains[i]); + } + audioPortConfigToHal(port.activeConfig, &halPort->active_config); + switch (port.type) { + case AudioPortType::NONE: break; + case AudioPortType::DEVICE: { + halPort->ext.device.hw_module = port.ext.device.hwModule; + halPort->ext.device.type = static_cast<audio_devices_t>(port.ext.device.type); + memcpy(halPort->ext.device.address, + port.ext.device.address.data(), + AUDIO_DEVICE_MAX_ADDRESS_LEN); + break; + } + case AudioPortType::MIX: { + halPort->ext.mix.hw_module = port.ext.mix.hwModule; + halPort->ext.mix.handle = port.ext.mix.ioHandle; + halPort->ext.mix.latency_class = + static_cast<audio_mix_latency_class_t>(port.ext.mix.latencyClass); + break; + } + case AudioPortType::SESSION: { + halPort->ext.session.session = static_cast<audio_session_t>(port.ext.session.session); + break; + } + } +} + +void HidlUtils::uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid) { + uuid->timeLow = halUuid.timeLow; + uuid->timeMid = halUuid.timeMid; + uuid->versionAndTimeHigh = halUuid.timeHiAndVersion; + uuid->variantAndClockSeqHigh = halUuid.clockSeq; + memcpy(uuid->node.data(), halUuid.node, uuid->node.size()); +} + +void HidlUtils::uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid) { + halUuid->timeLow = uuid.timeLow; + halUuid->timeMid = uuid.timeMid; + halUuid->timeHiAndVersion = uuid.versionAndTimeHigh; + halUuid->clockSeq = uuid.variantAndClockSeqHigh; + memcpy(halUuid->node, uuid.node.data(), uuid.node.size()); +} + +} // namespace android
diff --git a/audio/common/2.0/default/HidlUtils.h b/audio/common/2.0/default/HidlUtils.h new file mode 100644 index 0000000..3fde4d7 --- /dev/null +++ b/audio/common/2.0/default/HidlUtils.h
@@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_audio_V2_0_Hidl_Utils_H_ +#define android_hardware_audio_V2_0_Hidl_Utils_H_ + +#include <memory> + +#include <android/hardware/audio/common/2.0/types.h> +#include <system/audio.h> + +using ::android::hardware::audio::common::V2_0::AudioConfig; +using ::android::hardware::audio::common::V2_0::AudioGain; +using ::android::hardware::audio::common::V2_0::AudioGainConfig; +using ::android::hardware::audio::common::V2_0::AudioOffloadInfo; +using ::android::hardware::audio::common::V2_0::AudioPort; +using ::android::hardware::audio::common::V2_0::AudioPortConfig; +using ::android::hardware::audio::common::V2_0::Uuid; +using ::android::hardware::hidl_vec; + +namespace android { + +class HidlUtils { + public: + static void audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config); + static void audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig); + static void audioGainConfigFromHal( + const struct audio_gain_config& halConfig, AudioGainConfig* config); + static void audioGainConfigToHal( + const AudioGainConfig& config, struct audio_gain_config* halConfig); + static void audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain); + static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain); + static void audioOffloadInfoFromHal( + const audio_offload_info_t& halOffload, AudioOffloadInfo* offload); + static void audioOffloadInfoToHal( + const AudioOffloadInfo& offload, audio_offload_info_t* halOffload); + static void audioPortConfigFromHal( + const struct audio_port_config& halConfig, AudioPortConfig* config); + static void audioPortConfigToHal( + const AudioPortConfig& config, struct audio_port_config* halConfig); + static void audioPortConfigsFromHal( + unsigned int numHalConfigs, const struct audio_port_config *halConfigs, + hidl_vec<AudioPortConfig> *configs); + static std::unique_ptr<audio_port_config[]> audioPortConfigsToHal( + const hidl_vec<AudioPortConfig>& configs); + static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port); + static void audioPortToHal(const AudioPort& port, struct audio_port* halPort); + static void uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid); + static void uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid); +}; + +} // namespace android + +#endif // android_hardware_audio_V2_0_Hidl_Utils_H_
diff --git a/audio/common/2.0/types.hal b/audio/common/2.0/types.hal new file mode 100644 index 0000000..93b898b --- /dev/null +++ b/audio/common/2.0/types.hal
@@ -0,0 +1,944 @@ +/* + * Copyright (C) 2016 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.audio.common@2.0; + +/* + * + * IDs and Handles + * + */ + +/* + * Handle type for identifying audio sources and sinks. + */ +typedef int32_t AudioIoHandle; + +/* + * Audio hw module handle functions or structures referencing a module. + */ +typedef int32_t AudioModuleHandle; + +/* + * Each port has a unique ID or handle allocated by policy manager. + */ +typedef int32_t AudioPortHandle; + +/* + * Each patch is identified by a handle at the interface used to create that + * patch. For instance, when a patch is created by the audio HAL, the HAL + * allocates and returns a handle. This handle is unique to a given audio HAL + * hardware module. But the same patch receives another system wide unique + * handle allocated by the framework. This unique handle is used for all + * transactions inside the framework. + */ +typedef int32_t AudioPatchHandle; + +/* + * A HW synchronization source returned by the audio HAL. + */ +typedef uint32_t AudioHwSync; + +/* + * Each port has a unique ID or handle allocated by policy manager. + */ +@export(name="") +enum AudioHandleConsts : int32_t { + AUDIO_IO_HANDLE_NONE = 0, + AUDIO_MODULE_HANDLE_NONE = 0, + AUDIO_PORT_HANDLE_NONE = 0, + AUDIO_PATCH_HANDLE_NONE = 0, +}; + +/* + * Commonly used structure for passing unique identifieds (UUID). + * For the definition of UUID, refer to ITU-T X.667 spec. + */ +struct Uuid { + uint32_t timeLow; + uint16_t timeMid; + uint16_t versionAndTimeHigh; + uint16_t variantAndClockSeqHigh; + uint8_t[6] node; +}; + + +/* + * + * Audio streams + * + */ + +/* + * Audio stream type describing the intented use case of a stream. + */ +@export(name="audio_stream_type_t", value_prefix="AUDIO_STREAM_") +enum AudioStreamType : int32_t { + // These values must kept in sync with + // frameworks/base/media/java/android/media/AudioSystem.java + // TODO: Synchronization should be done automatically by tools + DEFAULT = -1, + MIN = 0, + VOICE_CALL = 0, + SYSTEM = 1, + RING = 2, + MUSIC = 3, + ALARM = 4, + NOTIFICATION = 5, + BLUETOOTH_SCO = 6, + ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be + // routed to speaker + DTMF = 8, + TTS = 9, // Transmitted Through Speaker. Plays over speaker + // only, silent on other devices + ACCESSIBILITY = 10, // For accessibility talk back prompts + REROUTING = 11, // For dynamic policy output mixes + PATCH = 12, // For internal audio flinger tracks. Fixed volume + PUBLIC_CNT = ACCESSIBILITY + 1, + // Number of streams considered by audio policy for volume and routing + FOR_POLICY_CNT = PATCH, + CNT = PATCH + 1 +}; + +@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_") +enum AudioSource : int32_t { + // These values must kept in sync with + // frameworks/base/media/java/android/media/MediaRecorder.java, + // frameworks/av/services/audiopolicy/AudioPolicyService.cpp, + // system/media/audio_effects/include/audio_effects/audio_effects_conf.h + DEFAULT = 0, + MIC = 1, + VOICE_UPLINK = 2, + VOICE_DOWNLINK = 3, + VOICE_CALL = 4, + CAMCORDER = 5, + VOICE_RECOGNITION = 6, + VOICE_COMMUNICATION = 7, + /* + * Source for the mix to be presented remotely. An example of remote + * presentation is Wifi Display where a dongle attached to a TV can be used + * to play the mix captured by this audio source. + */ + REMOTE_SUBMIX = 8, + /* + * Source for unprocessed sound. Usage examples include level measurement + * and raw signal analysis. + */ + UNPROCESSED = 9, + + CNT, + MAX = CNT - 1, + FM_TUNER = 1998, + /* + * A low-priority, preemptible audio source for for background software + * hotword detection. Same tuning as VOICE_RECOGNITION. Used only + * internally by the framework. + */ + HOTWORD = 1999 +}; + +typedef int32_t AudioSession; +/* + * Special audio session values. + */ +@export(name="audio_session_t", value_prefix="AUDIO_SESSION_") +enum AudioSessionConsts : int32_t { + /* + * Session for effects attached to a particular output stream + * (value must be less than 0) + */ + OUTPUT_STAGE = -1, + /* + * Session for effects applied to output mix. These effects can + * be moved by audio policy manager to another output stream + * (value must be 0) + */ + OUTPUT_MIX = 0, + /* + * Application does not specify an explicit session ID to be used, and + * requests a new session ID to be allocated TODO use unique values for + * AUDIO_SESSION_OUTPUT_MIX and AUDIO_SESSION_ALLOCATE, after all uses have + * been updated from 0 to the appropriate symbol, and have been tested. + * Corresponds to AudioManager.AUDIO_SESSION_ID_GENERATE and + * AudioSystem.AUDIO_SESSION_ALLOCATE. + */ + ALLOCATE = 0, + /* + * For use with AudioRecord::start(), this indicates no trigger session. + * It is also used with output tracks and patch tracks, which never have a + * session. + */ + NONE = 0 +}; + +/* + * Audio format is a 32-bit word that consists of: + * main format field (upper 8 bits) + * sub format field (lower 24 bits). + * + * The main format indicates the main codec type. The sub format field indicates + * options and parameters for each format. The sub format is mainly used for + * record to indicate for instance the requested bitrate or profile. It can + * also be used for certain formats to give informations not present in the + * encoded audio stream (e.g. octet alignement for AMR). + */ +@export(name="audio_format_t", value_prefix="AUDIO_FORMAT_") +enum AudioFormat : uint32_t { + INVALID = 0xFFFFFFFFUL, + DEFAULT = 0, + PCM = 0x00000000UL, /* DO NOT CHANGE */ + MP3 = 0x01000000UL, + AMR_NB = 0x02000000UL, + AMR_WB = 0x03000000UL, + AAC = 0x04000000UL, + HE_AAC_V1 = 0x05000000UL, /* Deprecated, Use AAC_HE_V1*/ + HE_AAC_V2 = 0x06000000UL, /* Deprecated, Use AAC_HE_V2*/ + VORBIS = 0x07000000UL, + OPUS = 0x08000000UL, + AC3 = 0x09000000UL, + E_AC3 = 0x0A000000UL, + DTS = 0x0B000000UL, + DTS_HD = 0x0C000000UL, + // IEC61937 is encoded audio wrapped in 16-bit PCM. + IEC61937 = 0x0D000000UL, + DOLBY_TRUEHD = 0x0E000000UL, + EVRC = 0x10000000UL, + EVRCB = 0x11000000UL, + EVRCWB = 0x12000000UL, + EVRCNW = 0x13000000UL, + AAC_ADIF = 0x14000000UL, + WMA = 0x15000000UL, + WMA_PRO = 0x16000000UL, + AMR_WB_PLUS = 0x17000000UL, + MP2 = 0x18000000UL, + QCELP = 0x19000000UL, + DSD = 0x1A000000UL, + FLAC = 0x1B000000UL, + ALAC = 0x1C000000UL, + APE = 0x1D000000UL, + AAC_ADTS = 0x1E000000UL, + SBC = 0x1F000000UL, + APTX = 0x20000000UL, + APTX_HD = 0x21000000UL, + AC4 = 0x22000000UL, + LDAC = 0x23000000UL, + MAIN_MASK = 0xFF000000UL, /* Deprecated */ + SUB_MASK = 0x00FFFFFFUL, + + /* Subformats */ + PCM_SUB_16_BIT = 0x1, // PCM signed 16 bits + PCM_SUB_8_BIT = 0x2, // PCM unsigned 8 bits + PCM_SUB_32_BIT = 0x3, // PCM signed .31 fixed point + PCM_SUB_8_24_BIT = 0x4, // PCM signed 8.23 fixed point + PCM_SUB_FLOAT = 0x5, // PCM single-precision float pt + PCM_SUB_24_BIT_PACKED = 0x6, // PCM signed .23 fix pt (3 bytes) + + MP3_SUB_NONE = 0x0, + + AMR_SUB_NONE = 0x0, + + AAC_SUB_MAIN = 0x1, + AAC_SUB_LC = 0x2, + AAC_SUB_SSR = 0x4, + AAC_SUB_LTP = 0x8, + AAC_SUB_HE_V1 = 0x10, + AAC_SUB_SCALABLE = 0x20, + AAC_SUB_ERLC = 0x40, + AAC_SUB_LD = 0x80, + AAC_SUB_HE_V2 = 0x100, + AAC_SUB_ELD = 0x200, + + VORBIS_SUB_NONE = 0x0, + + /* Aliases */ + /* note != AudioFormat.ENCODING_PCM_16BIT */ + PCM_16_BIT = (PCM | PCM_SUB_16_BIT), + /* note != AudioFormat.ENCODING_PCM_8BIT */ + PCM_8_BIT = (PCM | PCM_SUB_8_BIT), + PCM_32_BIT = (PCM | PCM_SUB_32_BIT), + PCM_8_24_BIT = (PCM | PCM_SUB_8_24_BIT), + PCM_FLOAT = (PCM | PCM_SUB_FLOAT), + PCM_24_BIT_PACKED = (PCM | PCM_SUB_24_BIT_PACKED), + AAC_MAIN = (AAC | AAC_SUB_MAIN), + AAC_LC = (AAC | AAC_SUB_LC), + AAC_SSR = (AAC | AAC_SUB_SSR), + AAC_LTP = (AAC | AAC_SUB_LTP), + AAC_HE_V1 = (AAC | AAC_SUB_HE_V1), + AAC_SCALABLE = (AAC | AAC_SUB_SCALABLE), + AAC_ERLC = (AAC | AAC_SUB_ERLC), + AAC_LD = (AAC | AAC_SUB_LD), + AAC_HE_V2 = (AAC | AAC_SUB_HE_V2), + AAC_ELD = (AAC | AAC_SUB_ELD), + AAC_ADTS_MAIN = (AAC_ADTS | AAC_SUB_MAIN), + AAC_ADTS_LC = (AAC_ADTS | AAC_SUB_LC), + AAC_ADTS_SSR = (AAC_ADTS | AAC_SUB_SSR), + AAC_ADTS_LTP = (AAC_ADTS | AAC_SUB_LTP), + AAC_ADTS_HE_V1 = (AAC_ADTS | AAC_SUB_HE_V1), + AAC_ADTS_SCALABLE = (AAC_ADTS | AAC_SUB_SCALABLE), + AAC_ADTS_ERLC = (AAC_ADTS | AAC_SUB_ERLC), + AAC_ADTS_LD = (AAC_ADTS | AAC_SUB_LD), + AAC_ADTS_HE_V2 = (AAC_ADTS | AAC_SUB_HE_V2), + AAC_ADTS_ELD = (AAC_ADTS | AAC_SUB_ELD) +}; + +/* + * Usage of these values highlights places in the code that use 2- or 8- channel + * assumptions. + */ +@export(name="") +enum FixedChannelCount : int32_t { + FCC_2 = 2, // This is typically due to legacy implementation of stereo I/O + FCC_8 = 8 // This is typically due to audio mixer and resampler limitations +}; + +/* + * A channel mask per se only defines the presence or absence of a channel, not + * the order. See AUDIO_INTERLEAVE_* for the platform convention of order. + * + * AudioChannelMask is an opaque type and its internal layout should not be + * assumed as it may change in the future. Instead, always use functions + * to examine it. + * + * These are the current representations: + * + * REPRESENTATION_POSITION + * is a channel mask representation for position assignment. Each low-order + * bit corresponds to the spatial position of a transducer (output), or + * interpretation of channel (input). The user of a channel mask needs to + * know the context of whether it is for output or input. The constants + * OUT_* or IN_* apply to the bits portion. It is not permitted for no bits + * to be set. + * + * REPRESENTATION_INDEX + * is a channel mask representation for index assignment. Each low-order + * bit corresponds to a selected channel. There is no platform + * interpretation of the various bits. There is no concept of output or + * input. It is not permitted for no bits to be set. + * + * All other representations are reserved for future use. + * + * Warning: current representation distinguishes between input and output, but + * this will not the be case in future revisions of the platform. Wherever there + * is an ambiguity between input and output that is currently resolved by + * checking the channel mask, the implementer should look for ways to fix it + * with additional information outside of the mask. + */ +@export(name="", value_prefix="AUDIO_CHANNEL_") +enum AudioChannelMask : uint32_t { + REPRESENTATION_POSITION = 0, /* must be 0 for compatibility */ + /* 1 is reserved for future use */ + REPRESENTATION_INDEX = 2, + /* 3 is reserved for future use */ + + /* These can be a complete value of AudioChannelMask */ + NONE = 0x0, + INVALID = 0xC0000000, + + /* + * These can be the bits portion of an AudioChannelMask + * with representation REPRESENTATION_POSITION. + */ + + /* output channels */ + OUT_FRONT_LEFT = 0x1, + OUT_FRONT_RIGHT = 0x2, + OUT_FRONT_CENTER = 0x4, + OUT_LOW_FREQUENCY = 0x8, + OUT_BACK_LEFT = 0x10, + OUT_BACK_RIGHT = 0x20, + OUT_FRONT_LEFT_OF_CENTER = 0x40, + OUT_FRONT_RIGHT_OF_CENTER = 0x80, + OUT_BACK_CENTER = 0x100, + OUT_SIDE_LEFT = 0x200, + OUT_SIDE_RIGHT = 0x400, + OUT_TOP_CENTER = 0x800, + OUT_TOP_FRONT_LEFT = 0x1000, + OUT_TOP_FRONT_CENTER = 0x2000, + OUT_TOP_FRONT_RIGHT = 0x4000, + OUT_TOP_BACK_LEFT = 0x8000, + OUT_TOP_BACK_CENTER = 0x10000, + OUT_TOP_BACK_RIGHT = 0x20000, + + OUT_MONO = OUT_FRONT_LEFT, + OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT), + OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY), + OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_BACK_LEFT | OUT_BACK_RIGHT), + OUT_QUAD_BACK = OUT_QUAD, + /* like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */ + OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_SIDE_LEFT | OUT_SIDE_RIGHT), + OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_BACK_CENTER), + OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER), + OUT_5POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | + OUT_BACK_LEFT | OUT_BACK_RIGHT), + OUT_5POINT1_BACK = OUT_5POINT1, + /* like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */ + OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | + OUT_SIDE_LEFT | OUT_SIDE_RIGHT), + OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | + OUT_BACK_LEFT | OUT_BACK_RIGHT | + OUT_BACK_CENTER), + /* matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND */ + OUT_7POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | + OUT_BACK_LEFT | OUT_BACK_RIGHT | + OUT_SIDE_LEFT | OUT_SIDE_RIGHT), + OUT_ALL = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | + OUT_FRONT_CENTER | OUT_LOW_FREQUENCY | + OUT_BACK_LEFT | OUT_BACK_RIGHT | + OUT_FRONT_LEFT_OF_CENTER | OUT_FRONT_RIGHT_OF_CENTER | + OUT_BACK_CENTER | + OUT_SIDE_LEFT | OUT_SIDE_RIGHT | + OUT_TOP_CENTER | + OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_CENTER | OUT_TOP_FRONT_RIGHT | + OUT_TOP_BACK_LEFT | OUT_TOP_BACK_CENTER | OUT_TOP_BACK_RIGHT), + + /* These are bits only, not complete values */ + + /* input channels */ + IN_LEFT = 0x4, + IN_RIGHT = 0x8, + IN_FRONT = 0x10, + IN_BACK = 0x20, + IN_LEFT_PROCESSED = 0x40, + IN_RIGHT_PROCESSED = 0x80, + IN_FRONT_PROCESSED = 0x100, + IN_BACK_PROCESSED = 0x200, + IN_PRESSURE = 0x400, + IN_X_AXIS = 0x800, + IN_Y_AXIS = 0x1000, + IN_Z_AXIS = 0x2000, + IN_VOICE_UPLINK = 0x4000, + IN_VOICE_DNLINK = 0x8000, + + IN_MONO = IN_FRONT, + IN_STEREO = (IN_LEFT | IN_RIGHT), + IN_FRONT_BACK = (IN_FRONT | IN_BACK), + IN_6 = (IN_LEFT | IN_RIGHT | + IN_FRONT | IN_BACK | + IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED), + IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO), + IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO), + IN_VOICE_CALL_MONO = (IN_VOICE_UPLINK_MONO | + IN_VOICE_DNLINK_MONO), + IN_ALL = (IN_LEFT | IN_RIGHT | IN_FRONT | IN_BACK| + IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED | + IN_FRONT_PROCESSED | IN_BACK_PROCESSED| + IN_PRESSURE | + IN_X_AXIS | IN_Y_AXIS | IN_Z_AXIS | + IN_VOICE_UPLINK | IN_VOICE_DNLINK), + + COUNT_MAX = 30, + INDEX_HDR = REPRESENTATION_INDEX << COUNT_MAX, + INDEX_MASK_1 = INDEX_HDR | ((1 << 1) - 1), + INDEX_MASK_2 = INDEX_HDR | ((1 << 2) - 1), + INDEX_MASK_3 = INDEX_HDR | ((1 << 3) - 1), + INDEX_MASK_4 = INDEX_HDR | ((1 << 4) - 1), + INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1), + INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1), + INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1), + INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1) +}; + + +/* + * Expresses the convention when stereo audio samples are stored interleaved + * in an array. This should improve readability by allowing code to use + * symbolic indices instead of hard-coded [0] and [1]. + * + * For multi-channel beyond stereo, the platform convention is that channels + * are interleaved in order from least significant channel mask bit to most + * significant channel mask bit, with unused bits skipped. Any exceptions + * to this convention will be noted at the appropriate API. + */ +@export(name="", value_prefix="AUDIO_INTERLEAVE_") +enum AudioInterleave : int32_t { + LEFT = 0, + RIGHT = 1, +}; + +/* + * Major modes for a mobile device. The current mode setting affects audio + * routing. + */ +@export(name="audio_mode_t", value_prefix="AUDIO_MODE_") +enum AudioMode : int32_t { + INVALID = -2, + CURRENT = -1, + NORMAL = 0, + RINGTONE = 1, + IN_CALL = 2, + IN_COMMUNICATION = 3, + + CNT, + MAX = CNT - 1, +}; + +@export(name="", value_prefix="AUDIO_DEVICE_") +enum AudioDevice : uint32_t { + NONE = 0x0, + /* reserved bits */ + BIT_IN = 0x80000000, + BIT_DEFAULT = 0x40000000, + /* output devices */ + OUT_EARPIECE = 0x1, + OUT_SPEAKER = 0x2, + OUT_WIRED_HEADSET = 0x4, + OUT_WIRED_HEADPHONE = 0x8, + OUT_BLUETOOTH_SCO = 0x10, + OUT_BLUETOOTH_SCO_HEADSET = 0x20, + OUT_BLUETOOTH_SCO_CARKIT = 0x40, + OUT_BLUETOOTH_A2DP = 0x80, + OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, + OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, + OUT_AUX_DIGITAL = 0x400, + OUT_HDMI = OUT_AUX_DIGITAL, + /* uses an analog connection (multiplexed over the USB pins for instance) */ + OUT_ANLG_DOCK_HEADSET = 0x800, + OUT_DGTL_DOCK_HEADSET = 0x1000, + /* USB accessory mode: Android device is USB device and dock is USB host */ + OUT_USB_ACCESSORY = 0x2000, + /* USB host mode: Android device is USB host and dock is USB device */ + OUT_USB_DEVICE = 0x4000, + OUT_REMOTE_SUBMIX = 0x8000, + /* Telephony voice TX path */ + OUT_TELEPHONY_TX = 0x10000, + /* Analog jack with line impedance detected */ + OUT_LINE = 0x20000, + /* HDMI Audio Return Channel */ + OUT_HDMI_ARC = 0x40000, + /* S/PDIF out */ + OUT_SPDIF = 0x80000, + /* FM transmitter out */ + OUT_FM = 0x100000, + /* Line out for av devices */ + OUT_AUX_LINE = 0x200000, + /* limited-output speaker device for acoustic safety */ + OUT_SPEAKER_SAFE = 0x400000, + OUT_IP = 0x800000, + /* audio bus implemented by the audio system (e.g an MOST stereo channel) */ + OUT_BUS = 0x1000000, + OUT_PROXY = 0x2000000, + OUT_USB_HEADSET = 0x4000000, + OUT_DEFAULT = BIT_DEFAULT, + OUT_ALL = (OUT_EARPIECE | + OUT_SPEAKER | + OUT_WIRED_HEADSET | + OUT_WIRED_HEADPHONE | + OUT_BLUETOOTH_SCO | + OUT_BLUETOOTH_SCO_HEADSET | + OUT_BLUETOOTH_SCO_CARKIT | + OUT_BLUETOOTH_A2DP | + OUT_BLUETOOTH_A2DP_HEADPHONES | + OUT_BLUETOOTH_A2DP_SPEAKER | + OUT_HDMI | + OUT_ANLG_DOCK_HEADSET | + OUT_DGTL_DOCK_HEADSET | + OUT_USB_ACCESSORY | + OUT_USB_DEVICE | + OUT_REMOTE_SUBMIX | + OUT_TELEPHONY_TX | + OUT_LINE | + OUT_HDMI_ARC | + OUT_SPDIF | + OUT_FM | + OUT_AUX_LINE | + OUT_SPEAKER_SAFE | + OUT_IP | + OUT_BUS | + OUT_PROXY | + OUT_DEFAULT), + OUT_ALL_A2DP = (OUT_BLUETOOTH_A2DP | + OUT_BLUETOOTH_A2DP_HEADPHONES | + OUT_BLUETOOTH_A2DP_SPEAKER), + OUT_ALL_SCO = (OUT_BLUETOOTH_SCO | + OUT_BLUETOOTH_SCO_HEADSET | + OUT_BLUETOOTH_SCO_CARKIT), + OUT_ALL_USB = (OUT_USB_ACCESSORY | OUT_USB_DEVICE), + /* input devices */ + IN_COMMUNICATION = BIT_IN | 0x1, + IN_AMBIENT = BIT_IN | 0x2, + IN_BUILTIN_MIC = BIT_IN | 0x4, + IN_BLUETOOTH_SCO_HEADSET = BIT_IN | 0x8, + IN_WIRED_HEADSET = BIT_IN | 0x10, + IN_AUX_DIGITAL = BIT_IN | 0x20, + IN_HDMI = IN_AUX_DIGITAL, + /* Telephony voice RX path */ + IN_VOICE_CALL = BIT_IN | 0x40, + IN_TELEPHONY_RX = IN_VOICE_CALL, + IN_BACK_MIC = BIT_IN | 0x80, + IN_REMOTE_SUBMIX = BIT_IN | 0x100, + IN_ANLG_DOCK_HEADSET = BIT_IN | 0x200, + IN_DGTL_DOCK_HEADSET = BIT_IN | 0x400, + IN_USB_ACCESSORY = BIT_IN | 0x800, + IN_USB_DEVICE = BIT_IN | 0x1000, + /* FM tuner input */ + IN_FM_TUNER = BIT_IN | 0x2000, + /* TV tuner input */ + IN_TV_TUNER = BIT_IN | 0x4000, + /* Analog jack with line impedance detected */ + IN_LINE = BIT_IN | 0x8000, + /* S/PDIF in */ + IN_SPDIF = BIT_IN | 0x10000, + IN_BLUETOOTH_A2DP = BIT_IN | 0x20000, + IN_LOOPBACK = BIT_IN | 0x40000, + IN_IP = BIT_IN | 0x80000, + /* audio bus implemented by the audio system (e.g an MOST stereo channel) */ + IN_BUS = BIT_IN | 0x100000, + IN_PROXY = BIT_IN | 0x1000000, + IN_USB_HEADSET = BIT_IN | 0x2000000, + IN_DEFAULT = BIT_IN | BIT_DEFAULT, + + IN_ALL = (IN_COMMUNICATION | + IN_AMBIENT | + IN_BUILTIN_MIC | + IN_BLUETOOTH_SCO_HEADSET | + IN_WIRED_HEADSET | + IN_HDMI | + IN_TELEPHONY_RX | + IN_BACK_MIC | + IN_REMOTE_SUBMIX | + IN_ANLG_DOCK_HEADSET | + IN_DGTL_DOCK_HEADSET | + IN_USB_ACCESSORY | + IN_USB_DEVICE | + IN_FM_TUNER | + IN_TV_TUNER | + IN_LINE | + IN_SPDIF | + IN_BLUETOOTH_A2DP | + IN_LOOPBACK | + IN_IP | + IN_BUS | + IN_PROXY | + IN_DEFAULT), + IN_ALL_SCO = IN_BLUETOOTH_SCO_HEADSET, + IN_ALL_USB = (IN_USB_ACCESSORY | IN_USB_DEVICE), +}; + +/* + * The audio output flags serve two purposes: + * + * - when an AudioTrack is created they indicate a "wish" to be connected to an + * output stream with attributes corresponding to the specified flags; + * + * - when present in an output profile descriptor listed for a particular audio + * hardware module, they indicate that an output stream can be opened that + * supports the attributes indicated by the flags. + * + * The audio policy manager will try to match the flags in the request + * (when getOuput() is called) to an available output stream. + */ +@export(name="audio_output_flags_t", value_prefix="AUDIO_OUTPUT_FLAG_") +enum AudioOutputFlag : int32_t { + NONE = 0x0, // no attributes + DIRECT = 0x1, // this output directly connects a track + // to one output stream: no software mixer + PRIMARY = 0x2, // this output is the primary output of the device. It is + // unique and must be present. It is opened by default and + // receives routing, audio mode and volume controls related + // to voice calls. + FAST = 0x4, // output supports "fast tracks", defined elsewhere + DEEP_BUFFER = 0x8, // use deep audio buffers + COMPRESS_OFFLOAD = 0x10, // offload playback of compressed streams to + // hardware codec + NON_BLOCKING = 0x20, // use non-blocking write + HW_AV_SYNC = 0x40, // output uses a hardware A/V sync + TTS = 0x80, // output for streams transmitted through speaker at a + // sample rate high enough to accommodate lower-range + // ultrasonic p/b + RAW = 0x100, // minimize signal processing + SYNC = 0x200, // synchronize I/O streams + IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in SPDIF + // data bursts, not PCM. + DIRECT_PCM = 0x2000, // Audio stream containing PCM data that needs + // to pass through compress path for DSP post proc. + MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode. + VOIP_CALL_RX = 0x8000, // preferred output for VoIP calls. +}; + +/* + * The audio input flags are analogous to audio output flags. + * Currently they are used only when an AudioRecord is created, + * to indicate a preference to be connected to an input stream with + * attributes corresponding to the specified flags. + */ +@export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_") +enum AudioInputFlag : int32_t { + NONE = 0x0, // no attributes + FAST = 0x1, // prefer an input that supports "fast tracks" + HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source + RAW = 0x4, // minimize signal processing + SYNC = 0x8, // synchronize I/O streams + MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode. + VOIP_CALL_TX = 0x20, // preferred input for VoIP calls. +}; + +@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_") +enum AudioUsage : int32_t { + // These values must kept in sync with + // frameworks/base/media/java/android/media/AudioAttributes.java + // TODO: Synchronization should be done automatically by tools + UNKNOWN = 0, + MEDIA = 1, + VOICE_COMMUNICATION = 2, + VOICE_COMMUNICATION_SIGNALLING = 3, + ALARM = 4, + NOTIFICATION = 5, + NOTIFICATION_TELEPHONY_RINGTONE = 6, + NOTIFICATION_COMMUNICATION_REQUEST = 7, + NOTIFICATION_COMMUNICATION_INSTANT = 8, + NOTIFICATION_COMMUNICATION_DELAYED = 9, + NOTIFICATION_EVENT = 10, + ASSISTANCE_ACCESSIBILITY = 11, + ASSISTANCE_NAVIGATION_GUIDANCE = 12, + ASSISTANCE_SONIFICATION = 13, + GAME = 14, + VIRTUAL_SOURCE = 15, + ASSISTANT = 16, + + CNT, + MAX = CNT - 1, +}; + +/* + * Additional information about the stream passed to hardware decoders. + */ +struct AudioOffloadInfo { + uint32_t sampleRateHz; + AudioChannelMask channelMask; + AudioFormat format; + AudioStreamType streamType; + uint32_t bitRatePerSecond; + int64_t durationMicroseconds; // -1 if unknown + bool hasVideo; + bool isStreaming; + uint32_t bitWidth; + uint32_t bufferSize; + AudioUsage usage; +}; + +/* + * Commonly used audio stream configuration parameters. + */ +struct AudioConfig { + uint32_t sampleRateHz; + AudioChannelMask channelMask; + AudioFormat format; + AudioOffloadInfo offloadInfo; + uint64_t frameCount; +}; + + +/* + * + * Volume control + * + */ + +/* + * Type of gain control exposed by an audio port. + */ +@export(name="", value_prefix="AUDIO_GAIN_MODE_") +enum AudioGainMode : uint32_t { + JOINT = 0x1, // supports joint channel gain control + CHANNELS = 0x2, // supports separate channel gain control + RAMP = 0x4 // supports gain ramps +}; + +/* + * An audio_gain struct is a representation of a gain stage. + * A gain stage is always attached to an audio port. + */ +struct AudioGain { + AudioGainMode mode; + AudioChannelMask channelMask; // channels which gain an be controlled + int32_t minValue; // minimum gain value in millibels + int32_t maxValue; // maximum gain value in millibels + int32_t defaultValue; // default gain value in millibels + uint32_t stepValue; // gain step in millibels + uint32_t minRampMs; // minimum ramp duration in ms + uint32_t maxRampMs; // maximum ramp duration in ms +}; + +/* + * The gain configuration structure is used to get or set the gain values of a + * given port. + */ +struct AudioGainConfig { + int32_t index; // index of the corresponding AudioGain in AudioPort.gains + AudioGainMode mode; + AudioChannelMask channelMask; // channels which gain value follows + /* + * 4 = sizeof(AudioChannelMask), + * 8 is not "FCC_8", so it won't need to be changed for > 8 channels. + * Gain values in millibels for each channel ordered from LSb to MSb in + * channel mask. The number of values is 1 in joint mode or + * popcount(channel_mask). + */ + int32_t[4 * 8] values; + uint32_t rampDurationMs; // ramp duration in ms +}; + + +/* + * + * Routing control + * + */ + +/* + * Types defined here are used to describe an audio source or sink at internal + * framework interfaces (audio policy, patch panel) or at the audio HAL. + * Sink and sources are grouped in a concept of “audio port” representing an + * audio end point at the edge of the system managed by the module exposing + * the interface. + */ + +/* Audio port role: either source or sink */ +@export(name="audio_port_role_t", value_prefix="AUDIO_PORT_ROLE_") +enum AudioPortRole : int32_t { + NONE, + SOURCE, + SINK, +}; + +/* + * Audio port type indicates if it is a session (e.g AudioTrack), a mix (e.g + * PlaybackThread output) or a physical device (e.g OUT_SPEAKER) + */ +@export(name="audio_port_type_t", value_prefix="AUDIO_PORT_TYPE_") +enum AudioPortType : int32_t { + NONE, + DEVICE, + MIX, + SESSION, +}; + +/* + * Extension for audio port configuration structure when the audio port is a + * hardware device. + */ +struct AudioPortConfigDeviceExt { + AudioModuleHandle hwModule; // module the device is attached to + AudioDevice type; // device type (e.g OUT_SPEAKER) + uint8_t[32] address; // device address. "" if N/A +}; + +/* + * Extension for audio port configuration structure when the audio port is an + * audio session. + */ +struct AudioPortConfigSessionExt { + AudioSession session; +}; + +/* + * Flags indicating which fields are to be considered in AudioPortConfig. + */ +@export(name="", value_prefix="AUDIO_PORT_CONFIG_") +enum AudioPortConfigMask : uint32_t { + SAMPLE_RATE = 0x1, + CHANNEL_MASK = 0x2, + FORMAT = 0x4, + GAIN = 0x8, + ALL = SAMPLE_RATE | CHANNEL_MASK | FORMAT | GAIN +}; + +/* + * Audio port configuration structure used to specify a particular configuration + * of an audio port. + */ +struct AudioPortConfig { + AudioPortHandle id; + AudioPortConfigMask configMask; + uint32_t sampleRateHz; + AudioChannelMask channelMask; + AudioFormat format; + AudioGainConfig gain; + AudioPortType type; // type is used as a discriminator for Ext union + AudioPortRole role; // role is used as a discriminator for UseCase union + union Ext { + AudioPortConfigDeviceExt device; + struct AudioPortConfigMixExt { + AudioModuleHandle hwModule; // module the stream is attached to + AudioIoHandle ioHandle; // I/O handle of the input/output stream + union UseCase { + AudioStreamType stream; + AudioSource source; + } useCase; + } mix; + AudioPortConfigSessionExt session; + } ext; +}; + +/* + * Extension for audio port structure when the audio port is a hardware device. + */ +struct AudioPortDeviceExt { + AudioModuleHandle hwModule; // module the device is attached to + AudioDevice type; + uint8_t[32] address; +}; + +/* + * Latency class of the audio mix. + */ +@export(name="audio_mix_latency_class_t", value_prefix="AUDIO_LATENCY_") +enum AudioMixLatencyClass : int32_t { + LOW, + NORMAL +} ; + +struct AudioPortMixExt { + AudioModuleHandle hwModule; // module the stream is attached to + AudioIoHandle ioHandle; // I/O handle of the stream + AudioMixLatencyClass latencyClass; +}; + +/* + * Extension for audio port structure when the audio port is an audio session. + */ +struct AudioPortSessionExt { + AudioSession session; +}; + +struct AudioPort { + AudioPortHandle id; + AudioPortRole role; + string name; + vec<uint32_t> sampleRates; + vec<AudioChannelMask> channelMasks; + vec<AudioFormat> formats; + vec<AudioGain> gains; + AudioPortConfig activeConfig; // current audio port configuration + AudioPortType type; // type is used as a discriminator + union Ext { + AudioPortDeviceExt device; + AudioPortMixExt mix; + AudioPortSessionExt session; + } ext; +}; + +struct ThreadInfo { + int64_t pid; + int64_t tid; +};
diff --git a/audio/common/Android.mk b/audio/common/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/audio/common/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/audio/effect/2.0/Android.bp b/audio/effect/2.0/Android.bp new file mode 100644 index 0000000..83a702a --- /dev/null +++ b/audio/effect/2.0/Android.bp
@@ -0,0 +1,155 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.audio.effect@2.0_hal", + srcs: [ + "types.hal", + "IAcousticEchoCancelerEffect.hal", + "IAutomaticGainControlEffect.hal", + "IBassBoostEffect.hal", + "IDownmixEffect.hal", + "IEffect.hal", + "IEffectBufferProviderCallback.hal", + "IEffectsFactory.hal", + "IEnvironmentalReverbEffect.hal", + "IEqualizerEffect.hal", + "ILoudnessEnhancerEffect.hal", + "INoiseSuppressionEffect.hal", + "IPresetReverbEffect.hal", + "IVirtualizerEffect.hal", + "IVisualizerEffect.hal", + ], +} + +genrule { + name: "android.hardware.audio.effect@2.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio.effect@2.0", + srcs: [ + ":android.hardware.audio.effect@2.0_hal", + ], + out: [ + "android/hardware/audio/effect/2.0/types.cpp", + "android/hardware/audio/effect/2.0/AcousticEchoCancelerEffectAll.cpp", + "android/hardware/audio/effect/2.0/AutomaticGainControlEffectAll.cpp", + "android/hardware/audio/effect/2.0/BassBoostEffectAll.cpp", + "android/hardware/audio/effect/2.0/DownmixEffectAll.cpp", + "android/hardware/audio/effect/2.0/EffectAll.cpp", + "android/hardware/audio/effect/2.0/EffectBufferProviderCallbackAll.cpp", + "android/hardware/audio/effect/2.0/EffectsFactoryAll.cpp", + "android/hardware/audio/effect/2.0/EnvironmentalReverbEffectAll.cpp", + "android/hardware/audio/effect/2.0/EqualizerEffectAll.cpp", + "android/hardware/audio/effect/2.0/LoudnessEnhancerEffectAll.cpp", + "android/hardware/audio/effect/2.0/NoiseSuppressionEffectAll.cpp", + "android/hardware/audio/effect/2.0/PresetReverbEffectAll.cpp", + "android/hardware/audio/effect/2.0/VirtualizerEffectAll.cpp", + "android/hardware/audio/effect/2.0/VisualizerEffectAll.cpp", + ], +} + +genrule { + name: "android.hardware.audio.effect@2.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.audio.effect@2.0", + srcs: [ + ":android.hardware.audio.effect@2.0_hal", + ], + out: [ + "android/hardware/audio/effect/2.0/types.h", + "android/hardware/audio/effect/2.0/IAcousticEchoCancelerEffect.h", + "android/hardware/audio/effect/2.0/IHwAcousticEchoCancelerEffect.h", + "android/hardware/audio/effect/2.0/BnHwAcousticEchoCancelerEffect.h", + "android/hardware/audio/effect/2.0/BpHwAcousticEchoCancelerEffect.h", + "android/hardware/audio/effect/2.0/BsAcousticEchoCancelerEffect.h", + "android/hardware/audio/effect/2.0/IAutomaticGainControlEffect.h", + "android/hardware/audio/effect/2.0/IHwAutomaticGainControlEffect.h", + "android/hardware/audio/effect/2.0/BnHwAutomaticGainControlEffect.h", + "android/hardware/audio/effect/2.0/BpHwAutomaticGainControlEffect.h", + "android/hardware/audio/effect/2.0/BsAutomaticGainControlEffect.h", + "android/hardware/audio/effect/2.0/IBassBoostEffect.h", + "android/hardware/audio/effect/2.0/IHwBassBoostEffect.h", + "android/hardware/audio/effect/2.0/BnHwBassBoostEffect.h", + "android/hardware/audio/effect/2.0/BpHwBassBoostEffect.h", + "android/hardware/audio/effect/2.0/BsBassBoostEffect.h", + "android/hardware/audio/effect/2.0/IDownmixEffect.h", + "android/hardware/audio/effect/2.0/IHwDownmixEffect.h", + "android/hardware/audio/effect/2.0/BnHwDownmixEffect.h", + "android/hardware/audio/effect/2.0/BpHwDownmixEffect.h", + "android/hardware/audio/effect/2.0/BsDownmixEffect.h", + "android/hardware/audio/effect/2.0/IEffect.h", + "android/hardware/audio/effect/2.0/IHwEffect.h", + "android/hardware/audio/effect/2.0/BnHwEffect.h", + "android/hardware/audio/effect/2.0/BpHwEffect.h", + "android/hardware/audio/effect/2.0/BsEffect.h", + "android/hardware/audio/effect/2.0/IEffectBufferProviderCallback.h", + "android/hardware/audio/effect/2.0/IHwEffectBufferProviderCallback.h", + "android/hardware/audio/effect/2.0/BnHwEffectBufferProviderCallback.h", + "android/hardware/audio/effect/2.0/BpHwEffectBufferProviderCallback.h", + "android/hardware/audio/effect/2.0/BsEffectBufferProviderCallback.h", + "android/hardware/audio/effect/2.0/IEffectsFactory.h", + "android/hardware/audio/effect/2.0/IHwEffectsFactory.h", + "android/hardware/audio/effect/2.0/BnHwEffectsFactory.h", + "android/hardware/audio/effect/2.0/BpHwEffectsFactory.h", + "android/hardware/audio/effect/2.0/BsEffectsFactory.h", + "android/hardware/audio/effect/2.0/IEnvironmentalReverbEffect.h", + "android/hardware/audio/effect/2.0/IHwEnvironmentalReverbEffect.h", + "android/hardware/audio/effect/2.0/BnHwEnvironmentalReverbEffect.h", + "android/hardware/audio/effect/2.0/BpHwEnvironmentalReverbEffect.h", + "android/hardware/audio/effect/2.0/BsEnvironmentalReverbEffect.h", + "android/hardware/audio/effect/2.0/IEqualizerEffect.h", + "android/hardware/audio/effect/2.0/IHwEqualizerEffect.h", + "android/hardware/audio/effect/2.0/BnHwEqualizerEffect.h", + "android/hardware/audio/effect/2.0/BpHwEqualizerEffect.h", + "android/hardware/audio/effect/2.0/BsEqualizerEffect.h", + "android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h", + "android/hardware/audio/effect/2.0/IHwLoudnessEnhancerEffect.h", + "android/hardware/audio/effect/2.0/BnHwLoudnessEnhancerEffect.h", + "android/hardware/audio/effect/2.0/BpHwLoudnessEnhancerEffect.h", + "android/hardware/audio/effect/2.0/BsLoudnessEnhancerEffect.h", + "android/hardware/audio/effect/2.0/INoiseSuppressionEffect.h", + "android/hardware/audio/effect/2.0/IHwNoiseSuppressionEffect.h", + "android/hardware/audio/effect/2.0/BnHwNoiseSuppressionEffect.h", + "android/hardware/audio/effect/2.0/BpHwNoiseSuppressionEffect.h", + "android/hardware/audio/effect/2.0/BsNoiseSuppressionEffect.h", + "android/hardware/audio/effect/2.0/IPresetReverbEffect.h", + "android/hardware/audio/effect/2.0/IHwPresetReverbEffect.h", + "android/hardware/audio/effect/2.0/BnHwPresetReverbEffect.h", + "android/hardware/audio/effect/2.0/BpHwPresetReverbEffect.h", + "android/hardware/audio/effect/2.0/BsPresetReverbEffect.h", + "android/hardware/audio/effect/2.0/IVirtualizerEffect.h", + "android/hardware/audio/effect/2.0/IHwVirtualizerEffect.h", + "android/hardware/audio/effect/2.0/BnHwVirtualizerEffect.h", + "android/hardware/audio/effect/2.0/BpHwVirtualizerEffect.h", + "android/hardware/audio/effect/2.0/BsVirtualizerEffect.h", + "android/hardware/audio/effect/2.0/IVisualizerEffect.h", + "android/hardware/audio/effect/2.0/IHwVisualizerEffect.h", + "android/hardware/audio/effect/2.0/BnHwVisualizerEffect.h", + "android/hardware/audio/effect/2.0/BpHwVisualizerEffect.h", + "android/hardware/audio/effect/2.0/BsVisualizerEffect.h", + ], +} + +cc_library_shared { + name: "android.hardware.audio.effect@2.0", + generated_sources: ["android.hardware.audio.effect@2.0_genc++"], + generated_headers: ["android.hardware.audio.effect@2.0_genc++_headers"], + export_generated_headers: ["android.hardware.audio.effect@2.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.audio.common@2.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.audio.common@2.0", + "android.hidl.base@1.0", + ], +}
diff --git a/audio/effect/2.0/Android.mk b/audio/effect/2.0/Android.mk new file mode 100644 index 0000000..d71255e --- /dev/null +++ b/audio/effect/2.0/Android.mk
@@ -0,0 +1,53 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.audio.effect@2.0-java-constants +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +# +GEN := $(intermediates)/android/hardware/audio/effect/V2_0/Constants.java +$(GEN): $(HIDL) +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/IAcousticEchoCancelerEffect.hal +$(GEN): $(LOCAL_PATH)/IAutomaticGainControlEffect.hal +$(GEN): $(LOCAL_PATH)/IBassBoostEffect.hal +$(GEN): $(LOCAL_PATH)/IDownmixEffect.hal +$(GEN): $(LOCAL_PATH)/IEffect.hal +$(GEN): $(LOCAL_PATH)/IEffectBufferProviderCallback.hal +$(GEN): $(LOCAL_PATH)/IEffectsFactory.hal +$(GEN): $(LOCAL_PATH)/IEnvironmentalReverbEffect.hal +$(GEN): $(LOCAL_PATH)/IEqualizerEffect.hal +$(GEN): $(LOCAL_PATH)/ILoudnessEnhancerEffect.hal +$(GEN): $(LOCAL_PATH)/INoiseSuppressionEffect.hal +$(GEN): $(LOCAL_PATH)/IPresetReverbEffect.hal +$(GEN): $(LOCAL_PATH)/IVirtualizerEffect.hal +$(GEN): $(LOCAL_PATH)/IVisualizerEffect.hal + +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava-constants \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.audio.effect@2.0 + +$(GEN): + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +# Avoid dependency cycle of framework.jar -> this-library -> framework.jar +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj + +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio/effect/2.0/IAcousticEchoCancelerEffect.hal b/audio/effect/2.0/IAcousticEchoCancelerEffect.hal new file mode 100644 index 0000000..9e2e0c3 --- /dev/null +++ b/audio/effect/2.0/IAcousticEchoCancelerEffect.hal
@@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IAcousticEchoCancelerEffect extends IEffect { + /* + * Sets echo delay value in milliseconds. + */ + setEchoDelay(uint32_t echoDelayMs) generates (Result retval); + + /* + * Gets echo delay value in milliseconds. + */ + getEchoDelay() generates (Result retval, uint32_t echoDelayMs); +};
diff --git a/audio/effect/2.0/IAutomaticGainControlEffect.hal b/audio/effect/2.0/IAutomaticGainControlEffect.hal new file mode 100644 index 0000000..a02002d --- /dev/null +++ b/audio/effect/2.0/IAutomaticGainControlEffect.hal
@@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IAutomaticGainControlEffect extends IEffect { + /* + * Sets target level in millibels. + */ + setTargetLevel(int16_t targetLevelMb) generates (Result retval); + + /* + * Gets target level. + */ + getTargetLevel() generates (Result retval, int16_t targetLevelMb); + + /* + * Sets gain in the compression range in millibels. + */ + setCompGain(int16_t compGainMb) generates (Result retval); + + /* + * Gets gain in the compression range. + */ + getCompGain() generates (Result retval, int16_t compGainMb); + + /* + * Enables or disables limiter. + */ + setLimiterEnabled(bool enabled) generates (Result retval); + + /* + * Returns whether limiter is enabled. + */ + isLimiterEnabled() generates (Result retval, bool enabled); + + struct AllProperties { + int16_t targetLevelMb; + int16_t compGainMb; + bool limiterEnabled; + }; + + /* + * Sets all properties at once. + */ + setAllProperties(AllProperties properties) generates (Result retval); + + /* + * Gets all properties at once. + */ + getAllProperties() generates (Result retval, AllProperties properties); +};
diff --git a/audio/effect/2.0/IBassBoostEffect.hal b/audio/effect/2.0/IBassBoostEffect.hal new file mode 100644 index 0000000..bcf7b7d --- /dev/null +++ b/audio/effect/2.0/IBassBoostEffect.hal
@@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IBassBoostEffect extends IEffect { + /* + * Returns whether setting bass boost strength is supported. + */ + isStrengthSupported() generates (Result retval, bool strengthSupported); + + enum StrengthRange : uint16_t { + MIN = 0, + MAX = 1000 + }; + + /* + * Sets bass boost strength. + * + * @param strength strength of the effect. The valid range for strength + * strength is [0, 1000], where 0 per mille designates the + * mildest effect and 1000 per mille designates the + * strongest. + * @return retval operation completion status. + */ + setStrength(uint16_t strength) generates (Result retval); + + /* + * Gets virtualization strength. + */ + getStrength() generates (Result retval, uint16_t strength); +};
diff --git a/audio/effect/2.0/IDownmixEffect.hal b/audio/effect/2.0/IDownmixEffect.hal new file mode 100644 index 0000000..06409a3 --- /dev/null +++ b/audio/effect/2.0/IDownmixEffect.hal
@@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IDownmixEffect extends IEffect { + enum Type : int32_t { + STRIP, // throw away the extra channels + FOLD // mix the extra channels with FL/FR + }; + + setType(Type preset) generates (Result retval); + + getType() generates (Result retval, Type preset); +};
diff --git a/audio/effect/2.0/IEffect.hal b/audio/effect/2.0/IEffect.hal new file mode 100644 index 0000000..d254e8c --- /dev/null +++ b/audio/effect/2.0/IEffect.hal
@@ -0,0 +1,439 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffectBufferProviderCallback; + +interface IEffect { + /* + * Initialize effect engine--all configurations return to default. + * + * @return retval operation completion status. + */ + @entry + @callflow(next={"*"}) + init() generates (Result retval); + + /* + * Apply new audio parameters configurations for input and output buffers. + * The provider callbacks may be empty, but in this case the buffer + * must be provided in the EffectConfig structure. + * + * @param config configuration descriptor. + * @param inputBufferProvider optional buffer provider reference. + * @param outputBufferProvider optional buffer provider reference. + * @return retval operation completion status. + */ + @callflow(next={"*"}) + setConfig(EffectConfig config, + IEffectBufferProviderCallback inputBufferProvider, + IEffectBufferProviderCallback outputBufferProvider) + generates (Result retval); + + /* + * Reset the effect engine. Keep configuration but resets state and buffer + * content. + * + * @return retval operation completion status. + */ + @callflow(next={"*"}) + reset() generates (Result retval); + + /* + * Enable processing. + * + * @return retval operation completion status. + */ + @callflow(next={"prepareForProcessing"}) + enable() generates (Result retval); + + /* + * Disable processing. + * + * @return retval operation completion status. + */ + @callflow(next={"close"}) + disable() generates (Result retval); + + /* + * Set the rendering device the audio output path is connected to. The + * effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its + * descriptor to receive this command when the device changes. + * + * Note: this method is only supported for effects inserted into + * the output chain. + * + * @param device output device specification. + * @return retval operation completion status. + */ + @callflow(next={"*"}) + setDevice(AudioDevice device) generates (Result retval); + + /* + * Set and get volume. Used by audio framework to delegate volume control to + * effect engine. The effect implementation must set EFFECT_FLAG_VOLUME_CTRL + * flag in its descriptor to receive this command. The effect engine must + * return the volume that should be applied before the effect is + * processed. The overall volume (the volume actually applied by the effect + * engine multiplied by the returned value) should match the value indicated + * in the command. + * + * @param volumes vector containing volume for each channel defined in + * EffectConfig for output buffer expressed in 8.24 fixed + * point format. + * @return result updated volume values. + * @return retval operation completion status. + */ + @callflow(next={"*"}) + setAndGetVolume(vec<uint32_t> volumes) + generates (Result retval, vec<uint32_t> result); + + /* + * Notify the effect of the volume change. The effect implementation must + * set EFFECT_FLAG_VOLUME_IND flag in its descriptor to receive this + * command. + * + * @param volumes vector containing volume for each channel defined in + * EffectConfig for output buffer expressed in 8.24 fixed + * point format. + * @return retval operation completion status. + */ + volumeChangeNotification(vec<uint32_t> volumes) + generates (Result retval); + + /* + * Set the audio mode. The effect implementation must set + * EFFECT_FLAG_AUDIO_MODE_IND flag in its descriptor to receive this command + * when the audio mode changes. + * + * @param mode desired audio mode. + * @return retval operation completion status. + */ + @callflow(next={"*"}) + setAudioMode(AudioMode mode) generates (Result retval); + + /* + * Apply new audio parameters configurations for input and output buffers of + * reverse stream. An example of reverse stream is the echo reference + * supplied to an Acoustic Echo Canceler. + * + * @param config configuration descriptor. + * @param inputBufferProvider optional buffer provider reference. + * @param outputBufferProvider optional buffer provider reference. + * @return retval operation completion status. + */ + @callflow(next={"*"}) + setConfigReverse(EffectConfig config, + IEffectBufferProviderCallback inputBufferProvider, + IEffectBufferProviderCallback outputBufferProvider) + generates (Result retval); + + /* + * Set the capture device the audio input path is connected to. The effect + * implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to + * receive this command when the device changes. + * + * Note: this method is only supported for effects inserted into + * the input chain. + * + * @param device input device specification. + * @return retval operation completion status. + */ + @callflow(next={"*"}) + setInputDevice(AudioDevice device) generates (Result retval); + + /* + * Read audio parameters configurations for input and output buffers. + * + * @return retval operation completion status. + * @return config configuration descriptor. + */ + @callflow(next={"*"}) + getConfig() generates (Result retval, EffectConfig config); + + /* + * Read audio parameters configurations for input and output buffers of + * reverse stream. + * + * @return retval operation completion status. + * @return config configuration descriptor. + */ + @callflow(next={"*"}) + getConfigReverse() generates (Result retval, EffectConfig config); + + /* + * Queries for supported combinations of main and auxiliary channels + * (e.g. for a multi-microphone noise suppressor). + * + * @param maxConfigs maximum number of the combinations to return. + * @return retval absence of the feature support is indicated using + * NOT_SUPPORTED code. RESULT_TOO_BIG is returned if + * the number of supported combinations exceeds 'maxConfigs'. + * @return result list of configuration descriptors. + */ + @callflow(next={"*"}) + getSupportedAuxChannelsConfigs(uint32_t maxConfigs) + generates (Result retval, vec<EffectAuxChannelsConfig> result); + + /* + * Retrieves the current configuration of main and auxiliary channels. + * + * @return retval absence of the feature support is indicated using + * NOT_SUPPORTED code. + * @return result configuration descriptor. + */ + @callflow(next={"*"}) + getAuxChannelsConfig() + generates (Result retval, EffectAuxChannelsConfig result); + + /* + * Sets the current configuration of main and auxiliary channels. + * + * @return retval operation completion status; absence of the feature + * support is indicated using NOT_SUPPORTED code. + */ + @callflow(next={"*"}) + setAuxChannelsConfig(EffectAuxChannelsConfig config) + generates (Result retval); + + /* + * Set the audio source the capture path is configured for (Camcorder, voice + * recognition...). + * + * Note: this method is only supported for effects inserted into + * the input chain. + * + * @param source source descriptor. + * @return retval operation completion status. + */ + @callflow(next={"*"}) + setAudioSource(AudioSource source) generates (Result retval); + + /* + * This command indicates if the playback thread the effect is attached to + * is offloaded or not, and updates the I/O handle of the playback thread + * the effect is attached to. + * + * @param param effect offload descriptor. + * @return retval operation completion status. + */ + @callflow(next={"*"}) + offload(EffectOffloadParameter param) generates (Result retval); + + /* + * Returns the effect descriptor. + * + * @return retval operation completion status. + * @return descriptor effect descriptor. + */ + @callflow(next={"*"}) + getDescriptor() generates (Result retval, EffectDescriptor descriptor); + + /* + * Set up required transports for passing audio buffers to the effect. + * + * The transport consists of shared memory and a message queue for reporting + * effect processing operation status. The shared memory is set up + * separately using 'setProcessBuffers' method. + * + * Processing is requested by setting 'REQUEST_PROCESS' or + * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message + * queue. The result of processing may be one of the following: + * OK if there were no errors during processing; + * INVALID_ARGUMENTS if audio buffers are invalid; + * INVALID_STATE if the engine has finished the disable phase; + * NOT_INITIALIZED if the audio buffers were not set; + * NOT_SUPPORTED if the requested processing type is not supported by + * the effect. + * + * @return retval OK if both message queues were created successfully. + * INVALID_STATE if the method was already called. + * INVALID_ARGUMENTS if there was a problem setting up + * the queue. + * @return statusMQ a message queue used for passing status from the effect. + */ + @callflow(next={"setProcessBuffers"}) + prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ); + + /* + * Set up input and output buffers for processing audio data. The effect + * may modify both the input and the output buffer during the operation. + * Buffers may be set multiple times during effect lifetime. + * + * The input and the output buffer may be reused between different effects, + * and the input buffer may be used as an output buffer. Buffers are + * distinguished using 'AudioBuffer.id' field. + * + * @param inBuffer input audio buffer. + * @param outBuffer output audio buffer. + * @return retval OK if both buffers were mapped successfully. + * INVALID_ARGUMENTS if there was a problem with mapping + * any of the buffers. + */ + @callflow(next={"*"}) + setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer) generates ( + Result retval); + + /* + * Execute a vendor specific command on the effect. The command code + * and data, as well as result data are not interpreted by Android + * Framework and are passed as-is between the application and the effect. + * + * The effect must use standard POSIX.1-2001 error codes for the operation + * completion status. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param commandId the ID of the command. + * @param data command data. + * @param resultMaxSize maximum size in bytes of the result; can be 0. + * @return status command completion status. + * @return result result data. + */ + command(uint32_t commandId, vec<uint8_t> data, uint32_t resultMaxSize) + generates (int32_t status, vec<uint8_t> result); + + /* + * Set a vendor-specific parameter and apply it immediately. The parameter + * code and data are not interpreted by Android Framework and are passed + * as-is between the application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the parameter ID is + * unknown or if provided parameter data is invalid. If the effect does not + * support setting vendor-specific parameters, it must return NOT_SUPPORTED. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param parameter identifying data of the parameter. + * @param value the value of the parameter. + * @return retval operation completion status. + */ + @callflow(next={"*"}) + setParameter(vec<uint8_t> parameter, vec<uint8_t> value) + generates (Result retval); + + /* + * Get a vendor-specific parameter value. The parameter code and returned + * data are not interpreted by Android Framework and are passed as-is + * between the application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the parameter ID is + * unknown. If the effect does not support setting vendor-specific + * parameters, it must return NOT_SUPPORTED. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param parameter identifying data of the parameter. + * @param valueMaxSize maximum size in bytes of the value. + * @return retval operation completion status. + * @return result the value of the parameter. + */ + @callflow(next={"*"}) + getParameter(vec<uint8_t> parameter, uint32_t valueMaxSize) + generates (Result retval, vec<uint8_t> value); + + /* + * Get supported configs for a vendor-specific feature. The configs returned + * are not interpreted by Android Framework and are passed as-is between the + * application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the feature ID is + * unknown. If the effect does not support getting vendor-specific feature + * configs, it must return NOT_SUPPORTED. If the feature is supported but + * the total number of supported configurations exceeds the maximum number + * indicated by the caller, the method must return RESULT_TOO_BIG. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param featureId feature identifier. + * @param maxConfigs maximum number of configs to return. + * @param configSize size of each config in bytes. + * @return retval operation completion status. + * @return configsCount number of configs returned. + * @return configsData data for all the configs returned. + */ + @callflow(next={"*"}) + getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize) generates ( + Result retval, + uint32_t configsCount, + vec<uint8_t> configsData); + + /* + * Get the current config for a vendor-specific feature. The config returned + * is not interpreted by Android Framework and is passed as-is between the + * application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the feature ID is + * unknown. If the effect does not support getting vendor-specific + * feature configs, it must return NOT_SUPPORTED. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param featureId feature identifier. + * @param configSize size of the config in bytes. + * @return retval operation completion status. + * @return configData config data. + */ + @callflow(next={"*"}) + getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize) + generates (Result retval, vec<uint8_t> configData); + + /* + * Set the current config for a vendor-specific feature. The config data + * is not interpreted by Android Framework and is passed as-is between the + * application and the effect. + * + * The effect must use INVALID_ARGUMENTS return code if the feature ID is + * unknown. If the effect does not support getting vendor-specific + * feature configs, it must return NOT_SUPPORTED. + * + * Use this method only if the effect is provided by a third party, and + * there is no interface defined for it. This method only works for effects + * implemented in software. + * + * @param featureId feature identifier. + * @param configData config data. + * @return retval operation completion status. + */ + setCurrentConfigForFeature(uint32_t featureId, vec<uint8_t> configData) + generates (Result retval); + + /* + * Called by the framework to deinitialize the effect and free up + * all the currently allocated resources. It is recommended to close + * the effect on the client side as soon as it is becomes unused. + * + * @return retval OK in case the success. + * INVALID_STATE if the effect was already closed. + */ + @exit + close() generates (Result retval); +};
diff --git a/audio/effect/2.0/IEffectBufferProviderCallback.hal b/audio/effect/2.0/IEffectBufferProviderCallback.hal new file mode 100644 index 0000000..545e2e5 --- /dev/null +++ b/audio/effect/2.0/IEffectBufferProviderCallback.hal
@@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +/* + * This callback interface contains functions that can be used by the effect + * engine 'process' function to exchange input and output audio buffers. + */ +interface IEffectBufferProviderCallback { + /* + * Called to retrieve a buffer where data should read from by 'process' + * function. + * + * @return buffer audio buffer for processing + */ + // TODO(mnaganov): replace with FMQ version. + getBuffer() generates (AudioBuffer buffer); + + /* + * Called to provide a buffer with the data written by 'process' function. + * + * @param buffer audio buffer for processing + */ + // TODO(mnaganov): replace with FMQ version. + putBuffer(AudioBuffer buffer); +};
diff --git a/audio/effect/2.0/IEffectsFactory.hal b/audio/effect/2.0/IEffectsFactory.hal new file mode 100644 index 0000000..c82b4a2 --- /dev/null +++ b/audio/effect/2.0/IEffectsFactory.hal
@@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IEffectsFactory { + /* + * Returns descriptors of different effects in all loaded libraries. + * + * @return retval operation completion status. + * @return result list of effect descriptors. + */ + getAllDescriptors() generates(Result retval, vec<EffectDescriptor> result); + + /* + * Returns a descriptor of a particular effect. + * + * @return retval operation completion status. + * @return result effect descriptor. + */ + getDescriptor(Uuid uid) generates(Result retval, EffectDescriptor result); + + /* + * Creates an effect engine of the specified type. To release the effect + * engine, it is necessary to release references to the returned effect + * object. + * + * @param uid effect uuid. + * @param session audio session to which this effect instance will be + * attached. All effects created with the same session ID + * are connected in series and process the same signal + * stream. + * @param ioHandle identifies the output or input stream this effect is + * directed to in audio HAL. + * @return retval operation completion status. + * @return result the interface for the created effect. + * @return effectId the unique ID of the effect to be used with + * IStream::addEffect and IStream::removeEffect methods. + */ + createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle) + generates (Result retval, IEffect result, uint64_t effectId); + + /* + * Dumps information about effects into the provided file descriptor. + * This is used for the dumpsys facility. + * + * @param fd dump file descriptor. + */ + debugDump(handle fd); +};
diff --git a/audio/effect/2.0/IEnvironmentalReverbEffect.hal b/audio/effect/2.0/IEnvironmentalReverbEffect.hal new file mode 100644 index 0000000..d9b1ee6 --- /dev/null +++ b/audio/effect/2.0/IEnvironmentalReverbEffect.hal
@@ -0,0 +1,178 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IEnvironmentalReverbEffect extends IEffect { + /* + * Sets whether the effect should be bypassed. + */ + setBypass(bool bypass) generates (Result retval); + + /* + * Gets whether the effect should be bypassed. + */ + getBypass() generates (Result retval, bool bypass); + + enum ParamRange : int16_t { + ROOM_LEVEL_MIN = -6000, + ROOM_LEVEL_MAX = 0, + ROOM_HF_LEVEL_MIN = -4000, + ROOM_HF_LEVEL_MAX = 0, + DECAY_TIME_MIN = 100, + DECAY_TIME_MAX = 20000, + DECAY_HF_RATIO_MIN = 100, + DECAY_HF_RATIO_MAX = 1000, + REFLECTIONS_LEVEL_MIN = -6000, + REFLECTIONS_LEVEL_MAX = 0, + REFLECTIONS_DELAY_MIN = 0, + REFLECTIONS_DELAY_MAX = 65, + REVERB_LEVEL_MIN = -6000, + REVERB_LEVEL_MAX = 0, + REVERB_DELAY_MIN = 0, + REVERB_DELAY_MAX = 65, + DIFFUSION_MIN = 0, + DIFFUSION_MAX = 1000, + DENSITY_MIN = 0, + DENSITY_MAX = 1000 + }; + + /* + * Sets the room level. + */ + setRoomLevel(int16_t roomLevel) generates (Result retval); + + /* + * Gets the room level. + */ + getRoomLevel() generates (Result retval, int16_t roomLevel); + + /* + * Sets the room high frequences level. + */ + setRoomHfLevel(int16_t roomHfLevel) generates (Result retval); + + /* + * Gets the room high frequences level. + */ + getRoomHfLevel() generates (Result retval, int16_t roomHfLevel); + + /* + * Sets the room decay time. + */ + setDecayTime(uint32_t decayTime) generates (Result retval); + + /* + * Gets the room decay time. + */ + getDecayTime() generates (Result retval, uint32_t decayTime); + + /* + * Sets the ratio of high frequences decay. + */ + setDecayHfRatio(int16_t decayHfRatio) generates (Result retval); + + /* + * Gets the ratio of high frequences decay. + */ + getDecayHfRatio() generates (Result retval, int16_t decayHfRatio); + + /* + * Sets the level of reflections in the room. + */ + setReflectionsLevel(int16_t reflectionsLevel) generates (Result retval); + + /* + * Gets the level of reflections in the room. + */ + getReflectionsLevel() generates (Result retval, int16_t reflectionsLevel); + + /* + * Sets the reflections delay in the room. + */ + setReflectionsDelay(uint32_t reflectionsDelay) generates (Result retval); + + /* + * Gets the reflections delay in the room. + */ + getReflectionsDelay() generates (Result retval, uint32_t reflectionsDelay); + + /* + * Sets the reverb level of the room. + */ + setReverbLevel(int16_t reverbLevel) generates (Result retval); + + /* + * Gets the reverb level of the room. + */ + getReverbLevel() generates (Result retval, int16_t reverbLevel); + + /* + * Sets the reverb delay of the room. + */ + setReverbDelay(uint32_t reverDelay) generates (Result retval); + + /* + * Gets the reverb delay of the room. + */ + getReverbDelay() generates (Result retval, uint32_t reverbDelay); + + /* + * Sets room diffusion. + */ + setDiffusion(int16_t diffusion) generates (Result retval); + + /* + * Gets room diffusion. + */ + getDiffusion() generates (Result retval, int16_t diffusion); + + /* + * Sets room wall density. + */ + setDensity(int16_t density) generates (Result retval); + + /* + * Gets room wall density. + */ + getDensity() generates (Result retval, int16_t density); + + struct AllProperties { + int16_t roomLevel; // in millibels, range -6000 to 0 + int16_t roomHfLevel; // in millibels, range -4000 to 0 + uint32_t decayTime; // in milliseconds, range 100 to 20000 + int16_t decayHfRatio; // in permilles, range 100 to 1000 + int16_t reflectionsLevel; // in millibels, range -6000 to 0 + uint32_t reflectionsDelay; // in milliseconds, range 0 to 65 + int16_t reverbLevel; // in millibels, range -6000 to 0 + uint32_t reverbDelay; // in milliseconds, range 0 to 65 + int16_t diffusion; // in permilles, range 0 to 1000 + int16_t density; // in permilles, range 0 to 1000 + }; + + /* + * Sets all properties at once. + */ + setAllProperties(AllProperties properties) generates (Result retval); + + /* + * Gets all properties at once. + */ + getAllProperties() generates (Result retval, AllProperties properties); +};
diff --git a/audio/effect/2.0/IEqualizerEffect.hal b/audio/effect/2.0/IEqualizerEffect.hal new file mode 100644 index 0000000..b8fa177 --- /dev/null +++ b/audio/effect/2.0/IEqualizerEffect.hal
@@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IEqualizerEffect extends IEffect { + /* + * Gets the number of frequency bands that the equalizer supports. + */ + getNumBands() generates (Result retval, uint16_t numBands); + + /* + * Returns the minimum and maximum band levels supported. + */ + getLevelRange() + generates (Result retval, int16_t minLevel, int16_t maxLevel); + + /* + * Sets the gain for the given equalizer band. + */ + setBandLevel(uint16_t band, int16_t level) generates (Result retval); + + /* + * Gets the gain for the given equalizer band. + */ + getBandLevel(uint16_t band) generates (Result retval, int16_t level); + + /* + * Gets the center frequency of the given band, in milliHertz. + */ + getBandCenterFrequency(uint16_t band) + generates (Result retval, uint32_t centerFreqmHz); + + /* + * Gets the frequency range of the given frequency band, in milliHertz. + */ + getBandFrequencyRange(uint16_t band) + generates (Result retval, uint32_t minFreqmHz, uint32_t maxFreqmHz); + + /* + * Gets the band that has the most effect on the given frequency + * in milliHertz. + */ + getBandForFrequency(uint32_t freqmHz) + generates (Result retval, uint16_t band); + + /* + * Gets the names of all presets the equalizer supports. + */ + getPresetNames() generates (Result retval, vec<string> names); + + /* + * Sets the current preset using the index of the preset in the names + * vector returned via 'getPresetNames'. + */ + setCurrentPreset(uint16_t preset) generates (Result retval); + + /* + * Gets the current preset. + */ + getCurrentPreset() generates (Result retval, uint16_t preset); + + struct AllProperties { + uint16_t curPreset; + vec<int16_t> bandLevels; + }; + + /* + * Sets all properties at once. + */ + setAllProperties(AllProperties properties) generates (Result retval); + + /* + * Gets all properties at once. + */ + getAllProperties() generates (Result retval, AllProperties properties); +};
diff --git a/audio/effect/2.0/ILoudnessEnhancerEffect.hal b/audio/effect/2.0/ILoudnessEnhancerEffect.hal new file mode 100644 index 0000000..3e1ee4e --- /dev/null +++ b/audio/effect/2.0/ILoudnessEnhancerEffect.hal
@@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface ILoudnessEnhancerEffect extends IEffect { + /* + * Sets target gain expressed in millibels. + */ + setTargetGain(int32_t targetGainMb) generates (Result retval); + + /* + * Gets target gain expressed in millibels. + */ + getTargetGain() generates (Result retval, int32_t targetGainMb); +};
diff --git a/audio/effect/2.0/INoiseSuppressionEffect.hal b/audio/effect/2.0/INoiseSuppressionEffect.hal new file mode 100644 index 0000000..ae2bfb5 --- /dev/null +++ b/audio/effect/2.0/INoiseSuppressionEffect.hal
@@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface INoiseSuppressionEffect extends IEffect { + enum Level : int32_t { + LOW, + MEDIUM, + HIGH + }; + + /* + * Sets suppression level. + */ + setSuppressionLevel(Level level) generates (Result retval); + + /* + * Gets suppression level. + */ + getSuppressionLevel() generates (Result retval, Level level); + + enum Type : int32_t { + SINGLE_CHANNEL, + MULTI_CHANNEL + }; + + /* + * Set suppression type. + */ + setSuppressionType(Type type) generates (Result retval); + + /* + * Get suppression type. + */ + getSuppressionType() generates (Result retval, Type type); + + struct AllProperties { + Level level; + Type type; + }; + + /* + * Sets all properties at once. + */ + setAllProperties(AllProperties properties) generates (Result retval); + + /* + * Gets all properties at once. + */ + getAllProperties() generates (Result retval, AllProperties properties); +};
diff --git a/audio/effect/2.0/IPresetReverbEffect.hal b/audio/effect/2.0/IPresetReverbEffect.hal new file mode 100644 index 0000000..2237bc4 --- /dev/null +++ b/audio/effect/2.0/IPresetReverbEffect.hal
@@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IPresetReverbEffect extends IEffect { + enum Preset : int32_t { + NONE, // no reverb or reflections + SMALLROOM, // a small room less than five meters in length + MEDIUMROOM, // a medium room with a length of ten meters or less + LARGEROOM, // a large-sized room suitable for live performances + MEDIUMHALL, // a medium-sized hall + LARGEHALL, // a large-sized hall suitable for a full orchestra + PLATE, // synthesis of the traditional plate reverb + LAST = PLATE + }; + + setPreset(Preset preset) generates (Result retval); + + getPreset() generates (Result retval, Preset preset); +};
diff --git a/audio/effect/2.0/IVirtualizerEffect.hal b/audio/effect/2.0/IVirtualizerEffect.hal new file mode 100644 index 0000000..2b7116c --- /dev/null +++ b/audio/effect/2.0/IVirtualizerEffect.hal
@@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IVirtualizerEffect extends IEffect { + /* + * Returns whether setting virtualization strength is supported. + */ + isStrengthSupported() generates (bool strengthSupported); + + enum StrengthRange : uint16_t { + MIN = 0, + MAX = 1000 + }; + + /* + * Sets virtualization strength. + * + * @param strength strength of the effect. The valid range for strength + * strength is [0, 1000], where 0 per mille designates the + * mildest effect and 1000 per mille designates the + * strongest. + * @return retval operation completion status. + */ + setStrength(uint16_t strength) generates (Result retval); + + /* + * Gets virtualization strength. + */ + getStrength() generates (Result retval, uint16_t strength); + + struct SpeakerAngle { + AudioChannelMask mask; // speaker channel mask (1 bit set). + // all angles are expressed in degrees and + // are relative to the listener. + int16_t azimuth; // 0 is the direction the listener faces + // 180 is behind the listener + // -90 is to their left + int16_t elevation; // 0 is the horizontal plane + // +90 is above the listener, -90 is below + }; + /* + * Retrieves virtual speaker angles for the given channel mask on the + * specified device. + */ + getVirtualSpeakerAngles(AudioChannelMask mask, AudioDevice device) + generates (Result retval, vec<SpeakerAngle> speakerAngles); + + /* + * Forces the virtualizer effect for the given output device. + */ + forceVirtualizationMode(AudioDevice device) generates (Result retval); + + /* + * Returns audio device reflecting the current virtualization mode, + * AUDIO_DEVICE_NONE when not virtualizing. + */ + getVirtualizationMode() generates (Result retval, AudioDevice device); +};
diff --git a/audio/effect/2.0/IVisualizerEffect.hal b/audio/effect/2.0/IVisualizerEffect.hal new file mode 100644 index 0000000..79dc9ee --- /dev/null +++ b/audio/effect/2.0/IVisualizerEffect.hal
@@ -0,0 +1,110 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; +import IEffect; + +interface IVisualizerEffect extends IEffect { + enum CaptureSizeRange : int32_t { + MAX = 1024, // maximum capture size in samples + MIN = 128 // minimum capture size in samples + }; + + /* + * Sets the number PCM samples in the capture. + */ + setCaptureSize(uint16_t captureSize) generates (Result retval); + + /* + * Gets the number PCM samples in the capture. + */ + getCaptureSize() generates (Result retval, uint16_t captureSize); + + enum ScalingMode : int32_t { + // Keep in sync with SCALING_MODE_... in + // frameworks/base/media/java/android/media/audiofx/Visualizer.java + NORMALIZED = 0, + AS_PLAYED = 1 + }; + + /* + * Specifies the way the captured data is scaled. + */ + setScalingMode(ScalingMode scalingMode) generates (Result retval); + + /* + * Retrieves the way the captured data is scaled. + */ + getScalingMode() generates (Result retval, ScalingMode scalingMode); + + /* + * Informs the visualizer about the downstream latency. + */ + setLatency(uint32_t latencyMs) generates (Result retval); + + /* + * Gets the downstream latency. + */ + getLatency() generates (Result retval, uint32_t latencyMs); + + enum MeasurementMode : int32_t { + // Keep in sync with MEASUREMENT_MODE_... in + // frameworks/base/media/java/android/media/audiofx/Visualizer.java + NONE = 0x0, + PEAK_RMS = 0x1 + }; + + /* + * Specifies which measurements are to be made. + */ + setMeasurementMode(MeasurementMode measurementMode) + generates (Result retval); + + /* + * Retrieves which measurements are to be made. + */ + getMeasurementMode() generates ( + Result retval, MeasurementMode measurementMode); + + /* + * Retrieves the latest PCM snapshot captured by the visualizer engine. The + * number of samples to capture is specified by 'setCaptureSize' parameter. + * + * @return retval operation completion status. + * @return samples samples in 8 bit unsigned format (0 = 0x80) + */ + capture() generates (Result retval, vec<uint8_t> samples); + + struct Measurement { + MeasurementMode mode; // discriminator + union Values { + struct PeakAndRms { + int32_t peakMb; // millibels + int32_t rmsMb; // millibels + } peakAndRms; + } value; + }; + /* + * Retrieves the lastest measurements. The measurements to be made + * are specified by 'setMeasurementMode' parameter. + * + * @return retval operation completion status. + * @return result measurement. + */ + measure() generates (Result retval, Measurement result); +};
diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp b/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp new file mode 100644 index 0000000..7b9ca30 --- /dev/null +++ b/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp
@@ -0,0 +1,191 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "AEC_Effect_HAL" +#include <system/audio_effects/effect_aec.h> +#include <android/log.h> + +#include "AcousticEchoCancelerEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +AcousticEchoCancelerEffect::AcousticEchoCancelerEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +AcousticEchoCancelerEffect::~AcousticEchoCancelerEffect() {} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> AcousticEchoCancelerEffect::init() { + return mEffect->init(); +} + +Return<Result> AcousticEchoCancelerEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> AcousticEchoCancelerEffect::reset() { + return mEffect->reset(); +} + +Return<Result> AcousticEchoCancelerEffect::enable() { + return mEffect->enable(); +} + +Return<Result> AcousticEchoCancelerEffect::disable() { + return mEffect->disable(); +} + +Return<Result> AcousticEchoCancelerEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> AcousticEchoCancelerEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> AcousticEchoCancelerEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> AcousticEchoCancelerEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> AcousticEchoCancelerEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> AcousticEchoCancelerEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> AcousticEchoCancelerEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> AcousticEchoCancelerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> AcousticEchoCancelerEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> AcousticEchoCancelerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> AcousticEchoCancelerEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> AcousticEchoCancelerEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> AcousticEchoCancelerEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> AcousticEchoCancelerEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> AcousticEchoCancelerEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> AcousticEchoCancelerEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> AcousticEchoCancelerEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> AcousticEchoCancelerEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> AcousticEchoCancelerEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> AcousticEchoCancelerEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> AcousticEchoCancelerEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> AcousticEchoCancelerEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> AcousticEchoCancelerEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow. +Return<Result> AcousticEchoCancelerEffect::setEchoDelay(uint32_t echoDelayMs) { + return mEffect->setParam(AEC_PARAM_ECHO_DELAY, echoDelayMs); +} + +Return<void> AcousticEchoCancelerEffect::getEchoDelay(getEchoDelay_cb _hidl_cb) { + return mEffect->getIntegerParam(AEC_PARAM_ECHO_DELAY, _hidl_cb); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.h b/audio/effect/2.0/default/AcousticEchoCancelerEffect.h new file mode 100644 index 0000000..1ac925d --- /dev/null +++ b/audio/effect/2.0/default/AcousticEchoCancelerEffect.h
@@ -0,0 +1,117 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H + +#include <android/hardware/audio/effect/2.0/IAcousticEchoCancelerEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect { + explicit AcousticEchoCancelerEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow. + Return<Result> setEchoDelay(uint32_t echoDelayMs) override; + Return<void> getEchoDelay(getEchoDelay_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~AcousticEchoCancelerEffect(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H
diff --git a/audio/effect/2.0/default/Android.mk b/audio/effect/2.0/default/Android.mk new file mode 100644 index 0000000..bbcf298 --- /dev/null +++ b/audio/effect/2.0/default/Android.mk
@@ -0,0 +1,39 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.audio.effect@2.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + AcousticEchoCancelerEffect.cpp \ + AudioBufferManager.cpp \ + AutomaticGainControlEffect.cpp \ + BassBoostEffect.cpp \ + Conversions.cpp \ + DownmixEffect.cpp \ + Effect.cpp \ + EffectsFactory.cpp \ + EnvironmentalReverbEffect.cpp \ + EqualizerEffect.cpp \ + LoudnessEnhancerEffect.cpp \ + NoiseSuppressionEffect.cpp \ + PresetReverbEffect.cpp \ + VirtualizerEffect.cpp \ + VisualizerEffect.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils \ + libeffects \ + libfmq \ + libhidlbase \ + libhidlmemory \ + libhidltransport \ + liblog \ + libutils \ + android.hardware.audio.common@2.0 \ + android.hardware.audio.common@2.0-util \ + android.hardware.audio.effect@2.0 \ + android.hidl.memory@1.0 \ + +include $(BUILD_SHARED_LIBRARY)
diff --git a/audio/effect/2.0/default/AudioBufferManager.cpp b/audio/effect/2.0/default/AudioBufferManager.cpp new file mode 100644 index 0000000..603dbb8 --- /dev/null +++ b/audio/effect/2.0/default/AudioBufferManager.cpp
@@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <atomic> + +#include <hidlmemory/mapping.h> + +#include "AudioBufferManager.h" + +namespace android { + +ANDROID_SINGLETON_STATIC_INSTANCE(AudioBufferManager); + +bool AudioBufferManager::wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper) { + // Check if we have this buffer already + std::lock_guard<std::mutex> lock(mLock); + ssize_t idx = mBuffers.indexOfKey(buffer.id); + if (idx >= 0) { + *wrapper = mBuffers[idx].promote(); + if (*wrapper != nullptr) return true; + mBuffers.removeItemsAt(idx); + } + // Need to create and init a new AudioBufferWrapper. + sp<AudioBufferWrapper> tempBuffer(new AudioBufferWrapper(buffer)); + if (!tempBuffer->init()) return false; + *wrapper = tempBuffer; + mBuffers.add(buffer.id, *wrapper); + return true; +} + +void AudioBufferManager::removeEntry(uint64_t id) { + std::lock_guard<std::mutex> lock(mLock); + ssize_t idx = mBuffers.indexOfKey(id); + if (idx >= 0) mBuffers.removeItemsAt(idx); +} + +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +AudioBufferWrapper::AudioBufferWrapper(const AudioBuffer& buffer) : + mHidlBuffer(buffer), mHalBuffer{ 0, { nullptr } } { +} + +AudioBufferWrapper::~AudioBufferWrapper() { + AudioBufferManager::getInstance().removeEntry(mHidlBuffer.id); +} + +bool AudioBufferWrapper::init() { + if (mHalBuffer.raw != nullptr) { + ALOGE("An attempt to init AudioBufferWrapper twice"); + return false; + } + mHidlMemory = mapMemory(mHidlBuffer.data); + if (mHidlMemory == nullptr) { + ALOGE("Could not map HIDL memory to IMemory"); + return false; + } + mHalBuffer.raw = static_cast<void*>(mHidlMemory->getPointer()); + if (mHalBuffer.raw == nullptr) { + ALOGE("IMemory buffer pointer is null"); + return false; + } + mHalBuffer.frameCount = mHidlBuffer.frameCount; + return true; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/AudioBufferManager.h b/audio/effect/2.0/default/AudioBufferManager.h new file mode 100644 index 0000000..6d65995 --- /dev/null +++ b/audio/effect/2.0/default/AudioBufferManager.h
@@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef android_hardware_audio_effect_V2_0_AudioBufferManager_H_ +#define android_hardware_audio_effect_V2_0_AudioBufferManager_H_ + +#include <mutex> + +#include <android/hardware/audio/effect/2.0/types.h> +#include <android/hidl/memory/1.0/IMemory.h> +#include <system/audio_effect.h> +#include <utils/RefBase.h> +#include <utils/KeyedVector.h> +#include <utils/Singleton.h> + +using ::android::hardware::audio::effect::V2_0::AudioBuffer; +using ::android::hidl::memory::V1_0::IMemory; + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +class AudioBufferWrapper : public RefBase { + public: + explicit AudioBufferWrapper(const AudioBuffer& buffer); + virtual ~AudioBufferWrapper(); + bool init(); + audio_buffer_t* getHalBuffer() { return &mHalBuffer; } + private: + AudioBufferWrapper(const AudioBufferWrapper&) = delete; + void operator=(AudioBufferWrapper) = delete; + + AudioBuffer mHidlBuffer; + sp<IMemory> mHidlMemory; + audio_buffer_t mHalBuffer; +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +using ::android::hardware::audio::effect::V2_0::implementation::AudioBufferWrapper; + +namespace android { + +// This class needs to be in 'android' ns because Singleton macros require that. +class AudioBufferManager : public Singleton<AudioBufferManager> { + public: + bool wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper); + + private: + friend class hardware::audio::effect::V2_0::implementation::AudioBufferWrapper; + + // Called by AudioBufferWrapper. + void removeEntry(uint64_t id); + + std::mutex mLock; + KeyedVector<uint64_t, wp<AudioBufferWrapper>> mBuffers; +}; + +} // namespace android + +#endif // android_hardware_audio_effect_V2_0_AudioBufferManager_H_
diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.cpp b/audio/effect/2.0/default/AutomaticGainControlEffect.cpp new file mode 100644 index 0000000..62fe5f7 --- /dev/null +++ b/audio/effect/2.0/default/AutomaticGainControlEffect.cpp
@@ -0,0 +1,237 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "AGC_Effect_HAL" +#include <android/log.h> + +#include "AutomaticGainControlEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +AutomaticGainControlEffect::AutomaticGainControlEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +AutomaticGainControlEffect::~AutomaticGainControlEffect() {} + +void AutomaticGainControlEffect::propertiesFromHal( + const t_agc_settings& halProperties, + IAutomaticGainControlEffect::AllProperties* properties) { + properties->targetLevelMb = halProperties.targetLevel; + properties->compGainMb = halProperties.compGain; + properties->limiterEnabled = halProperties.limiterEnabled; +} + +void AutomaticGainControlEffect::propertiesToHal( + const IAutomaticGainControlEffect::AllProperties& properties, + t_agc_settings* halProperties) { + halProperties->targetLevel = properties.targetLevelMb; + halProperties->compGain = properties.compGainMb; + halProperties->limiterEnabled = properties.limiterEnabled; +} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> AutomaticGainControlEffect::init() { + return mEffect->init(); +} + +Return<Result> AutomaticGainControlEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> AutomaticGainControlEffect::reset() { + return mEffect->reset(); +} + +Return<Result> AutomaticGainControlEffect::enable() { + return mEffect->enable(); +} + +Return<Result> AutomaticGainControlEffect::disable() { + return mEffect->disable(); +} + +Return<Result> AutomaticGainControlEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> AutomaticGainControlEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> AutomaticGainControlEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> AutomaticGainControlEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> AutomaticGainControlEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> AutomaticGainControlEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> AutomaticGainControlEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> AutomaticGainControlEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> AutomaticGainControlEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> AutomaticGainControlEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> AutomaticGainControlEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> AutomaticGainControlEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> AutomaticGainControlEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> AutomaticGainControlEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> AutomaticGainControlEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> AutomaticGainControlEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> AutomaticGainControlEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> AutomaticGainControlEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> AutomaticGainControlEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> AutomaticGainControlEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> AutomaticGainControlEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> AutomaticGainControlEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> AutomaticGainControlEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect follow. +Return<Result> AutomaticGainControlEffect::setTargetLevel(int16_t targetLevelMb) { + return mEffect->setParam(AGC_PARAM_TARGET_LEVEL, targetLevelMb); +} + +Return<void> AutomaticGainControlEffect::getTargetLevel(getTargetLevel_cb _hidl_cb) { + return mEffect->getIntegerParam(AGC_PARAM_TARGET_LEVEL, _hidl_cb); +} + +Return<Result> AutomaticGainControlEffect::setCompGain(int16_t compGainMb) { + return mEffect->setParam(AGC_PARAM_COMP_GAIN, compGainMb); +} + +Return<void> AutomaticGainControlEffect::getCompGain(getCompGain_cb _hidl_cb) { + return mEffect->getIntegerParam(AGC_PARAM_COMP_GAIN, _hidl_cb); +} + +Return<Result> AutomaticGainControlEffect::setLimiterEnabled(bool enabled) { + return mEffect->setParam(AGC_PARAM_LIMITER_ENA, enabled); +} + +Return<void> AutomaticGainControlEffect::isLimiterEnabled(isLimiterEnabled_cb _hidl_cb) { + return mEffect->getIntegerParam(AGC_PARAM_LIMITER_ENA, _hidl_cb); +} + +Return<Result> AutomaticGainControlEffect::setAllProperties(const IAutomaticGainControlEffect::AllProperties& properties) { + t_agc_settings halProperties; + propertiesToHal(properties, &halProperties); + return mEffect->setParam(AGC_PARAM_PROPERTIES, halProperties); +} + +Return<void> AutomaticGainControlEffect::getAllProperties(getAllProperties_cb _hidl_cb) { + t_agc_settings halProperties; + Result retval = mEffect->getParam(AGC_PARAM_PROPERTIES, halProperties); + AllProperties properties; + propertiesFromHal(halProperties, &properties); + _hidl_cb(retval, properties); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.h b/audio/effect/2.0/default/AutomaticGainControlEffect.h new file mode 100644 index 0000000..5e1f279 --- /dev/null +++ b/audio/effect/2.0/default/AutomaticGainControlEffect.h
@@ -0,0 +1,133 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H + +#include <system/audio_effects/effect_agc.h> + +#include <android/hardware/audio/effect/2.0/IAutomaticGainControlEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct AutomaticGainControlEffect : public IAutomaticGainControlEffect { + explicit AutomaticGainControlEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect follow. + Return<Result> setTargetLevel(int16_t targetLevelMb) override; + Return<void> getTargetLevel(getTargetLevel_cb _hidl_cb) override; + Return<Result> setCompGain(int16_t compGainMb) override; + Return<void> getCompGain(getCompGain_cb _hidl_cb) override; + Return<Result> setLimiterEnabled(bool enabled) override; + Return<void> isLimiterEnabled(isLimiterEnabled_cb _hidl_cb) override; + Return<Result> setAllProperties( + const IAutomaticGainControlEffect::AllProperties& properties) override; + Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~AutomaticGainControlEffect(); + + void propertiesFromHal( + const t_agc_settings& halProperties, + IAutomaticGainControlEffect::AllProperties* properties); + void propertiesToHal( + const IAutomaticGainControlEffect::AllProperties& properties, + t_agc_settings* halProperties); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H
diff --git a/audio/effect/2.0/default/BassBoostEffect.cpp b/audio/effect/2.0/default/BassBoostEffect.cpp new file mode 100644 index 0000000..8f35e5f --- /dev/null +++ b/audio/effect/2.0/default/BassBoostEffect.cpp
@@ -0,0 +1,195 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "BassBoost_HAL" +#include <system/audio_effects/effect_bassboost.h> +#include <android/log.h> + +#include "BassBoostEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +BassBoostEffect::BassBoostEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +BassBoostEffect::~BassBoostEffect() {} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> BassBoostEffect::init() { + return mEffect->init(); +} + +Return<Result> BassBoostEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> BassBoostEffect::reset() { + return mEffect->reset(); +} + +Return<Result> BassBoostEffect::enable() { + return mEffect->enable(); +} + +Return<Result> BassBoostEffect::disable() { + return mEffect->disable(); +} + +Return<Result> BassBoostEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> BassBoostEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> BassBoostEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> BassBoostEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> BassBoostEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> BassBoostEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> BassBoostEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> BassBoostEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> BassBoostEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> BassBoostEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> BassBoostEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> BassBoostEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> BassBoostEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> BassBoostEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> BassBoostEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> BassBoostEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> BassBoostEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> BassBoostEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> BassBoostEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> BassBoostEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> BassBoostEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> BassBoostEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> BassBoostEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IBassBoostEffect follow. +Return<void> BassBoostEffect::isStrengthSupported(isStrengthSupported_cb _hidl_cb) { + return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH_SUPPORTED, _hidl_cb); +} + +Return<Result> BassBoostEffect::setStrength(uint16_t strength) { + return mEffect->setParam(BASSBOOST_PARAM_STRENGTH, strength); +} + +Return<void> BassBoostEffect::getStrength(getStrength_cb _hidl_cb) { + return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH, _hidl_cb); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/BassBoostEffect.h b/audio/effect/2.0/default/BassBoostEffect.h new file mode 100644 index 0000000..1e5053b --- /dev/null +++ b/audio/effect/2.0/default/BassBoostEffect.h
@@ -0,0 +1,118 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H + +#include <android/hardware/audio/effect/2.0/IBassBoostEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::effect::V2_0::IBassBoostEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct BassBoostEffect : public IBassBoostEffect { + explicit BassBoostEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::IBassBoostEffect follow. + Return<void> isStrengthSupported(isStrengthSupported_cb _hidl_cb) override; + Return<Result> setStrength(uint16_t strength) override; + Return<void> getStrength(getStrength_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~BassBoostEffect(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H
diff --git a/audio/effect/2.0/default/Conversions.cpp b/audio/effect/2.0/default/Conversions.cpp new file mode 100644 index 0000000..e7d4c46 --- /dev/null +++ b/audio/effect/2.0/default/Conversions.cpp
@@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <memory.h> +#include <stdio.h> + +#include "Conversions.h" +#include "HidlUtils.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +void effectDescriptorFromHal( + const effect_descriptor_t& halDescriptor, EffectDescriptor* descriptor) { + HidlUtils::uuidFromHal(halDescriptor.type, &descriptor->type); + HidlUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid); + descriptor->flags = EffectFlags(halDescriptor.flags); + descriptor->cpuLoad = halDescriptor.cpuLoad; + descriptor->memoryUsage = halDescriptor.memoryUsage; + memcpy(descriptor->name.data(), halDescriptor.name, descriptor->name.size()); + memcpy(descriptor->implementor.data(), + halDescriptor.implementor, descriptor->implementor.size()); +} + +std::string uuidToString(const effect_uuid_t& halUuid) { + char str[64]; + snprintf(str, sizeof(str), "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", + halUuid.timeLow, + halUuid.timeMid, + halUuid.timeHiAndVersion, + halUuid.clockSeq, + halUuid.node[0], + halUuid.node[1], + halUuid.node[2], + halUuid.node[3], + halUuid.node[4], + halUuid.node[5]); + return str; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/Conversions.h b/audio/effect/2.0/default/Conversions.h new file mode 100644 index 0000000..7cef362 --- /dev/null +++ b/audio/effect/2.0/default/Conversions.h
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_audio_effect_V2_0_Conversions_H_ +#define android_hardware_audio_effect_V2_0_Conversions_H_ + +#include <string> + +#include <android/hardware/audio/effect/2.0/types.h> +#include <system/audio_effect.h> + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; + +void effectDescriptorFromHal( + const effect_descriptor_t& halDescriptor, EffectDescriptor* descriptor); +std::string uuidToString(const effect_uuid_t& halUuid); + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // android_hardware_audio_effect_V2_0_Conversions_H_
diff --git a/audio/effect/2.0/default/DownmixEffect.cpp b/audio/effect/2.0/default/DownmixEffect.cpp new file mode 100644 index 0000000..92f15bd --- /dev/null +++ b/audio/effect/2.0/default/DownmixEffect.cpp
@@ -0,0 +1,194 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "Downmix_HAL" +#include <system/audio_effects/effect_downmix.h> +#include <android/log.h> + +#include "DownmixEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +DownmixEffect::DownmixEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +DownmixEffect::~DownmixEffect() {} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> DownmixEffect::init() { + return mEffect->init(); +} + +Return<Result> DownmixEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> DownmixEffect::reset() { + return mEffect->reset(); +} + +Return<Result> DownmixEffect::enable() { + return mEffect->enable(); +} + +Return<Result> DownmixEffect::disable() { + return mEffect->disable(); +} + +Return<Result> DownmixEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> DownmixEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> DownmixEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> DownmixEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> DownmixEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> DownmixEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> DownmixEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> DownmixEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> DownmixEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> DownmixEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> DownmixEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> DownmixEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> DownmixEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> DownmixEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> DownmixEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> DownmixEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> DownmixEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> DownmixEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> DownmixEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> DownmixEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> DownmixEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> DownmixEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> DownmixEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IDownmixEffect follow. +Return<Result> DownmixEffect::setType(IDownmixEffect::Type preset) { + return mEffect->setParam(DOWNMIX_PARAM_TYPE, static_cast<downmix_type_t>(preset)); +} + +Return<void> DownmixEffect::getType(getType_cb _hidl_cb) { + downmix_type_t halPreset = DOWNMIX_TYPE_INVALID; + Result retval = mEffect->getParam(DOWNMIX_PARAM_TYPE, halPreset); + _hidl_cb(retval, Type(halPreset)); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/DownmixEffect.h b/audio/effect/2.0/default/DownmixEffect.h new file mode 100644 index 0000000..125f34d --- /dev/null +++ b/audio/effect/2.0/default/DownmixEffect.h
@@ -0,0 +1,117 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H + +#include <android/hardware/audio/effect/2.0/IDownmixEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::effect::V2_0::IDownmixEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct DownmixEffect : public IDownmixEffect { + explicit DownmixEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::IDownmixEffect follow. + Return<Result> setType(IDownmixEffect::Type preset) override; + Return<void> getType(getType_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~DownmixEffect(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H
diff --git a/audio/effect/2.0/default/Effect.cpp b/audio/effect/2.0/default/Effect.cpp new file mode 100644 index 0000000..6704239 --- /dev/null +++ b/audio/effect/2.0/default/Effect.cpp
@@ -0,0 +1,766 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <memory.h> + +#define LOG_TAG "EffectHAL" +#define ATRACE_TAG ATRACE_TAG_AUDIO + +#include <android/log.h> +#include <media/EffectsFactoryApi.h> +#include <utils/Trace.h> + +#include "Conversions.h" +#include "Effect.h" +#include "EffectMap.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioFormat; +using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits; + +namespace { + +class ProcessThread : public Thread { + public: + // ProcessThread's lifespan never exceeds Effect's lifespan. + ProcessThread(std::atomic<bool>* stop, + effect_handle_t effect, + std::atomic<audio_buffer_t*>* inBuffer, + std::atomic<audio_buffer_t*>* outBuffer, + Effect::StatusMQ* statusMQ, + EventFlag* efGroup) + : Thread(false /*canCallJava*/), + mStop(stop), + mEffect(effect), + mHasProcessReverse((*mEffect)->process_reverse != NULL), + mInBuffer(inBuffer), + mOutBuffer(outBuffer), + mStatusMQ(statusMQ), + mEfGroup(efGroup) { + } + virtual ~ProcessThread() {} + + private: + std::atomic<bool>* mStop; + effect_handle_t mEffect; + bool mHasProcessReverse; + std::atomic<audio_buffer_t*>* mInBuffer; + std::atomic<audio_buffer_t*>* mOutBuffer; + Effect::StatusMQ* mStatusMQ; + EventFlag* mEfGroup; + + bool threadLoop() override; +}; + +bool ProcessThread::threadLoop() { + // This implementation doesn't return control back to the Thread until it decides to stop, + // as the Thread uses mutexes, and this can lead to priority inversion. + while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) { + uint32_t efState = 0; + mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL), &efState); + if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL)) + || (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT))) { + continue; // Nothing to do or time to quit. + } + Result retval = Result::OK; + if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE) + && !mHasProcessReverse) { + retval = Result::NOT_SUPPORTED; + } + + if (retval == Result::OK) { + // affects both buffer pointers and their contents. + std::atomic_thread_fence(std::memory_order_acquire); + int32_t processResult; + audio_buffer_t* inBuffer = + std::atomic_load_explicit(mInBuffer, std::memory_order_relaxed); + audio_buffer_t* outBuffer = + std::atomic_load_explicit(mOutBuffer, std::memory_order_relaxed); + if (inBuffer != nullptr && outBuffer != nullptr) { + if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS)) { + processResult = (*mEffect)->process(mEffect, inBuffer, outBuffer); + } else { + processResult = (*mEffect)->process_reverse(mEffect, inBuffer, outBuffer); + } + std::atomic_thread_fence(std::memory_order_release); + } else { + ALOGE("processing buffers were not set before calling 'process'"); + processResult = -ENODEV; + } + switch(processResult) { + case 0: retval = Result::OK; break; + case -ENODATA: retval = Result::INVALID_STATE; break; + case -EINVAL: retval = Result::INVALID_ARGUMENTS; break; + default: retval = Result::NOT_INITIALIZED; + } + } + if (!mStatusMQ->write(&retval)) { + ALOGW("status message queue write failed"); + } + mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING)); + } + + return false; +} + +} // namespace + +// static +const char *Effect::sContextResultOfCommand = "returned status"; +const char *Effect::sContextCallToCommand = "error"; +const char *Effect::sContextCallFunction = sContextCallToCommand; + +Effect::Effect(effect_handle_t handle) + : mIsClosed(false), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) { +} + +Effect::~Effect() { + ATRACE_CALL(); + close(); + if (mProcessThread.get()) { + ATRACE_NAME("mProcessThread->join"); + status_t status = mProcessThread->join(); + ALOGE_IF(status, "processing thread exit error: %s", strerror(-status)); + } + if (mEfGroup) { + status_t status = EventFlag::deleteEventFlag(&mEfGroup); + ALOGE_IF(status, "processing MQ event flag deletion error: %s", strerror(-status)); + } + mInBuffer.clear(); + mOutBuffer.clear(); + int status = EffectRelease(mHandle); + ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status)); + EffectMap::getInstance().remove(mHandle); + mHandle = 0; +} + +// static +template<typename T> size_t Effect::alignedSizeIn(size_t s) { + return (s + sizeof(T) - 1) / sizeof(T); +} + +// static +template<typename T> std::unique_ptr<uint8_t[]> Effect::hidlVecToHal( + const hidl_vec<T>& vec, uint32_t* halDataSize) { + // Due to bugs in HAL, they may attempt to write into the provided + // input buffer. The original binder buffer is r/o, thus it is needed + // to create a r/w version. + *halDataSize = vec.size() * sizeof(T); + std::unique_ptr<uint8_t[]> halData(new uint8_t[*halDataSize]); + memcpy(&halData[0], &vec[0], *halDataSize); + return halData; +} + +// static +void Effect::effectAuxChannelsConfigFromHal( + const channel_config_t& halConfig, EffectAuxChannelsConfig* config) { + config->mainChannels = AudioChannelMask(halConfig.main_channels); + config->auxChannels = AudioChannelMask(halConfig.aux_channels); +} + +// static +void Effect::effectAuxChannelsConfigToHal( + const EffectAuxChannelsConfig& config, channel_config_t* halConfig) { + halConfig->main_channels = static_cast<audio_channel_mask_t>(config.mainChannels); + halConfig->aux_channels = static_cast<audio_channel_mask_t>(config.auxChannels); +} + +// static +void Effect::effectBufferConfigFromHal( + const buffer_config_t& halConfig, EffectBufferConfig* config) { + config->buffer.id = 0; + config->buffer.frameCount = 0; + config->samplingRateHz = halConfig.samplingRate; + config->channels = AudioChannelMask(halConfig.channels); + config->format = AudioFormat(halConfig.format); + config->accessMode = EffectBufferAccess(halConfig.accessMode); + config->mask = EffectConfigParameters(halConfig.mask); +} + +// static +void Effect::effectBufferConfigToHal(const EffectBufferConfig& config, buffer_config_t* halConfig) { + // Note: setting the buffers directly is considered obsolete. They need to be set + // using 'setProcessBuffers'. + halConfig->buffer.frameCount = 0; + halConfig->buffer.raw = NULL; + halConfig->samplingRate = config.samplingRateHz; + halConfig->channels = static_cast<uint32_t>(config.channels); + // TODO(mnaganov): The framework code currently does not use BP, implement later. + halConfig->bufferProvider.cookie = NULL; + halConfig->bufferProvider.getBuffer = NULL; + halConfig->bufferProvider.releaseBuffer = NULL; + halConfig->format = static_cast<uint8_t>(config.format); + halConfig->accessMode = static_cast<uint8_t>(config.accessMode); + halConfig->mask = static_cast<uint8_t>(config.mask); +} + +// static +void Effect::effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config) { + effectBufferConfigFromHal(halConfig.inputCfg, &config->inputCfg); + effectBufferConfigFromHal(halConfig.outputCfg, &config->outputCfg); +} + +// static +void Effect::effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig) { + effectBufferConfigToHal(config.inputCfg, &halConfig->inputCfg); + effectBufferConfigToHal(config.outputCfg, &halConfig->outputCfg); +} + +// static +void Effect::effectOffloadParamToHal( + const EffectOffloadParameter& offload, effect_offload_param_t* halOffload) { + halOffload->isOffload = offload.isOffload; + halOffload->ioHandle = offload.ioHandle; +} + +// static +std::vector<uint8_t> Effect::parameterToHal( + uint32_t paramSize, + const void* paramData, + uint32_t valueSize, + const void** valueData) { + size_t valueOffsetFromData = alignedSizeIn<uint32_t>(paramSize) * sizeof(uint32_t); + size_t halParamBufferSize = sizeof(effect_param_t) + valueOffsetFromData + valueSize; + std::vector<uint8_t> halParamBuffer(halParamBufferSize, 0); + effect_param_t *halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]); + halParam->psize = paramSize; + halParam->vsize = valueSize; + memcpy(halParam->data, paramData, paramSize); + if (valueData) { + if (*valueData) { + // Value data is provided. + memcpy(halParam->data + valueOffsetFromData, *valueData, valueSize); + } else { + // The caller needs the pointer to the value data location. + *valueData = halParam->data + valueOffsetFromData; + } + } + return halParamBuffer; +} + +Result Effect::analyzeCommandStatus(const char* commandName, const char* context, status_t status) { + return analyzeStatus("command", commandName, context, status); +} + +Result Effect::analyzeStatus( + const char* funcName, + const char* subFuncName, + const char* contextDescription, + status_t status) { + if (status != OK) { + ALOGW("Effect %p %s %s %s: %s", + mHandle, funcName, subFuncName, contextDescription, strerror(-status)); + } + switch (status) { + case OK: return Result::OK; + case -EINVAL: return Result::INVALID_ARGUMENTS; + case -ENODATA: return Result::INVALID_STATE; + case -ENODEV: return Result::NOT_INITIALIZED; + case -ENOMEM: return Result::RESULT_TOO_BIG; + case -ENOSYS: return Result::NOT_SUPPORTED; + default: return Result::INVALID_STATE; + } +} + +void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb) { + uint32_t halResultSize = sizeof(effect_config_t); + effect_config_t halConfig{}; + status_t status = (*mHandle)->command( + mHandle, commandCode, 0, NULL, &halResultSize, &halConfig); + EffectConfig config; + if (status == OK) { + effectConfigFromHal(halConfig, &config); + } + cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config); +} + +Result Effect::getCurrentConfigImpl( + uint32_t featureId, uint32_t configSize, GetCurrentConfigSuccessCallback onSuccess) { + uint32_t halCmd = featureId; + uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize)]; + memset(halResult, 0, sizeof(halResult)); + uint32_t halResultSize = 0; + return sendCommandReturningStatusAndData( + EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG", + sizeof(uint32_t), &halCmd, + &halResultSize, halResult, + sizeof(uint32_t), + [&]{ onSuccess(&halResult[1]); }); +} + +Result Effect::getParameterImpl( + uint32_t paramSize, + const void* paramData, + uint32_t requestValueSize, + uint32_t replyValueSize, + GetParameterSuccessCallback onSuccess) { + // As it is unknown what method HAL uses for copying the provided parameter data, + // it is safer to make sure that input and output buffers do not overlap. + std::vector<uint8_t> halCmdBuffer = + parameterToHal(paramSize, paramData, requestValueSize, nullptr); + const void *valueData = nullptr; + std::vector<uint8_t> halParamBuffer = + parameterToHal(paramSize, paramData, replyValueSize, &valueData); + uint32_t halParamBufferSize = halParamBuffer.size(); + + return sendCommandReturningStatusAndData( + EFFECT_CMD_GET_PARAM, "GET_PARAM", + halCmdBuffer.size(), &halCmdBuffer[0], + &halParamBufferSize, &halParamBuffer[0], + sizeof(effect_param_t), + [&]{ + effect_param_t *halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]); + onSuccess(halParam->vsize, valueData); + }); +} + +Result Effect::getSupportedConfigsImpl( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + GetSupportedConfigsSuccessCallback onSuccess) { + uint32_t halCmd[2] = { featureId, maxConfigs }; + uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize); + uint8_t halResult[halResultSize]; + memset(&halResult[0], 0, halResultSize); + return sendCommandReturningStatusAndData( + EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", + sizeof(halCmd), halCmd, + &halResultSize, &halResult[0], + 2 * sizeof(uint32_t), + [&]{ + uint32_t *halResult32 = reinterpret_cast<uint32_t*>(&halResult[0]); + uint32_t supportedConfigs = *(++halResult32); // skip status field + if (supportedConfigs > maxConfigs) supportedConfigs = maxConfigs; + onSuccess(supportedConfigs, ++halResult32); + }); +} + +Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) { + status_t status; + // Create message queue. + if (mStatusMQ) { + ALOGE("the client attempts to call prepareForProcessing_cb twice"); + _hidl_cb(Result::INVALID_STATE, StatusMQ::Descriptor()); + return Void(); + } + std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1, true /*EventFlag*/)); + if (!tempStatusMQ->isValid()) { + ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid"); + _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor()); + return Void(); + } + status = EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup); + if (status != OK || !mEfGroup) { + ALOGE("failed creating event flag for status MQ: %s", strerror(-status)); + _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor()); + return Void(); + } + + // Create and launch the thread. + mProcessThread = new ProcessThread( + &mStopProcessThread, + mHandle, + &mHalInBufferPtr, + &mHalOutBufferPtr, + tempStatusMQ.get(), + mEfGroup); + status = mProcessThread->run("effect", PRIORITY_URGENT_AUDIO); + if (status != OK) { + ALOGW("failed to start effect processing thread: %s", strerror(-status)); + _hidl_cb(Result::INVALID_ARGUMENTS, MQDescriptorSync<Result>()); + return Void(); + } + + mStatusMQ = std::move(tempStatusMQ); + _hidl_cb(Result::OK, *mStatusMQ->getDesc()); + return Void(); +} + +Return<Result> Effect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + AudioBufferManager& manager = AudioBufferManager::getInstance(); + sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer; + if (!manager.wrap(inBuffer, &tempInBuffer)) { + ALOGE("Could not map memory of the input buffer"); + return Result::INVALID_ARGUMENTS; + } + if (!manager.wrap(outBuffer, &tempOutBuffer)) { + ALOGE("Could not map memory of the output buffer"); + return Result::INVALID_ARGUMENTS; + } + mInBuffer = tempInBuffer; + mOutBuffer = tempOutBuffer; + // The processing thread only reads these pointers after waking up by an event flag, + // so it's OK to update the pair non-atomically. + mHalInBufferPtr.store(mInBuffer->getHalBuffer(), std::memory_order_release); + mHalOutBufferPtr.store(mOutBuffer->getHalBuffer(), std::memory_order_release); + return Result::OK; +} + +Result Effect::sendCommand(int commandCode, const char* commandName) { + return sendCommand(commandCode, commandName, 0, NULL); +} + +Result Effect::sendCommand( + int commandCode, const char* commandName, uint32_t size, void* data) { + status_t status = (*mHandle)->command(mHandle, commandCode, size, data, 0, NULL); + return analyzeCommandStatus(commandName, sContextCallToCommand, status); +} + +Result Effect::sendCommandReturningData( + int commandCode, const char* commandName, + uint32_t* replySize, void* replyData) { + return sendCommandReturningData(commandCode, commandName, 0, NULL, replySize, replyData); +} + +Result Effect::sendCommandReturningData( + int commandCode, const char* commandName, + uint32_t size, void* data, + uint32_t* replySize, void* replyData) { + uint32_t expectedReplySize = *replySize; + status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData); + if (status == OK && *replySize != expectedReplySize) { + status = -ENODATA; + } + return analyzeCommandStatus(commandName, sContextCallToCommand, status); +} + +Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName) { + return sendCommandReturningStatus(commandCode, commandName, 0, NULL); +} + +Result Effect::sendCommandReturningStatus( + int commandCode, const char* commandName, uint32_t size, void* data) { + uint32_t replyCmdStatus; + uint32_t replySize = sizeof(uint32_t); + return sendCommandReturningStatusAndData( + commandCode, commandName, size, data, &replySize, &replyCmdStatus, replySize, []{}); +} + +Result Effect::sendCommandReturningStatusAndData( + int commandCode, const char* commandName, + uint32_t size, void* data, + uint32_t* replySize, void* replyData, + uint32_t minReplySize, + CommandSuccessCallback onSuccess) { + status_t status = + (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData); + Result retval; + if (status == OK && minReplySize >= sizeof(uint32_t) && *replySize >= minReplySize) { + uint32_t commandStatus = *reinterpret_cast<uint32_t*>(replyData); + retval = analyzeCommandStatus(commandName, sContextResultOfCommand, commandStatus); + if (commandStatus == OK) { + onSuccess(); + } + } else { + retval = analyzeCommandStatus(commandName, sContextCallToCommand, status); + } + return retval; +} + +Result Effect::setConfigImpl( + int commandCode, const char* commandName, + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + effect_config_t halConfig; + effectConfigToHal(config, &halConfig); + if (inputBufferProvider != 0) { + LOG_FATAL("Using input buffer provider is not supported"); + } + if (outputBufferProvider != 0) { + LOG_FATAL("Using output buffer provider is not supported"); + } + return sendCommandReturningStatus( + commandCode, commandName, sizeof(effect_config_t), &halConfig); +} + + +Result Effect::setParameterImpl( + uint32_t paramSize, const void* paramData, uint32_t valueSize, const void* valueData) { + std::vector<uint8_t> halParamBuffer = parameterToHal( + paramSize, paramData, valueSize, &valueData); + return sendCommandReturningStatus( + EFFECT_CMD_SET_PARAM, "SET_PARAM", halParamBuffer.size(), &halParamBuffer[0]); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> Effect::init() { + return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT"); +} + +Return<Result> Effect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return setConfigImpl( + EFFECT_CMD_SET_CONFIG, "SET_CONFIG", config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> Effect::reset() { + return sendCommand(EFFECT_CMD_RESET, "RESET"); +} + +Return<Result> Effect::enable() { + return sendCommandReturningStatus(EFFECT_CMD_ENABLE, "ENABLE"); +} + +Return<Result> Effect::disable() { + return sendCommandReturningStatus(EFFECT_CMD_DISABLE, "DISABLE"); +} + +Return<Result> Effect::setDevice(AudioDevice device) { + uint32_t halDevice = static_cast<uint32_t>(device); + return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDevice); +} + +Return<void> Effect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + uint32_t halDataSize; + std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize); + uint32_t halResultSize = halDataSize; + uint32_t halResult[volumes.size()]; + Result retval = sendCommandReturningData( + EFFECT_CMD_SET_VOLUME, "SET_VOLUME", + halDataSize, &halData[0], + &halResultSize, halResult); + hidl_vec<uint32_t> result; + if (retval == Result::OK) { + result.setToExternal(&halResult[0], halResultSize); + } + _hidl_cb(retval, result); + return Void(); +} + +Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) { + uint32_t halDataSize; + std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize); + return sendCommand( + EFFECT_CMD_SET_VOLUME, "SET_VOLUME", + halDataSize, &halData[0]); +} + +Return<Result> Effect::setAudioMode(AudioMode mode) { + uint32_t halMode = static_cast<uint32_t>(mode); + return sendCommand( + EFFECT_CMD_SET_AUDIO_MODE, "SET_AUDIO_MODE", sizeof(uint32_t), &halMode); +} + +Return<Result> Effect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return setConfigImpl(EFFECT_CMD_SET_CONFIG_REVERSE, "SET_CONFIG_REVERSE", + config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> Effect::setInputDevice(AudioDevice device) { + uint32_t halDevice = static_cast<uint32_t>(device); + return sendCommand( + EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t), &halDevice); +} + +Return<void> Effect::getConfig(getConfig_cb _hidl_cb) { + getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb); + return Void(); +} + +Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb); + return Void(); +} + +Return<void> Effect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + hidl_vec<EffectAuxChannelsConfig> result; + Result retval = getSupportedConfigsImpl( + EFFECT_FEATURE_AUX_CHANNELS, + maxConfigs, + sizeof(channel_config_t), + [&] (uint32_t supportedConfigs, void* configsData) { + result.resize(supportedConfigs); + channel_config_t *config = reinterpret_cast<channel_config_t*>(configsData); + for (size_t i = 0; i < result.size(); ++i) { + effectAuxChannelsConfigFromHal(*config++, &result[i]); + } + }); + _hidl_cb(retval, result); + return Void(); +} + +Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + uint32_t halCmd = EFFECT_FEATURE_AUX_CHANNELS; + uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))]; + memset(halResult, 0, sizeof(halResult)); + uint32_t halResultSize = 0; + EffectAuxChannelsConfig result; + Result retval = getCurrentConfigImpl( + EFFECT_FEATURE_AUX_CHANNELS, + sizeof(channel_config_t), + [&] (void* configData) { + effectAuxChannelsConfigFromHal( + *reinterpret_cast<channel_config_t*>(configData), &result); + }); + _hidl_cb(retval, result); + return Void(); +} + +Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) { + uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))]; + halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS; + effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1])); + return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, + "SET_FEATURE_CONFIG AUX_CHANNELS", sizeof(halCmd), halCmd); +} + +Return<Result> Effect::setAudioSource(AudioSource source) { + uint32_t halSource = static_cast<uint32_t>(source); + return sendCommand( + EFFECT_CMD_SET_AUDIO_SOURCE, "SET_AUDIO_SOURCE", sizeof(uint32_t), &halSource); +} + +Return<Result> Effect::offload(const EffectOffloadParameter& param) { + effect_offload_param_t halParam; + effectOffloadParamToHal(param, &halParam); + return sendCommandReturningStatus( + EFFECT_CMD_OFFLOAD, "OFFLOAD", sizeof(effect_offload_param_t), &halParam); +} + +Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) { + effect_descriptor_t halDescriptor; + memset(&halDescriptor, 0, sizeof(effect_descriptor_t)); + status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor); + EffectDescriptor descriptor; + if (status == OK) { + effectDescriptorFromHal(halDescriptor, &descriptor); + } + _hidl_cb(analyzeStatus("get_descriptor", "", sContextCallFunction, status), descriptor); + return Void(); +} + +Return<void> Effect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + uint32_t halDataSize; + std::unique_ptr<uint8_t[]> halData = hidlVecToHal(data, &halDataSize); + uint32_t halResultSize = resultMaxSize; + std::unique_ptr<uint8_t[]> halResult(new uint8_t[halResultSize]); + memset(&halResult[0], 0, halResultSize); + + void* dataPtr = halDataSize > 0 ? &halData[0] : NULL; + void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL; + status_t status = (*mHandle)->command( + mHandle, commandId, halDataSize, dataPtr, &halResultSize, resultPtr); + hidl_vec<uint8_t> result; + if (status == OK && resultPtr != NULL) { + result.setToExternal(&halResult[0], halResultSize); + } + _hidl_cb(status, result); + return Void(); +} + +Return<Result> Effect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return setParameterImpl(parameter.size(), ¶meter[0], value.size(), &value[0]); +} + +Return<void> Effect::getParameter( + const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize, getParameter_cb _hidl_cb) { + hidl_vec<uint8_t> value; + Result retval = getParameterImpl( + parameter.size(), + ¶meter[0], + valueMaxSize, + [&] (uint32_t valueSize, const void* valueData) { + value.setToExternal( + reinterpret_cast<uint8_t*>(const_cast<void*>(valueData)), valueSize); + }); + _hidl_cb(retval, value); + return Void(); +} + +Return<void> Effect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + uint32_t configCount = 0; + hidl_vec<uint8_t> result; + Result retval = getSupportedConfigsImpl( + featureId, + maxConfigs, + configSize, + [&] (uint32_t supportedConfigs, void* configsData) { + configCount = supportedConfigs; + result.resize(configCount * configSize); + memcpy(&result[0], configsData, result.size()); + }); + _hidl_cb(retval, configCount, result); + return Void(); +} + +Return<void> Effect::getCurrentConfigForFeature( + uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb) { + hidl_vec<uint8_t> result; + Result retval = getCurrentConfigImpl( + featureId, + configSize, + [&] (void* configData) { + result.resize(configSize); + memcpy(&result[0], configData, result.size()); + }); + _hidl_cb(retval, result); + return Void(); +} + +Return<Result> Effect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size())]; + memset(halCmd, 0, sizeof(halCmd)); + halCmd[0] = featureId; + memcpy(&halCmd[1], &configData[0], configData.size()); + return sendCommandReturningStatus( + EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG", sizeof(halCmd), halCmd); +} + +Return<Result> Effect::close() { + if (mIsClosed) return Result::INVALID_STATE; + mIsClosed = true; + if (mProcessThread.get()) { + mStopProcessThread.store(true, std::memory_order_release); + } + if (mEfGroup) { + mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT)); + } + return Result::OK; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/Effect.h b/audio/effect/2.0/default/Effect.h new file mode 100644 index 0000000..0918cd8 --- /dev/null +++ b/audio/effect/2.0/default/Effect.h
@@ -0,0 +1,275 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H + +#include <atomic> +#include <memory> +#include <vector> + +#include <android/hardware/audio/effect/2.0/IEffect.h> +#include <fmq/EventFlag.h> +#include <fmq/MessageQueue.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <utils/Thread.h> + +#include <hardware/audio_effect.h> + +#include "AudioBufferManager.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::common::V2_0::Uuid; +using ::android::hardware::audio::effect::V2_0::AudioBuffer; +using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig; +using ::android::hardware::audio::effect::V2_0::EffectConfig; +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; +using ::android::hardware::audio::effect::V2_0::EffectFeature; +using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter; +using ::android::hardware::audio::effect::V2_0::IEffect; +using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Effect : public IEffect { + typedef MessageQueue<Result, kSynchronizedReadWrite> StatusMQ; + using GetParameterSuccessCallback = + std::function<void(uint32_t valueSize, const void* valueData)>; + + explicit Effect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Utility methods for extending interfaces. + template<typename T> Return<void> getIntegerParam( + uint32_t paramId, std::function<void(Result retval, T paramValue)> cb) { + T value; + Result retval = getParameterImpl( + sizeof(uint32_t), ¶mId, + sizeof(T), + [&] (uint32_t valueSize, const void* valueData) { + if (valueSize > sizeof(T)) valueSize = sizeof(T); + memcpy(&value, valueData, valueSize); + }); + cb(retval, value); + return Void(); + } + + template<typename T> Result getParam(uint32_t paramId, T& paramValue) { + return getParameterImpl( + sizeof(uint32_t), ¶mId, + sizeof(T), + [&] (uint32_t valueSize, const void* valueData) { + if (valueSize > sizeof(T)) valueSize = sizeof(T); + memcpy(¶mValue, valueData, valueSize); + }); + } + + template<typename T> Result getParam(uint32_t paramId, uint32_t paramArg, T& paramValue) { + uint32_t params[2] = { paramId, paramArg }; + return getParameterImpl( + sizeof(params), params, + sizeof(T), + [&] (uint32_t valueSize, const void* valueData) { + if (valueSize > sizeof(T)) valueSize = sizeof(T); + memcpy(¶mValue, valueData, valueSize); + }); + } + + template<typename T> Result setParam(uint32_t paramId, const T& paramValue) { + return setParameterImpl(sizeof(uint32_t), ¶mId, sizeof(T), ¶mValue); + } + + template<typename T> Result setParam(uint32_t paramId, uint32_t paramArg, const T& paramValue) { + uint32_t params[2] = { paramId, paramArg }; + return setParameterImpl(sizeof(params), params, sizeof(T), ¶mValue); + } + + Result getParameterImpl( + uint32_t paramSize, + const void* paramData, + uint32_t valueSize, + GetParameterSuccessCallback onSuccess) { + return getParameterImpl(paramSize, paramData, valueSize, valueSize, onSuccess); + } + Result getParameterImpl( + uint32_t paramSize, + const void* paramData, + uint32_t requestValueSize, + uint32_t replyValueSize, + GetParameterSuccessCallback onSuccess); + Result setParameterImpl( + uint32_t paramSize, const void* paramData, uint32_t valueSize, const void* valueData); + + private: + friend struct VirtualizerEffect; // for getParameterImpl + friend struct VisualizerEffect; // to allow executing commands + + using CommandSuccessCallback = std::function<void()>; + using GetConfigCallback = std::function<void(Result retval, const EffectConfig& config)>; + using GetCurrentConfigSuccessCallback = std::function<void(void* configData)>; + using GetSupportedConfigsSuccessCallback = + std::function<void(uint32_t supportedConfigs, void* configsData)>; + + static const char *sContextResultOfCommand; + static const char *sContextCallToCommand; + static const char *sContextCallFunction; + + bool mIsClosed; + effect_handle_t mHandle; + sp<AudioBufferWrapper> mInBuffer; + sp<AudioBufferWrapper> mOutBuffer; + std::atomic<audio_buffer_t*> mHalInBufferPtr; + std::atomic<audio_buffer_t*> mHalOutBufferPtr; + std::unique_ptr<StatusMQ> mStatusMQ; + EventFlag* mEfGroup; + std::atomic<bool> mStopProcessThread; + sp<Thread> mProcessThread; + + virtual ~Effect(); + + template<typename T> static size_t alignedSizeIn(size_t s); + template<typename T> std::unique_ptr<uint8_t[]> hidlVecToHal( + const hidl_vec<T>& vec, uint32_t* halDataSize); + static void effectAuxChannelsConfigFromHal( + const channel_config_t& halConfig, EffectAuxChannelsConfig* config); + static void effectAuxChannelsConfigToHal( + const EffectAuxChannelsConfig& config, channel_config_t* halConfig); + static void effectBufferConfigFromHal( + const buffer_config_t& halConfig, EffectBufferConfig* config); + static void effectBufferConfigToHal( + const EffectBufferConfig& config, buffer_config_t* halConfig); + static void effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config); + static void effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig); + static void effectOffloadParamToHal( + const EffectOffloadParameter& offload, effect_offload_param_t* halOffload); + static std::vector<uint8_t> parameterToHal( + uint32_t paramSize, const void* paramData, uint32_t valueSize, const void** valueData); + + Result analyzeCommandStatus( + const char* commandName, const char* context, status_t status); + Result analyzeStatus( + const char* funcName, + const char* subFuncName, + const char* contextDescription, + status_t status); + void getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb); + Result getCurrentConfigImpl( + uint32_t featureId, uint32_t configSize, GetCurrentConfigSuccessCallback onSuccess); + Result getSupportedConfigsImpl( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + GetSupportedConfigsSuccessCallback onSuccess); + Result sendCommand(int commandCode, const char* commandName); + Result sendCommand(int commandCode, const char* commandName, uint32_t size, void* data); + Result sendCommandReturningData( + int commandCode, const char* commandName, uint32_t* replySize, void* replyData); + Result sendCommandReturningData( + int commandCode, const char* commandName, + uint32_t size, void* data, + uint32_t* replySize, void* replyData); + Result sendCommandReturningStatus(int commandCode, const char* commandName); + Result sendCommandReturningStatus( + int commandCode, const char* commandName, uint32_t size, void* data); + Result sendCommandReturningStatusAndData( + int commandCode, const char* commandName, + uint32_t size, void* data, + uint32_t* replySize, void* replyData, + uint32_t minReplySize, + CommandSuccessCallback onSuccess); + Result setConfigImpl( + int commandCode, const char* commandName, + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H
diff --git a/audio/effect/2.0/default/EffectsFactory.cpp b/audio/effect/2.0/default/EffectsFactory.cpp new file mode 100644 index 0000000..08d92bd --- /dev/null +++ b/audio/effect/2.0/default/EffectsFactory.cpp
@@ -0,0 +1,205 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "EffectFactoryHAL" +#include <media/EffectsFactoryApi.h> +#include <system/audio_effects/effect_aec.h> +#include <system/audio_effects/effect_agc.h> +#include <system/audio_effects/effect_bassboost.h> +#include <system/audio_effects/effect_downmix.h> +#include <system/audio_effects/effect_environmentalreverb.h> +#include <system/audio_effects/effect_equalizer.h> +#include <system/audio_effects/effect_loudnessenhancer.h> +#include <system/audio_effects/effect_ns.h> +#include <system/audio_effects/effect_presetreverb.h> +#include <system/audio_effects/effect_virtualizer.h> +#include <system/audio_effects/effect_visualizer.h> +#include <android/log.h> + +#include "AcousticEchoCancelerEffect.h" +#include "AutomaticGainControlEffect.h" +#include "BassBoostEffect.h" +#include "Conversions.h" +#include "DownmixEffect.h" +#include "EffectsFactory.h" +#include "HidlUtils.h" +#include "Effect.h" +#include "EffectMap.h" +#include "EnvironmentalReverbEffect.h" +#include "EqualizerEffect.h" +#include "LoudnessEnhancerEffect.h" +#include "NoiseSuppressionEffect.h" +#include "PresetReverbEffect.h" +#include "VirtualizerEffect.h" +#include "VisualizerEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +// static +sp<IEffect> EffectsFactory::dispatchEffectInstanceCreation( + const effect_descriptor_t& halDescriptor, effect_handle_t handle) { + const effect_uuid_t *halUuid = &halDescriptor.type; + if (memcmp(halUuid, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) { + return new AcousticEchoCancelerEffect(handle); + } else if (memcmp(halUuid, FX_IID_AGC, sizeof(effect_uuid_t)) == 0) { + return new AutomaticGainControlEffect(handle); + } else if (memcmp(halUuid, SL_IID_BASSBOOST, sizeof(effect_uuid_t)) == 0) { + return new BassBoostEffect(handle); + } else if (memcmp(halUuid, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) { + return new DownmixEffect(handle); + } else if (memcmp(halUuid, SL_IID_ENVIRONMENTALREVERB, sizeof(effect_uuid_t)) == 0) { + return new EnvironmentalReverbEffect(handle); + } else if (memcmp(halUuid, SL_IID_EQUALIZER, sizeof(effect_uuid_t)) == 0) { + return new EqualizerEffect(handle); + } else if (memcmp(halUuid, FX_IID_LOUDNESS_ENHANCER, sizeof(effect_uuid_t)) == 0) { + return new LoudnessEnhancerEffect(handle); + } else if (memcmp(halUuid, FX_IID_NS, sizeof(effect_uuid_t)) == 0) { + return new NoiseSuppressionEffect(handle); + } else if (memcmp(halUuid, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) { + return new PresetReverbEffect(handle); + } else if (memcmp(halUuid, SL_IID_VIRTUALIZER, sizeof(effect_uuid_t)) == 0) { + return new VirtualizerEffect(handle); + } else if (memcmp(halUuid, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) { + return new VisualizerEffect(handle); + } + return new Effect(handle); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffectsFactory follow. +Return<void> EffectsFactory::getAllDescriptors(getAllDescriptors_cb _hidl_cb) { + Result retval(Result::OK); + hidl_vec<EffectDescriptor> result; + uint32_t numEffects; + status_t status; + +restart: + numEffects = 0; + status = EffectQueryNumberEffects(&numEffects); + if (status != OK) { + retval = Result::NOT_INITIALIZED; + ALOGE("Error querying number of effects: %s", strerror(-status)); + goto exit; + } + result.resize(numEffects); + for (uint32_t i = 0; i < numEffects; ++i) { + effect_descriptor_t halDescriptor; + status = EffectQueryEffect(i, &halDescriptor); + if (status == OK) { + effectDescriptorFromHal(halDescriptor, &result[i]); + } else { + ALOGE("Error querying effect at position %d / %d: %s", + i, numEffects, strerror(-status)); + switch (status) { + case -ENOSYS: { + // Effect list has changed. + goto restart; + } + case -ENOENT: { + // No more effects available. + result.resize(i); + } + default: { + result.resize(0); + retval = Result::NOT_INITIALIZED; + } + } + break; + } + } + +exit: + _hidl_cb(retval, result); + return Void(); +} + +Return<void> EffectsFactory::getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) { + effect_uuid_t halUuid; + HidlUtils::uuidToHal(uid, &halUuid); + effect_descriptor_t halDescriptor; + status_t status = EffectGetDescriptor(&halUuid, &halDescriptor); + EffectDescriptor descriptor; + effectDescriptorFromHal(halDescriptor, &descriptor); + Result retval(Result::OK); + if (status != OK) { + ALOGE("Error querying effect descriptor for %s: %s", + uuidToString(halUuid).c_str(), strerror(-status)); + if (status == -ENOENT) { + retval = Result::INVALID_ARGUMENTS; + } else { + retval = Result::NOT_INITIALIZED; + } + } + _hidl_cb(retval, descriptor); + return Void(); +} + +Return<void> EffectsFactory::createEffect( + const Uuid& uid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb) { + effect_uuid_t halUuid; + HidlUtils::uuidToHal(uid, &halUuid); + effect_handle_t handle; + Result retval(Result::OK); + status_t status = EffectCreate(&halUuid, session, ioHandle, &handle); + sp<IEffect> effect; + uint64_t effectId = EffectMap::INVALID_ID; + if (status == OK) { + effect_descriptor_t halDescriptor; + memset(&halDescriptor, 0, sizeof(effect_descriptor_t)); + status = (*handle)->get_descriptor(handle, &halDescriptor); + if (status == OK) { + effect = dispatchEffectInstanceCreation(halDescriptor, handle); + effectId = EffectMap::getInstance().add(handle); + } else { + ALOGE("Error querying effect descriptor for %s: %s", + uuidToString(halUuid).c_str(), strerror(-status)); + EffectRelease(handle); + } + } + if (status != OK) { + ALOGE("Error creating effect %s: %s", uuidToString(halUuid).c_str(), strerror(-status)); + if (status == -ENOENT) { + retval = Result::INVALID_ARGUMENTS; + } else { + retval = Result::NOT_INITIALIZED; + } + } + _hidl_cb(retval, effect, effectId); + return Void(); +} + +Return<void> EffectsFactory::debugDump(const hidl_handle& fd) { + if (fd->numFds == 1) { + EffectDumpEffects(fd->data[0]); + } + return Void(); +} + + +IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* /* name */) { + return new EffectsFactory(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/EffectsFactory.h b/audio/effect/2.0/default/EffectsFactory.h new file mode 100644 index 0000000..829a534 --- /dev/null +++ b/audio/effect/2.0/default/EffectsFactory.h
@@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H + +#include <system/audio_effect.h> + +#include <android/hardware/audio/effect/2.0/IEffectsFactory.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::Uuid; +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; +using ::android::hardware::audio::effect::V2_0::IEffect; +using ::android::hardware::audio::effect::V2_0::IEffectsFactory; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct EffectsFactory : public IEffectsFactory { + // Methods from ::android::hardware::audio::effect::V2_0::IEffectsFactory follow. + Return<void> getAllDescriptors(getAllDescriptors_cb _hidl_cb) override; + Return<void> getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) override; + Return<void> createEffect( + const Uuid& uid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb) override; + Return<void> debugDump(const hidl_handle& fd) override; + + private: + static sp<IEffect> dispatchEffectInstanceCreation( + const effect_descriptor_t& halDescriptor, effect_handle_t handle); +}; + +extern "C" IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name); + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H
diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp b/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp new file mode 100644 index 0000000..86ff368 --- /dev/null +++ b/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp
@@ -0,0 +1,316 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "EnvReverb_HAL" +#include <android/log.h> + +#include "EnvironmentalReverbEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +EnvironmentalReverbEffect::EnvironmentalReverbEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +EnvironmentalReverbEffect::~EnvironmentalReverbEffect() {} + +void EnvironmentalReverbEffect::propertiesFromHal( + const t_reverb_settings& halProperties, + IEnvironmentalReverbEffect::AllProperties* properties) { + properties->roomLevel = halProperties.roomLevel; + properties->roomHfLevel = halProperties.roomHFLevel; + properties->decayTime = halProperties.decayTime; + properties->decayHfRatio = halProperties.decayHFRatio; + properties->reflectionsLevel = halProperties.reflectionsLevel; + properties->reflectionsDelay = halProperties.reflectionsDelay; + properties->reverbLevel = halProperties.reverbLevel; + properties->reverbDelay = halProperties.reverbDelay; + properties->diffusion = halProperties.diffusion; + properties->density = halProperties.density; +} + +void EnvironmentalReverbEffect::propertiesToHal( + const IEnvironmentalReverbEffect::AllProperties& properties, + t_reverb_settings* halProperties) { + halProperties->roomLevel = properties.roomLevel; + halProperties->roomHFLevel = properties.roomHfLevel; + halProperties->decayTime = properties.decayTime; + halProperties->decayHFRatio = properties.decayHfRatio; + halProperties->reflectionsLevel = properties.reflectionsLevel; + halProperties->reflectionsDelay = properties.reflectionsDelay; + halProperties->reverbLevel = properties.reverbLevel; + halProperties->reverbDelay = properties.reverbDelay; + halProperties->diffusion = properties.diffusion; + halProperties->density = properties.density; +} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> EnvironmentalReverbEffect::init() { + return mEffect->init(); +} + +Return<Result> EnvironmentalReverbEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> EnvironmentalReverbEffect::reset() { + return mEffect->reset(); +} + +Return<Result> EnvironmentalReverbEffect::enable() { + return mEffect->enable(); +} + +Return<Result> EnvironmentalReverbEffect::disable() { + return mEffect->disable(); +} + +Return<Result> EnvironmentalReverbEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> EnvironmentalReverbEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> EnvironmentalReverbEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> EnvironmentalReverbEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> EnvironmentalReverbEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> EnvironmentalReverbEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> EnvironmentalReverbEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> EnvironmentalReverbEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> EnvironmentalReverbEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> EnvironmentalReverbEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> EnvironmentalReverbEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> EnvironmentalReverbEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> EnvironmentalReverbEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> EnvironmentalReverbEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> EnvironmentalReverbEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> EnvironmentalReverbEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> EnvironmentalReverbEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> EnvironmentalReverbEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect follow. +Return<Result> EnvironmentalReverbEffect::setBypass(bool bypass) { + return mEffect->setParam(REVERB_PARAM_BYPASS, bypass); +} + +Return<void> EnvironmentalReverbEffect::getBypass(getBypass_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_BYPASS, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setRoomLevel(int16_t roomLevel) { + return mEffect->setParam(REVERB_PARAM_ROOM_LEVEL, roomLevel); +} + +Return<void> EnvironmentalReverbEffect::getRoomLevel(getRoomLevel_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_ROOM_LEVEL, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setRoomHfLevel(int16_t roomHfLevel) { + return mEffect->setParam(REVERB_PARAM_ROOM_HF_LEVEL, roomHfLevel); +} + +Return<void> EnvironmentalReverbEffect::getRoomHfLevel(getRoomHfLevel_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_ROOM_HF_LEVEL, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setDecayTime(uint32_t decayTime) { + return mEffect->setParam(REVERB_PARAM_DECAY_TIME, decayTime); +} + +Return<void> EnvironmentalReverbEffect::getDecayTime(getDecayTime_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_DECAY_TIME, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setDecayHfRatio(int16_t decayHfRatio) { + return mEffect->setParam(REVERB_PARAM_DECAY_HF_RATIO, decayHfRatio); +} + +Return<void> EnvironmentalReverbEffect::getDecayHfRatio(getDecayHfRatio_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_DECAY_HF_RATIO, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setReflectionsLevel(int16_t reflectionsLevel) { + return mEffect->setParam(REVERB_PARAM_REFLECTIONS_LEVEL, reflectionsLevel); +} + +Return<void> EnvironmentalReverbEffect::getReflectionsLevel(getReflectionsLevel_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_REFLECTIONS_LEVEL, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setReflectionsDelay(uint32_t reflectionsDelay) { + return mEffect->setParam(REVERB_PARAM_REFLECTIONS_DELAY, reflectionsDelay); +} + +Return<void> EnvironmentalReverbEffect::getReflectionsDelay(getReflectionsDelay_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_REFLECTIONS_DELAY, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setReverbLevel(int16_t reverbLevel) { + return mEffect->setParam(REVERB_PARAM_REVERB_LEVEL, reverbLevel); +} + +Return<void> EnvironmentalReverbEffect::getReverbLevel(getReverbLevel_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_REVERB_LEVEL, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setReverbDelay(uint32_t reverbDelay) { + return mEffect->setParam(REVERB_PARAM_REVERB_DELAY, reverbDelay); +} + +Return<void> EnvironmentalReverbEffect::getReverbDelay(getReverbDelay_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_REVERB_DELAY, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setDiffusion(int16_t diffusion) { + return mEffect->setParam(REVERB_PARAM_DIFFUSION, diffusion); +} + +Return<void> EnvironmentalReverbEffect::getDiffusion(getDiffusion_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_DIFFUSION, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setDensity(int16_t density) { + return mEffect->setParam(REVERB_PARAM_DENSITY, density); +} + +Return<void> EnvironmentalReverbEffect::getDensity(getDensity_cb _hidl_cb) { + return mEffect->getIntegerParam(REVERB_PARAM_DENSITY, _hidl_cb); +} + +Return<Result> EnvironmentalReverbEffect::setAllProperties( + const IEnvironmentalReverbEffect::AllProperties& properties) { + t_reverb_settings halProperties; + propertiesToHal(properties, &halProperties); + return mEffect->setParam(REVERB_PARAM_PROPERTIES, halProperties); +} + +Return<void> EnvironmentalReverbEffect::getAllProperties(getAllProperties_cb _hidl_cb) { + t_reverb_settings halProperties; + Result retval = mEffect->getParam(REVERB_PARAM_PROPERTIES, halProperties); + AllProperties properties; + propertiesFromHal(halProperties, &properties); + _hidl_cb(retval, properties); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.h b/audio/effect/2.0/default/EnvironmentalReverbEffect.h new file mode 100644 index 0000000..794caac --- /dev/null +++ b/audio/effect/2.0/default/EnvironmentalReverbEffect.h
@@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H + +#include <system/audio_effects/effect_environmentalreverb.h> + +#include <android/hardware/audio/effect/2.0/IEnvironmentalReverbEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::effect::V2_0::AudioBuffer; +using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig; +using ::android::hardware::audio::effect::V2_0::EffectConfig; +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; +using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter; +using ::android::hardware::audio::effect::V2_0::IEffect; +using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback; +using ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct EnvironmentalReverbEffect : public IEnvironmentalReverbEffect { + explicit EnvironmentalReverbEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect follow. + Return<Result> setBypass(bool bypass) override; + Return<void> getBypass(getBypass_cb _hidl_cb) override; + Return<Result> setRoomLevel(int16_t roomLevel) override; + Return<void> getRoomLevel(getRoomLevel_cb _hidl_cb) override; + Return<Result> setRoomHfLevel(int16_t roomHfLevel) override; + Return<void> getRoomHfLevel(getRoomHfLevel_cb _hidl_cb) override; + Return<Result> setDecayTime(uint32_t decayTime) override; + Return<void> getDecayTime(getDecayTime_cb _hidl_cb) override; + Return<Result> setDecayHfRatio(int16_t decayHfRatio) override; + Return<void> getDecayHfRatio(getDecayHfRatio_cb _hidl_cb) override; + Return<Result> setReflectionsLevel(int16_t reflectionsLevel) override; + Return<void> getReflectionsLevel(getReflectionsLevel_cb _hidl_cb) override; + Return<Result> setReflectionsDelay(uint32_t reflectionsDelay) override; + Return<void> getReflectionsDelay(getReflectionsDelay_cb _hidl_cb) override; + Return<Result> setReverbLevel(int16_t reverbLevel) override; + Return<void> getReverbLevel(getReverbLevel_cb _hidl_cb) override; + Return<Result> setReverbDelay(uint32_t reverbDelay) override; + Return<void> getReverbDelay(getReverbDelay_cb _hidl_cb) override; + Return<Result> setDiffusion(int16_t diffusion) override; + Return<void> getDiffusion(getDiffusion_cb _hidl_cb) override; + Return<Result> setDensity(int16_t density) override; + Return<void> getDensity(getDensity_cb _hidl_cb) override; + Return<Result> setAllProperties( + const IEnvironmentalReverbEffect::AllProperties& properties) override; + Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~EnvironmentalReverbEffect(); + + void propertiesFromHal( + const t_reverb_settings& halProperties, + IEnvironmentalReverbEffect::AllProperties* properties); + void propertiesToHal( + const IEnvironmentalReverbEffect::AllProperties& properties, + t_reverb_settings* halProperties); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H
diff --git a/audio/effect/2.0/default/EqualizerEffect.cpp b/audio/effect/2.0/default/EqualizerEffect.cpp new file mode 100644 index 0000000..808d8eb --- /dev/null +++ b/audio/effect/2.0/default/EqualizerEffect.cpp
@@ -0,0 +1,311 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <memory.h> + +#define LOG_TAG "Equalizer_HAL" +#include <android/log.h> + +#include "EqualizerEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +EqualizerEffect::EqualizerEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +EqualizerEffect::~EqualizerEffect() {} + +void EqualizerEffect::propertiesFromHal( + const t_equalizer_settings& halProperties, + IEqualizerEffect::AllProperties* properties) { + properties->curPreset = halProperties.curPreset; + // t_equalizer_settings incorrectly defines bandLevels as uint16_t, + // whereas the actual type of values used by effects is int16_t. + const int16_t* signedBandLevels = + reinterpret_cast<const int16_t*>(&halProperties.bandLevels[0]); + properties->bandLevels.setToExternal( + const_cast<int16_t*>(signedBandLevels), halProperties.numBands); +} + +std::vector<uint8_t> EqualizerEffect::propertiesToHal( + const IEqualizerEffect::AllProperties& properties, + t_equalizer_settings** halProperties) { + size_t bandsSize = properties.bandLevels.size() * sizeof(uint16_t); + std::vector<uint8_t> halBuffer(sizeof(t_equalizer_settings) + bandsSize, 0); + *halProperties = reinterpret_cast<t_equalizer_settings*>(&halBuffer[0]); + (*halProperties)->curPreset = properties.curPreset; + (*halProperties)->numBands = properties.bandLevels.size(); + memcpy((*halProperties)->bandLevels, &properties.bandLevels[0], bandsSize); + return halBuffer; +} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> EqualizerEffect::init() { + return mEffect->init(); +} + +Return<Result> EqualizerEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> EqualizerEffect::reset() { + return mEffect->reset(); +} + +Return<Result> EqualizerEffect::enable() { + return mEffect->enable(); +} + +Return<Result> EqualizerEffect::disable() { + return mEffect->disable(); +} + +Return<Result> EqualizerEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> EqualizerEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> EqualizerEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> EqualizerEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> EqualizerEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> EqualizerEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> EqualizerEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> EqualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> EqualizerEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> EqualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> EqualizerEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> EqualizerEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> EqualizerEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> EqualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> EqualizerEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> EqualizerEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> EqualizerEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> EqualizerEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> EqualizerEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> EqualizerEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> EqualizerEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> EqualizerEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> EqualizerEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IEqualizerEffect follow. +Return<void> EqualizerEffect::getNumBands(getNumBands_cb _hidl_cb) { + return mEffect->getIntegerParam(EQ_PARAM_NUM_BANDS, _hidl_cb); +} + +Return<void> EqualizerEffect::getLevelRange(getLevelRange_cb _hidl_cb) { + int16_t halLevels[2] = { 0, 0 }; + Result retval = mEffect->getParam(EQ_PARAM_LEVEL_RANGE, halLevels); + _hidl_cb(retval, halLevels[0], halLevels[1]); + return Void(); +} + +Return<Result> EqualizerEffect::setBandLevel(uint16_t band, int16_t level) { + return mEffect->setParam(EQ_PARAM_BAND_LEVEL, band, level); +} + +Return<void> EqualizerEffect::getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) { + int16_t halLevel = 0; + Result retval = mEffect->getParam(EQ_PARAM_BAND_LEVEL, band, halLevel); + _hidl_cb(retval, halLevel); + return Void(); +} + +Return<void> EqualizerEffect::getBandCenterFrequency( + uint16_t band, getBandCenterFrequency_cb _hidl_cb) { + uint32_t halFreq = 0; + Result retval = mEffect->getParam(EQ_PARAM_CENTER_FREQ, band, halFreq); + _hidl_cb(retval, halFreq); + return Void(); +} + +Return<void> EqualizerEffect::getBandFrequencyRange( + uint16_t band, getBandFrequencyRange_cb _hidl_cb) { + uint32_t halFreqs[2] = { 0, 0 }; + Result retval = mEffect->getParam(EQ_PARAM_BAND_FREQ_RANGE, band, halFreqs); + _hidl_cb(retval, halFreqs[0], halFreqs[1]); + return Void(); +} + +Return<void> EqualizerEffect::getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb) { + uint16_t halBand = 0; + Result retval = mEffect->getParam(EQ_PARAM_GET_BAND, freq, halBand); + _hidl_cb(retval, halBand); + return Void(); +} + +Return<void> EqualizerEffect::getPresetNames(getPresetNames_cb _hidl_cb) { + uint16_t halPresetCount = 0; + Result retval = mEffect->getParam(EQ_PARAM_GET_NUM_OF_PRESETS, halPresetCount); + hidl_vec<hidl_string> presetNames; + if (retval == Result::OK) { + presetNames.resize(halPresetCount); + for (uint16_t i = 0; i < halPresetCount; ++i) { + char halPresetName[EFFECT_STRING_LEN_MAX]; + retval = mEffect->getParam(EQ_PARAM_GET_PRESET_NAME, i, halPresetName); + if (retval == Result::OK) { + presetNames[i] = halPresetName; + } else { + presetNames.resize(i); + } + } + } + _hidl_cb(retval, presetNames); + return Void(); +} + +Return<Result> EqualizerEffect::setCurrentPreset(uint16_t preset) { + return mEffect->setParam(EQ_PARAM_CUR_PRESET, preset); +} + +Return<void> EqualizerEffect::getCurrentPreset(getCurrentPreset_cb _hidl_cb) { + return mEffect->getIntegerParam(EQ_PARAM_CUR_PRESET, _hidl_cb); +} + +Return<Result> EqualizerEffect::setAllProperties( + const IEqualizerEffect::AllProperties& properties) { + t_equalizer_settings *halPropertiesPtr = nullptr; + std::vector<uint8_t> halBuffer = propertiesToHal(properties, &halPropertiesPtr); + uint32_t paramId = EQ_PARAM_PROPERTIES; + return mEffect->setParameterImpl( + sizeof(paramId), ¶mId, halBuffer.size(), halPropertiesPtr); +} + +Return<void> EqualizerEffect::getAllProperties(getAllProperties_cb _hidl_cb) { + uint16_t numBands = 0; + Result retval = mEffect->getParam(EQ_PARAM_NUM_BANDS, numBands); + AllProperties properties; + if (retval != Result::OK) { + _hidl_cb(retval, properties); + return Void(); + } + size_t valueSize = sizeof(t_equalizer_settings) + sizeof(int16_t) * numBands; + uint32_t paramId = EQ_PARAM_PROPERTIES; + retval = mEffect->getParameterImpl( + sizeof(paramId), ¶mId, valueSize, + [&] (uint32_t, const void* valueData) { + const t_equalizer_settings* halProperties = + reinterpret_cast<const t_equalizer_settings*>(valueData); + propertiesFromHal(*halProperties, &properties); + }); + _hidl_cb(retval, properties); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/EqualizerEffect.h b/audio/effect/2.0/default/EqualizerEffect.h new file mode 100644 index 0000000..9e8d75b --- /dev/null +++ b/audio/effect/2.0/default/EqualizerEffect.h
@@ -0,0 +1,149 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H + +#include <vector> + +#include <system/audio_effects/effect_equalizer.h> + +#include <android/hardware/audio/effect/2.0/IEqualizerEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::effect::V2_0::AudioBuffer; +using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig; +using ::android::hardware::audio::effect::V2_0::EffectConfig; +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; +using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter; +using ::android::hardware::audio::effect::V2_0::IEffect; +using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback; +using ::android::hardware::audio::effect::V2_0::IEqualizerEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct EqualizerEffect : public IEqualizerEffect { + explicit EqualizerEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::IEqualizerEffect follow. + Return<void> getNumBands(getNumBands_cb _hidl_cb) override; + Return<void> getLevelRange(getLevelRange_cb _hidl_cb) override; + Return<Result> setBandLevel(uint16_t band, int16_t level) override; + Return<void> getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) override; + Return<void> getBandCenterFrequency( + uint16_t band, getBandCenterFrequency_cb _hidl_cb) override; + Return<void> getBandFrequencyRange(uint16_t band, getBandFrequencyRange_cb _hidl_cb) override; + Return<void> getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb) override; + Return<void> getPresetNames(getPresetNames_cb _hidl_cb) override; + Return<Result> setCurrentPreset(uint16_t preset) override; + Return<void> getCurrentPreset(getCurrentPreset_cb _hidl_cb) override; + Return<Result> setAllProperties(const IEqualizerEffect::AllProperties& properties) override; + Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~EqualizerEffect(); + + void propertiesFromHal( + const t_equalizer_settings& halProperties, + IEqualizerEffect::AllProperties* properties); + std::vector<uint8_t> propertiesToHal( + const IEqualizerEffect::AllProperties& properties, + t_equalizer_settings** halProperties); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H
diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp new file mode 100644 index 0000000..fda5eb0 --- /dev/null +++ b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
@@ -0,0 +1,204 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <system/audio_effects/effect_loudnessenhancer.h> + +#define LOG_TAG "LoudnessEnhancer_HAL" +#include <system/audio_effects/effect_aec.h> +#include <android/log.h> + +#include "LoudnessEnhancerEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +LoudnessEnhancerEffect::LoudnessEnhancerEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +LoudnessEnhancerEffect::~LoudnessEnhancerEffect() {} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> LoudnessEnhancerEffect::init() { + return mEffect->init(); +} + +Return<Result> LoudnessEnhancerEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> LoudnessEnhancerEffect::reset() { + return mEffect->reset(); +} + +Return<Result> LoudnessEnhancerEffect::enable() { + return mEffect->enable(); +} + +Return<Result> LoudnessEnhancerEffect::disable() { + return mEffect->disable(); +} + +Return<Result> LoudnessEnhancerEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> LoudnessEnhancerEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> LoudnessEnhancerEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> LoudnessEnhancerEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> LoudnessEnhancerEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> LoudnessEnhancerEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> LoudnessEnhancerEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> LoudnessEnhancerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> LoudnessEnhancerEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> LoudnessEnhancerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> LoudnessEnhancerEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> LoudnessEnhancerEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> LoudnessEnhancerEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> LoudnessEnhancerEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> LoudnessEnhancerEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> LoudnessEnhancerEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> LoudnessEnhancerEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> LoudnessEnhancerEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> LoudnessEnhancerEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> LoudnessEnhancerEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> LoudnessEnhancerEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> LoudnessEnhancerEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> LoudnessEnhancerEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect follow. +Return<Result> LoudnessEnhancerEffect::setTargetGain(int32_t targetGainMb) { + return mEffect->setParam(LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB, targetGainMb); +} + +Return<void> LoudnessEnhancerEffect::getTargetGain(getTargetGain_cb _hidl_cb) { + // AOSP Loudness Enhancer expects the size of the request to not include the + // size of the parameter. + uint32_t paramId = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB; + uint32_t targetGainMb = 0; + Result retval = mEffect->getParameterImpl( + sizeof(paramId), ¶mId, + 0, sizeof(targetGainMb), + [&] (uint32_t, const void* valueData) { + memcpy(&targetGainMb, valueData, sizeof(targetGainMb)); + }); + _hidl_cb(retval, targetGainMb); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.h b/audio/effect/2.0/default/LoudnessEnhancerEffect.h new file mode 100644 index 0000000..039b8d6 --- /dev/null +++ b/audio/effect/2.0/default/LoudnessEnhancerEffect.h
@@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H + +#include <android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::effect::V2_0::AudioBuffer; +using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig; +using ::android::hardware::audio::effect::V2_0::EffectConfig; +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; +using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter; +using ::android::hardware::audio::effect::V2_0::IEffect; +using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback; +using ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct LoudnessEnhancerEffect : public ILoudnessEnhancerEffect { + explicit LoudnessEnhancerEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect follow. + Return<Result> setTargetGain(int32_t targetGainMb) override; + Return<void> getTargetGain(getTargetGain_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~LoudnessEnhancerEffect(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H
diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.cpp b/audio/effect/2.0/default/NoiseSuppressionEffect.cpp new file mode 100644 index 0000000..7c4e06d --- /dev/null +++ b/audio/effect/2.0/default/NoiseSuppressionEffect.cpp
@@ -0,0 +1,234 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "NS_Effect_HAL" +#include <android/log.h> + +#include "NoiseSuppressionEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +NoiseSuppressionEffect::NoiseSuppressionEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +NoiseSuppressionEffect::~NoiseSuppressionEffect() {} + +void NoiseSuppressionEffect::propertiesFromHal( + const t_ns_settings& halProperties, + INoiseSuppressionEffect::AllProperties* properties) { + properties->level = Level(halProperties.level); + properties->type = Type(halProperties.type); +} + +void NoiseSuppressionEffect::propertiesToHal( + const INoiseSuppressionEffect::AllProperties& properties, + t_ns_settings* halProperties) { + halProperties->level = static_cast<uint32_t>(properties.level); + halProperties->type = static_cast<uint32_t>(properties.type); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> NoiseSuppressionEffect::init() { + return mEffect->init(); +} + +Return<Result> NoiseSuppressionEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> NoiseSuppressionEffect::reset() { + return mEffect->reset(); +} + +Return<Result> NoiseSuppressionEffect::enable() { + return mEffect->enable(); +} + +Return<Result> NoiseSuppressionEffect::disable() { + return mEffect->disable(); +} + +Return<Result> NoiseSuppressionEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> NoiseSuppressionEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> NoiseSuppressionEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> NoiseSuppressionEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> NoiseSuppressionEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> NoiseSuppressionEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> NoiseSuppressionEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> NoiseSuppressionEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> NoiseSuppressionEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> NoiseSuppressionEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> NoiseSuppressionEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> NoiseSuppressionEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> NoiseSuppressionEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> NoiseSuppressionEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> NoiseSuppressionEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> NoiseSuppressionEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> NoiseSuppressionEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> NoiseSuppressionEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> NoiseSuppressionEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> NoiseSuppressionEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> NoiseSuppressionEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> NoiseSuppressionEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> NoiseSuppressionEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect follow. +Return<Result> NoiseSuppressionEffect::setSuppressionLevel(INoiseSuppressionEffect::Level level) { + return mEffect->setParam(NS_PARAM_LEVEL, static_cast<int32_t>(level)); +} + +Return<void> NoiseSuppressionEffect::getSuppressionLevel(getSuppressionLevel_cb _hidl_cb) { + int32_t halLevel = 0; + Result retval = mEffect->getParam(NS_PARAM_LEVEL, halLevel); + _hidl_cb(retval, Level(halLevel)); + return Void(); +} + +Return<Result> NoiseSuppressionEffect::setSuppressionType(INoiseSuppressionEffect::Type type) { + return mEffect->setParam(NS_PARAM_TYPE, static_cast<int32_t>(type)); +} + +Return<void> NoiseSuppressionEffect::getSuppressionType(getSuppressionType_cb _hidl_cb) { + int32_t halType = 0; + Result retval = mEffect->getParam(NS_PARAM_TYPE, halType); + _hidl_cb(retval, Type(halType)); + return Void(); +} + +Return<Result> NoiseSuppressionEffect::setAllProperties( + const INoiseSuppressionEffect::AllProperties& properties) { + t_ns_settings halProperties; + propertiesToHal(properties, &halProperties); + return mEffect->setParam(NS_PARAM_PROPERTIES, halProperties); +} + +Return<void> NoiseSuppressionEffect::getAllProperties(getAllProperties_cb _hidl_cb) { + t_ns_settings halProperties; + Result retval = mEffect->getParam(NS_PARAM_PROPERTIES, halProperties); + AllProperties properties; + propertiesFromHal(halProperties, &properties); + _hidl_cb(retval, properties); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.h b/audio/effect/2.0/default/NoiseSuppressionEffect.h new file mode 100644 index 0000000..5491201 --- /dev/null +++ b/audio/effect/2.0/default/NoiseSuppressionEffect.h
@@ -0,0 +1,141 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H + +#include <system/audio_effects/effect_ns.h> + +#include <android/hardware/audio/effect/2.0/INoiseSuppressionEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::effect::V2_0::AudioBuffer; +using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig; +using ::android::hardware::audio::effect::V2_0::EffectConfig; +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; +using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter; +using ::android::hardware::audio::effect::V2_0::IEffect; +using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback; +using ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct NoiseSuppressionEffect : public INoiseSuppressionEffect { + explicit NoiseSuppressionEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect follow. + Return<Result> setSuppressionLevel(INoiseSuppressionEffect::Level level) override; + Return<void> getSuppressionLevel(getSuppressionLevel_cb _hidl_cb) override; + Return<Result> setSuppressionType(INoiseSuppressionEffect::Type type) override; + Return<void> getSuppressionType(getSuppressionType_cb _hidl_cb) override; + Return<Result> setAllProperties( + const INoiseSuppressionEffect::AllProperties& properties) override; + Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~NoiseSuppressionEffect(); + + void propertiesFromHal( + const t_ns_settings& halProperties, + INoiseSuppressionEffect::AllProperties* properties); + void propertiesToHal( + const INoiseSuppressionEffect::AllProperties& properties, + t_ns_settings* halProperties); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H
diff --git a/audio/effect/2.0/default/PresetReverbEffect.cpp b/audio/effect/2.0/default/PresetReverbEffect.cpp new file mode 100644 index 0000000..5f17791 --- /dev/null +++ b/audio/effect/2.0/default/PresetReverbEffect.cpp
@@ -0,0 +1,194 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "PresetReverb_HAL" +#include <system/audio_effects/effect_presetreverb.h> +#include <android/log.h> + +#include "PresetReverbEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +PresetReverbEffect::PresetReverbEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +PresetReverbEffect::~PresetReverbEffect() {} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> PresetReverbEffect::init() { + return mEffect->init(); +} + +Return<Result> PresetReverbEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> PresetReverbEffect::reset() { + return mEffect->reset(); +} + +Return<Result> PresetReverbEffect::enable() { + return mEffect->enable(); +} + +Return<Result> PresetReverbEffect::disable() { + return mEffect->disable(); +} + +Return<Result> PresetReverbEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> PresetReverbEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> PresetReverbEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> PresetReverbEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> PresetReverbEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> PresetReverbEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> PresetReverbEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> PresetReverbEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> PresetReverbEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> PresetReverbEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> PresetReverbEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> PresetReverbEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> PresetReverbEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> PresetReverbEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> PresetReverbEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> PresetReverbEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> PresetReverbEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> PresetReverbEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> PresetReverbEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> PresetReverbEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> PresetReverbEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> PresetReverbEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> PresetReverbEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IPresetReverbEffect follow. +Return<Result> PresetReverbEffect::setPreset(IPresetReverbEffect::Preset preset) { + return mEffect->setParam(REVERB_PARAM_PRESET, static_cast<t_reverb_presets>(preset)); +} + +Return<void> PresetReverbEffect::getPreset(getPreset_cb _hidl_cb) { + t_reverb_presets halPreset = REVERB_PRESET_NONE; + Result retval = mEffect->getParam(REVERB_PARAM_PRESET, halPreset); + _hidl_cb(retval, Preset(halPreset)); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/PresetReverbEffect.h b/audio/effect/2.0/default/PresetReverbEffect.h new file mode 100644 index 0000000..4eb074a --- /dev/null +++ b/audio/effect/2.0/default/PresetReverbEffect.h
@@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H + +#include <android/hardware/audio/effect/2.0/IPresetReverbEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::effect::V2_0::AudioBuffer; +using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig; +using ::android::hardware::audio::effect::V2_0::EffectConfig; +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; +using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter; +using ::android::hardware::audio::effect::V2_0::IEffect; +using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback; +using ::android::hardware::audio::effect::V2_0::IPresetReverbEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct PresetReverbEffect : public IPresetReverbEffect { + explicit PresetReverbEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::IPresetReverbEffect follow. + Return<Result> setPreset(IPresetReverbEffect::Preset preset) override; + Return<void> getPreset(getPreset_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~PresetReverbEffect(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H
diff --git a/audio/effect/2.0/default/VirtualizerEffect.cpp b/audio/effect/2.0/default/VirtualizerEffect.cpp new file mode 100644 index 0000000..c1fe52f --- /dev/null +++ b/audio/effect/2.0/default/VirtualizerEffect.cpp
@@ -0,0 +1,248 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <memory.h> + +#define LOG_TAG "Virtualizer_HAL" +#include <system/audio_effects/effect_virtualizer.h> +#include <android/log.h> + +#include "VirtualizerEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +VirtualizerEffect::VirtualizerEffect(effect_handle_t handle) + : mEffect(new Effect(handle)) { +} + +VirtualizerEffect::~VirtualizerEffect() {} + +void VirtualizerEffect::speakerAnglesFromHal( + const int32_t* halAngles, uint32_t channelCount, hidl_vec<SpeakerAngle>& speakerAngles) { + speakerAngles.resize(channelCount); + for (uint32_t i = 0; i < channelCount; ++i) { + speakerAngles[i].mask = AudioChannelMask(*halAngles++); + speakerAngles[i].azimuth = *halAngles++; + speakerAngles[i].elevation = *halAngles++; + } +} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> VirtualizerEffect::init() { + return mEffect->init(); +} + +Return<Result> VirtualizerEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> VirtualizerEffect::reset() { + return mEffect->reset(); +} + +Return<Result> VirtualizerEffect::enable() { + return mEffect->enable(); +} + +Return<Result> VirtualizerEffect::disable() { + return mEffect->disable(); +} + +Return<Result> VirtualizerEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> VirtualizerEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> VirtualizerEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> VirtualizerEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> VirtualizerEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> VirtualizerEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> VirtualizerEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> VirtualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> VirtualizerEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> VirtualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> VirtualizerEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> VirtualizerEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> VirtualizerEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> VirtualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> VirtualizerEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> VirtualizerEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> VirtualizerEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> VirtualizerEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> VirtualizerEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> VirtualizerEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> VirtualizerEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> VirtualizerEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> VirtualizerEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IVirtualizerEffect follow. +Return<bool> VirtualizerEffect::isStrengthSupported() { + bool halSupported = false; + mEffect->getParam(VIRTUALIZER_PARAM_STRENGTH_SUPPORTED, halSupported); + return halSupported; +} + +Return<Result> VirtualizerEffect::setStrength(uint16_t strength) { + return mEffect->setParam(VIRTUALIZER_PARAM_STRENGTH, strength); +} + +Return<void> VirtualizerEffect::getStrength(getStrength_cb _hidl_cb) { + return mEffect->getIntegerParam(VIRTUALIZER_PARAM_STRENGTH, _hidl_cb); +} + +Return<void> VirtualizerEffect::getVirtualSpeakerAngles( + AudioChannelMask mask, AudioDevice device, getVirtualSpeakerAngles_cb _hidl_cb) { + uint32_t channelCount = audio_channel_count_from_out_mask( + static_cast<audio_channel_mask_t>(mask)); + size_t halSpeakerAnglesSize = sizeof(int32_t) * 3 * channelCount; + uint32_t halParam[3] = { + VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES, + static_cast<audio_channel_mask_t>(mask), + static_cast<audio_devices_t>(device) + }; + hidl_vec<SpeakerAngle> speakerAngles; + Result retval = mEffect->getParameterImpl( + sizeof(halParam), halParam, + halSpeakerAnglesSize, + [&] (uint32_t valueSize, const void* valueData) { + if (valueSize > halSpeakerAnglesSize) { + valueSize = halSpeakerAnglesSize; + } else if (valueSize < halSpeakerAnglesSize) { + channelCount = valueSize / (sizeof(int32_t) * 3); + } + speakerAnglesFromHal( + reinterpret_cast<const int32_t*>(valueData), channelCount, speakerAngles); + }); + _hidl_cb(retval, speakerAngles); + return Void(); +} + +Return<Result> VirtualizerEffect::forceVirtualizationMode(AudioDevice device) { + return mEffect->setParam( + VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE, static_cast<audio_devices_t>(device)); +} + +Return<void> VirtualizerEffect::getVirtualizationMode(getVirtualizationMode_cb _hidl_cb) { + uint32_t halMode = 0; + Result retval = mEffect->getParam(VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE, halMode); + _hidl_cb(retval, AudioDevice(halMode)); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/VirtualizerEffect.h b/audio/effect/2.0/default/VirtualizerEffect.h new file mode 100644 index 0000000..536775f --- /dev/null +++ b/audio/effect/2.0/default/VirtualizerEffect.h
@@ -0,0 +1,138 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H + +#include <android/hardware/audio/effect/2.0/IVirtualizerEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioChannelMask; +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::effect::V2_0::AudioBuffer; +using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig; +using ::android::hardware::audio::effect::V2_0::EffectConfig; +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; +using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter; +using ::android::hardware::audio::effect::V2_0::IEffect; +using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback; +using ::android::hardware::audio::effect::V2_0::IVirtualizerEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct VirtualizerEffect : public IVirtualizerEffect { + explicit VirtualizerEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::IVirtualizerEffect follow. + Return<bool> isStrengthSupported() override; + Return<Result> setStrength(uint16_t strength) override; + Return<void> getStrength(getStrength_cb _hidl_cb) override; + Return<void> getVirtualSpeakerAngles( + AudioChannelMask mask, + AudioDevice device, + getVirtualSpeakerAngles_cb _hidl_cb) override; + Return<Result> forceVirtualizationMode(AudioDevice device) override; + Return<void> getVirtualizationMode(getVirtualizationMode_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + + virtual ~VirtualizerEffect(); + + void speakerAnglesFromHal( + const int32_t* halAngles, uint32_t channelCount, hidl_vec<SpeakerAngle>& speakerAngles); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H
diff --git a/audio/effect/2.0/default/VisualizerEffect.cpp b/audio/effect/2.0/default/VisualizerEffect.cpp new file mode 100644 index 0000000..2cd3240 --- /dev/null +++ b/audio/effect/2.0/default/VisualizerEffect.cpp
@@ -0,0 +1,268 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "Visualizer_HAL" +#include <system/audio_effects/effect_visualizer.h> +#include <android/log.h> + +#include "VisualizerEffect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +VisualizerEffect::VisualizerEffect(effect_handle_t handle) + : mEffect(new Effect(handle)), mCaptureSize(0), mMeasurementMode(MeasurementMode::NONE) { +} + +VisualizerEffect::~VisualizerEffect() {} + +// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. +Return<Result> VisualizerEffect::init() { + return mEffect->init(); +} + +Return<Result> VisualizerEffect::setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> VisualizerEffect::reset() { + return mEffect->reset(); +} + +Return<Result> VisualizerEffect::enable() { + return mEffect->enable(); +} + +Return<Result> VisualizerEffect::disable() { + return mEffect->disable(); +} + +Return<Result> VisualizerEffect::setDevice(AudioDevice device) { + return mEffect->setDevice(device); +} + +Return<void> VisualizerEffect::setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) { + return mEffect->setAndGetVolume(volumes, _hidl_cb); +} + +Return<Result> VisualizerEffect::volumeChangeNotification( + const hidl_vec<uint32_t>& volumes) { + return mEffect->volumeChangeNotification(volumes); +} + +Return<Result> VisualizerEffect::setAudioMode(AudioMode mode) { + return mEffect->setAudioMode(mode); +} + +Return<Result> VisualizerEffect::setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) { + return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider); +} + +Return<Result> VisualizerEffect::setInputDevice(AudioDevice device) { + return mEffect->setInputDevice(device); +} + +Return<void> VisualizerEffect::getConfig(getConfig_cb _hidl_cb) { + return mEffect->getConfig(_hidl_cb); +} + +Return<void> VisualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) { + return mEffect->getConfigReverse(_hidl_cb); +} + +Return<void> VisualizerEffect::getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) { + return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb); +} + +Return<void> VisualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) { + return mEffect->getAuxChannelsConfig(_hidl_cb); +} + +Return<Result> VisualizerEffect::setAuxChannelsConfig( + const EffectAuxChannelsConfig& config) { + return mEffect->setAuxChannelsConfig(config); +} + +Return<Result> VisualizerEffect::setAudioSource(AudioSource source) { + return mEffect->setAudioSource(source); +} + +Return<Result> VisualizerEffect::offload(const EffectOffloadParameter& param) { + return mEffect->offload(param); +} + +Return<void> VisualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) { + return mEffect->getDescriptor(_hidl_cb); +} + +Return<void> VisualizerEffect::prepareForProcessing( + prepareForProcessing_cb _hidl_cb) { + return mEffect->prepareForProcessing(_hidl_cb); +} + +Return<Result> VisualizerEffect::setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) { + return mEffect->setProcessBuffers(inBuffer, outBuffer); +} + +Return<void> VisualizerEffect::command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) { + return mEffect->command(commandId, data, resultMaxSize, _hidl_cb); +} + +Return<Result> VisualizerEffect::setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) { + return mEffect->setParameter(parameter, value); +} + +Return<void> VisualizerEffect::getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) { + return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb); +} + +Return<void> VisualizerEffect::getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) { + return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb); +} + +Return<void> VisualizerEffect::getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) { + return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb); +} + +Return<Result> VisualizerEffect::setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) { + return mEffect->setCurrentConfigForFeature(featureId, configData); +} + +Return<Result> VisualizerEffect::close() { + return mEffect->close(); +} + +// Methods from ::android::hardware::audio::effect::V2_0::IVisualizerEffect follow. +Return<Result> VisualizerEffect::setCaptureSize(uint16_t captureSize) { + Result retval = mEffect->setParam(VISUALIZER_PARAM_CAPTURE_SIZE, captureSize); + if (retval == Result::OK) { + mCaptureSize = captureSize; + } + return retval; +} + +Return<void> VisualizerEffect::getCaptureSize(getCaptureSize_cb _hidl_cb) { + return mEffect->getIntegerParam(VISUALIZER_PARAM_CAPTURE_SIZE, _hidl_cb); +} + +Return<Result> VisualizerEffect::setScalingMode(IVisualizerEffect::ScalingMode scalingMode) { + return mEffect->setParam(VISUALIZER_PARAM_SCALING_MODE, static_cast<int32_t>(scalingMode)); +} + +Return<void> VisualizerEffect::getScalingMode(getScalingMode_cb _hidl_cb) { + int32_t halMode; + Result retval = mEffect->getParam(VISUALIZER_PARAM_SCALING_MODE, halMode); + _hidl_cb(retval, ScalingMode(halMode)); + return Void(); +} + +Return<Result> VisualizerEffect::setLatency(uint32_t latencyMs) { + return mEffect->setParam(VISUALIZER_PARAM_LATENCY, latencyMs); +} + +Return<void> VisualizerEffect::getLatency(getLatency_cb _hidl_cb) { + return mEffect->getIntegerParam(VISUALIZER_PARAM_LATENCY, _hidl_cb); +} + +Return<Result> VisualizerEffect::setMeasurementMode( + IVisualizerEffect::MeasurementMode measurementMode) { + Result retval = mEffect->setParam( + VISUALIZER_PARAM_MEASUREMENT_MODE, static_cast<int32_t>(measurementMode)); + if (retval == Result::OK) { + mMeasurementMode = measurementMode; + } + return retval; +} + +Return<void> VisualizerEffect::getMeasurementMode(getMeasurementMode_cb _hidl_cb) { + int32_t halMode; + Result retval = mEffect->getParam(VISUALIZER_PARAM_MEASUREMENT_MODE, halMode); + _hidl_cb(retval, MeasurementMode(halMode)); + return Void(); +} + +Return<void> VisualizerEffect::capture(capture_cb _hidl_cb) { + if (mCaptureSize == 0) { + _hidl_cb(Result::NOT_INITIALIZED, hidl_vec<uint8_t>()); + return Void(); + } + uint32_t halCaptureSize = mCaptureSize; + uint8_t halCapture[mCaptureSize]; + Result retval = mEffect->sendCommandReturningData( + VISUALIZER_CMD_CAPTURE, "VISUALIZER_CAPTURE", &halCaptureSize, halCapture); + hidl_vec<uint8_t> capture; + if (retval == Result::OK) { + capture.setToExternal(&halCapture[0], halCaptureSize); + } + _hidl_cb(retval, capture); + return Void(); +} + +Return<void> VisualizerEffect::measure(measure_cb _hidl_cb) { + if (mMeasurementMode == MeasurementMode::NONE) { + _hidl_cb(Result::NOT_INITIALIZED, Measurement()); + return Void(); + } + int32_t halMeasurement[MEASUREMENT_COUNT]; + uint32_t halMeasurementSize = sizeof(halMeasurement); + Result retval = mEffect->sendCommandReturningData( + VISUALIZER_CMD_MEASURE, "VISUALIZER_MEASURE", &halMeasurementSize, halMeasurement); + Measurement measurement = { .mode = MeasurementMode::PEAK_RMS }; + measurement.value.peakAndRms.peakMb = 0; + measurement.value.peakAndRms.rmsMb = 0; + if (retval == Result::OK) { + measurement.value.peakAndRms.peakMb = halMeasurement[MEASUREMENT_IDX_PEAK]; + measurement.value.peakAndRms.rmsMb = halMeasurement[MEASUREMENT_IDX_RMS]; + } + _hidl_cb(retval, measurement); + return Void(); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android
diff --git a/audio/effect/2.0/default/VisualizerEffect.h b/audio/effect/2.0/default/VisualizerEffect.h new file mode 100644 index 0000000..fd40ca8 --- /dev/null +++ b/audio/effect/2.0/default/VisualizerEffect.h
@@ -0,0 +1,137 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H +#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H + +#include <android/hardware/audio/effect/2.0/IVisualizerEffect.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include "Effect.h" + +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::audio::common::V2_0::AudioMode; +using ::android::hardware::audio::common::V2_0::AudioSource; +using ::android::hardware::audio::effect::V2_0::AudioBuffer; +using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig; +using ::android::hardware::audio::effect::V2_0::EffectConfig; +using ::android::hardware::audio::effect::V2_0::EffectDescriptor; +using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter; +using ::android::hardware::audio::effect::V2_0::IEffect; +using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback; +using ::android::hardware::audio::effect::V2_0::IVisualizerEffect; +using ::android::hardware::audio::effect::V2_0::Result; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct VisualizerEffect : public IVisualizerEffect { + explicit VisualizerEffect(effect_handle_t handle); + + // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow. + Return<Result> init() override; + Return<Result> setConfig( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> reset() override; + Return<Result> enable() override; + Return<Result> disable() override; + Return<Result> setDevice(AudioDevice device) override; + Return<void> setAndGetVolume( + const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) override; + Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override; + Return<Result> setAudioMode(AudioMode mode) override; + Return<Result> setConfigReverse( + const EffectConfig& config, + const sp<IEffectBufferProviderCallback>& inputBufferProvider, + const sp<IEffectBufferProviderCallback>& outputBufferProvider) override; + Return<Result> setInputDevice(AudioDevice device) override; + Return<void> getConfig(getConfig_cb _hidl_cb) override; + Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override; + Return<void> getSupportedAuxChannelsConfigs( + uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override; + Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override; + Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override; + Return<Result> setAudioSource(AudioSource source) override; + Return<Result> offload(const EffectOffloadParameter& param) override; + Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override; + Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override; + Return<Result> setProcessBuffers( + const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) override; + Return<void> command( + uint32_t commandId, + const hidl_vec<uint8_t>& data, + uint32_t resultMaxSize, + command_cb _hidl_cb) override; + Return<Result> setParameter( + const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) override; + Return<void> getParameter( + const hidl_vec<uint8_t>& parameter, + uint32_t valueMaxSize, + getParameter_cb _hidl_cb) override; + Return<void> getSupportedConfigsForFeature( + uint32_t featureId, + uint32_t maxConfigs, + uint32_t configSize, + getSupportedConfigsForFeature_cb _hidl_cb) override; + Return<void> getCurrentConfigForFeature( + uint32_t featureId, + uint32_t configSize, + getCurrentConfigForFeature_cb _hidl_cb) override; + Return<Result> setCurrentConfigForFeature( + uint32_t featureId, const hidl_vec<uint8_t>& configData) override; + Return<Result> close() override; + + // Methods from ::android::hardware::audio::effect::V2_0::IVisualizerEffect follow. + Return<Result> setCaptureSize(uint16_t captureSize) override; + Return<void> getCaptureSize(getCaptureSize_cb _hidl_cb) override; + Return<Result> setScalingMode(IVisualizerEffect::ScalingMode scalingMode) override; + Return<void> getScalingMode(getScalingMode_cb _hidl_cb) override; + Return<Result> setLatency(uint32_t latencyMs) override; + Return<void> getLatency(getLatency_cb _hidl_cb) override; + Return<Result> setMeasurementMode(IVisualizerEffect::MeasurementMode measurementMode) override; + Return<void> getMeasurementMode(getMeasurementMode_cb _hidl_cb) override; + Return<void> capture(capture_cb _hidl_cb) override; + Return<void> measure(measure_cb _hidl_cb) override; + + private: + sp<Effect> mEffect; + uint16_t mCaptureSize; + MeasurementMode mMeasurementMode; + + virtual ~VisualizerEffect(); +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H
diff --git a/audio/effect/2.0/types.hal b/audio/effect/2.0/types.hal new file mode 100644 index 0000000..0626ec5 --- /dev/null +++ b/audio/effect/2.0/types.hal
@@ -0,0 +1,299 @@ +/* + * Copyright (C) 2016 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.audio.effect@2.0; + +import android.hardware.audio.common@2.0; + +enum Result : int32_t { + OK, + NOT_INITIALIZED, + INVALID_ARGUMENTS, + INVALID_STATE, + NOT_SUPPORTED, + RESULT_TOO_BIG +}; + +/* + * Effect engine capabilities/requirements flags. + * + * Definitions for flags field of effect descriptor. + * + * +----------------+--------+-------------------------------------------------- + * | description | bits | values + * +----------------+--------+-------------------------------------------------- + * | connection | 0..2 | 0 insert: after track process + * | mode | | 1 auxiliary: connect to track auxiliary + * | | | output and use send level + * | | | 2 replace: replaces track process function; + * | | | must implement SRC, volume and mono to stereo. + * | | | 3 pre processing: applied below audio HAL on in + * | | | 4 post processing: applied below audio HAL on out + * | | | 5 - 7 reserved + * +----------------+--------+-------------------------------------------------- + * | insertion | 3..5 | 0 none + * | preference | | 1 first of the chain + * | | | 2 last of the chain + * | | | 3 exclusive (only effect in the insert chain) + * | | | 4..7 reserved + * +----------------+--------+-------------------------------------------------- + * | Volume | 6..8 | 0 none + * | management | | 1 implements volume control + * | | | 2 requires volume indication + * | | | 4 reserved + * +----------------+--------+-------------------------------------------------- + * | Device | 9..11 | 0 none + * | indication | | 1 requires device updates + * | | | 2, 4 reserved + * +----------------+--------+-------------------------------------------------- + * | Sample input | 12..13 | 1 direct: process() function or + * | mode | | EFFECT_CMD_SET_CONFIG command must specify + * | | | a buffer descriptor + * | | | 2 provider: process() function uses the + * | | | bufferProvider indicated by the + * | | | EFFECT_CMD_SET_CONFIG command to request input. + * | | | buffers. + * | | | 3 both: both input modes are supported + * +----------------+--------+-------------------------------------------------- + * | Sample output | 14..15 | 1 direct: process() function or + * | mode | | EFFECT_CMD_SET_CONFIG command must specify + * | | | a buffer descriptor + * | | | 2 provider: process() function uses the + * | | | bufferProvider indicated by the + * | | | EFFECT_CMD_SET_CONFIG command to request output + * | | | buffers. + * | | | 3 both: both output modes are supported + * +----------------+--------+-------------------------------------------------- + * | Hardware | 16..17 | 0 No hardware acceleration + * | acceleration | | 1 non tunneled hw acceleration: the process() + * | | | function reads the samples, send them to HW + * | | | accelerated effect processor, reads back + * | | | the processed samples and returns them + * | | | to the output buffer. + * | | | 2 tunneled hw acceleration: the process() + * | | | function is transparent. The effect interface + * | | | is only used to control the effect engine. + * | | | This mode is relevant for global effects + * | | | actually applied by the audio hardware on + * | | | the output stream. + * +----------------+--------+-------------------------------------------------- + * | Audio Mode | 18..19 | 0 none + * | indication | | 1 requires audio mode updates + * | | | 2..3 reserved + * +----------------+--------+-------------------------------------------------- + * | Audio source | 20..21 | 0 none + * | indication | | 1 requires audio source updates + * | | | 2..3 reserved + * +----------------+--------+-------------------------------------------------- + * | Effect offload | 22 | 0 The effect cannot be offloaded to an audio DSP + * | supported | | 1 The effect can be offloaded to an audio DSP + * +----------------+--------+-------------------------------------------------- + * | Process | 23 | 0 The effect implements a process function. + * | function | | 1 The effect does not implement a process + * | not | | function: enabling the effect has no impact + * | implemented | | on latency or CPU load. + * | | | Effect implementations setting this flag do not + * | | | have to implement a process function. + * +----------------+--------+-------------------------------------------------- + */ +@export(name="", value_prefix="EFFECT_FLAG_") +enum EffectFlags : int32_t { + // Insert mode + TYPE_SHIFT = 0, + TYPE_SIZE = 3, + TYPE_MASK = ((1 << TYPE_SIZE) -1) << TYPE_SHIFT, + TYPE_INSERT = 0 << TYPE_SHIFT, + TYPE_AUXILIARY = 1 << TYPE_SHIFT, + TYPE_REPLACE = 2 << TYPE_SHIFT, + TYPE_PRE_PROC = 3 << TYPE_SHIFT, + TYPE_POST_PROC = 4 << TYPE_SHIFT, + + // Insert preference + INSERT_SHIFT = TYPE_SHIFT + TYPE_SIZE, + INSERT_SIZE = 3, + INSERT_MASK = ((1 << INSERT_SIZE) -1) << INSERT_SHIFT, + INSERT_ANY = 0 << INSERT_SHIFT, + INSERT_FIRST = 1 << INSERT_SHIFT, + INSERT_LAST = 2 << INSERT_SHIFT, + INSERT_EXCLUSIVE = 3 << INSERT_SHIFT, + + // Volume control + VOLUME_SHIFT = INSERT_SHIFT + INSERT_SIZE, + VOLUME_SIZE = 3, + VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT, + VOLUME_CTRL = 1 << VOLUME_SHIFT, + VOLUME_IND = 2 << VOLUME_SHIFT, + VOLUME_NONE = 0 << VOLUME_SHIFT, + + // Device indication + DEVICE_SHIFT = VOLUME_SHIFT + VOLUME_SIZE, + DEVICE_SIZE = 3, + DEVICE_MASK = ((1 << DEVICE_SIZE) -1) << DEVICE_SHIFT, + DEVICE_IND = 1 << DEVICE_SHIFT, + DEVICE_NONE = 0 << DEVICE_SHIFT, + + // Sample input modes + INPUT_SHIFT = DEVICE_SHIFT + DEVICE_SIZE, + INPUT_SIZE = 2, + INPUT_MASK = ((1 << INPUT_SIZE) -1) << INPUT_SHIFT, + INPUT_DIRECT = 1 << INPUT_SHIFT, + INPUT_PROVIDER = 2 << INPUT_SHIFT, + INPUT_BOTH = 3 << INPUT_SHIFT, + + // Sample output modes + OUTPUT_SHIFT = INPUT_SHIFT + INPUT_SIZE, + OUTPUT_SIZE = 2, + OUTPUT_MASK = ((1 << OUTPUT_SIZE) -1) << OUTPUT_SHIFT, + OUTPUT_DIRECT = 1 << OUTPUT_SHIFT, + OUTPUT_PROVIDER = 2 << OUTPUT_SHIFT, + OUTPUT_BOTH = 3 << OUTPUT_SHIFT, + + // Hardware acceleration mode + HW_ACC_SHIFT = OUTPUT_SHIFT + OUTPUT_SIZE, + HW_ACC_SIZE = 2, + HW_ACC_MASK = ((1 << HW_ACC_SIZE) -1) << HW_ACC_SHIFT, + HW_ACC_SIMPLE = 1 << HW_ACC_SHIFT, + HW_ACC_TUNNEL = 2 << HW_ACC_SHIFT, + + // Audio mode indication + AUDIO_MODE_SHIFT = HW_ACC_SHIFT + HW_ACC_SIZE, + AUDIO_MODE_SIZE = 2, + AUDIO_MODE_MASK = ((1 << AUDIO_MODE_SIZE) -1) << AUDIO_MODE_SHIFT, + AUDIO_MODE_IND = 1 << AUDIO_MODE_SHIFT, + AUDIO_MODE_NONE = 0 << AUDIO_MODE_SHIFT, + + // Audio source indication + AUDIO_SOURCE_SHIFT = AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE, + AUDIO_SOURCE_SIZE = 2, + AUDIO_SOURCE_MASK = ((1 << AUDIO_SOURCE_SIZE) -1) << AUDIO_SOURCE_SHIFT, + AUDIO_SOURCE_IND = 1 << AUDIO_SOURCE_SHIFT, + AUDIO_SOURCE_NONE = 0 << AUDIO_SOURCE_SHIFT, + + // Effect offload indication + OFFLOAD_SHIFT = AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE, + OFFLOAD_SIZE = 1, + OFFLOAD_MASK = ((1 << OFFLOAD_SIZE) -1) << OFFLOAD_SHIFT, + OFFLOAD_SUPPORTED = 1 << OFFLOAD_SHIFT, + + // Effect has no process indication + NO_PROCESS_SHIFT = OFFLOAD_SHIFT + OFFLOAD_SIZE, + NO_PROCESS_SIZE = 1, + NO_PROCESS_MASK = ((1 << NO_PROCESS_SIZE) -1) << NO_PROCESS_SHIFT, + NO_PROCESS = 1 << NO_PROCESS_SHIFT +}; + +/* + * The effect descriptor contains necessary information to facilitate the + * enumeration of the effect engines present in a library. + */ +struct EffectDescriptor { + Uuid type; // UUID of to the OpenSL ES interface implemented + // by this effect + Uuid uuid; // UUID for this particular implementation + EffectFlags flags; // effect engine capabilities/requirements flags + uint16_t cpuLoad; // CPU load indication expressed in 0.1 MIPS units + // as estimated on an ARM9E core (ARMv5TE) with 0 WS + uint16_t memoryUsage; // data memory usage expressed in KB and includes + // only dynamically allocated memory + uint8_t[64] name; // human readable effect name + uint8_t[64] implementor; // human readable effect implementor name +}; + +/* + * A buffer is a chunk of audio data for processing. Multi-channel audio is + * always interleaved. The channel order is from LSB to MSB with regard to the + * channel mask definition in audio.h, audio_channel_mask_t, e.g.: + * Stereo: L, R; 5.1: FL, FR, FC, LFE, BL, BR. + * + * The buffer size is expressed in frame count, a frame being composed of + * samples for all channels at a given time. Frame size for unspecified format + * (AUDIO_FORMAT_OTHER) is 8 bit by definition. + */ +struct AudioBuffer { + uint64_t id; + uint32_t frameCount; + memory data; +}; + +@export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_") +enum EffectBufferAccess : int32_t { + ACCESS_WRITE, + ACCESS_READ, + ACCESS_ACCUMULATE +}; + +/* + * Determines what fields of EffectBufferConfig need to be considered. + */ +@export(name="", value_prefix="EFFECT_CONFIG_") +enum EffectConfigParameters : int32_t { + BUFFER = 0x0001, // buffer field + SMP_RATE = 0x0002, // samplingRate + CHANNELS = 0x0004, // channels + FORMAT = 0x0008, // format + ACC_MODE = 0x0010, // accessMode + ALL = BUFFER | SMP_RATE | CHANNELS | FORMAT | ACC_MODE +}; + +/* + * The buffer config structure specifies the input or output audio format + * to be used by the effect engine. + */ +struct EffectBufferConfig { + AudioBuffer buffer; + uint32_t samplingRateHz; + AudioChannelMask channels; + AudioFormat format; + EffectBufferAccess accessMode; + EffectConfigParameters mask; +}; + +struct EffectConfig { + EffectBufferConfig inputCfg; + EffectBufferConfig outputCfg; +}; + +@export(name="effect_feature_e", value_prefix="EFFECT_FEATURE_") +enum EffectFeature : int32_t { + AUX_CHANNELS, // supports auxiliary channels + // (e.g. dual mic noise suppressor) + CNT +}; + +struct EffectAuxChannelsConfig { + AudioChannelMask mainChannels; // channel mask for main channels + AudioChannelMask auxChannels; // channel mask for auxiliary channels +}; + +struct EffectOffloadParameter { + bool isOffload; // true if the playback thread the effect + // is attached to is offloaded + AudioIoHandle ioHandle; // io handle of the playback thread + // the effect is attached to +}; + +/* + * The message queue flags used to synchronize reads and writes from + * the status message queue used by effects. + */ +enum MessageQueueFlagBits : uint32_t { + DONE_PROCESSING = 1 << 0, + REQUEST_PROCESS = 1 << 1, + REQUEST_PROCESS_REVERSE = 1 << 2, + REQUEST_QUIT = 1 << 3, + REQUEST_PROCESS_ALL = + REQUEST_PROCESS | REQUEST_PROCESS_REVERSE | REQUEST_QUIT +};
diff --git a/audio/effect/2.0/vts/Android.mk b/audio/effect/2.0/vts/Android.mk new file mode 100644 index 0000000..abdd5bf --- /dev/null +++ b/audio/effect/2.0/vts/Android.mk
@@ -0,0 +1,21 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/audio/effect/2.0/vts/functional/Android.bp b/audio/effect/2.0/vts/functional/Android.bp new file mode 100644 index 0000000..8a370cd --- /dev/null +++ b/audio/effect/2.0/vts/functional/Android.bp
@@ -0,0 +1,39 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalAudioEffectV2_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalAudioEffectV2_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.audio.common@2.0", + "android.hardware.audio.effect@2.0", + "android.hidl.allocator@1.0", + "android.hidl.memory@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +}
diff --git a/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp b/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp new file mode 100644 index 0000000..f6da213 --- /dev/null +++ b/audio/effect/2.0/vts/functional/VtsHalAudioEffectV2_0TargetTest.cpp
@@ -0,0 +1,741 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "AudioEffectHidlHalTest" +#include <android-base/logging.h> +#include <system/audio.h> + +#include <android/hardware/audio/effect/2.0/IEffect.h> +#include <android/hardware/audio/effect/2.0/IEffectsFactory.h> +#include <android/hardware/audio/effect/2.0/IEqualizerEffect.h> +#include <android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h> +#include <android/hardware/audio/effect/2.0/types.h> +#include <android/hidl/allocator/1.0/IAllocator.h> +#include <android/hidl/memory/1.0/IMemory.h> + +#include <VtsHalHidlTargetTestBase.h> + +using android::hardware::audio::common::V2_0::AudioDevice; +using android::hardware::audio::common::V2_0::AudioHandleConsts; +using android::hardware::audio::common::V2_0::AudioMode; +using android::hardware::audio::common::V2_0::Uuid; +using android::hardware::audio::effect::V2_0::AudioBuffer; +using android::hardware::audio::effect::V2_0::EffectBufferConfig; +using android::hardware::audio::effect::V2_0::EffectConfig; +using android::hardware::audio::effect::V2_0::EffectDescriptor; +using android::hardware::audio::effect::V2_0::EffectOffloadParameter; +using android::hardware::audio::effect::V2_0::IEffect; +using android::hardware::audio::effect::V2_0::IEffectsFactory; +using android::hardware::audio::effect::V2_0::IEqualizerEffect; +using android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect; +using android::hardware::audio::effect::V2_0::Result; +using android::hardware::MQDescriptorSync; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::hidl_memory; +using android::hardware::hidl_string; +using android::hardware::hidl_vec; +using android::hidl::allocator::V1_0::IAllocator; +using android::hidl::memory::V1_0::IMemory; +using android::sp; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) +#endif + +// The main test class for Audio Effects Factory HIDL HAL. +class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + void SetUp() override { + effectsFactory = + ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>(); + ASSERT_NE(effectsFactory, nullptr); + } + + void TearDown() override { effectsFactory.clear(); } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp<IEffectsFactory> effectsFactory; +}; + +TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) { + description("Verify that EnumerateEffects returns at least one effect"); + Result retval = Result::NOT_INITIALIZED; + size_t effectCount = 0; + Return<void> ret = effectsFactory->getAllDescriptors( + [&](Result r, const hidl_vec<EffectDescriptor>& result) { + retval = r; + effectCount = result.size(); + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_GT(effectCount, 0u); +} + +TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) { + description("Verify that an effect can be created via CreateEffect"); + bool gotEffect = false; + Uuid effectUuid; + Return<void> ret = effectsFactory->getAllDescriptors( + [&](Result r, const hidl_vec<EffectDescriptor>& result) { + if (r == Result::OK && result.size() > 0) { + gotEffect = true; + effectUuid = result[0].uuid; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_TRUE(gotEffect); + Result retval = Result::NOT_INITIALIZED; + sp<IEffect> effect; + ret = effectsFactory->createEffect( + effectUuid, 1 /*session*/, 1 /*ioHandle*/, + [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) { + retval = r; + if (r == Result::OK) { + effect = result; + } + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_NE(nullptr, effect.get()); +} + +TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) { + description( + "Verify that effects factory can provide an effect descriptor via " + "GetDescriptor"); + hidl_vec<EffectDescriptor> allDescriptors; + Return<void> ret = effectsFactory->getAllDescriptors( + [&](Result r, const hidl_vec<EffectDescriptor>& result) { + if (r == Result::OK) { + allDescriptors = result; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_GT(allDescriptors.size(), 0u); + for (size_t i = 0; i < allDescriptors.size(); ++i) { + ret = effectsFactory->getDescriptor( + allDescriptors[i].uuid, [&](Result r, const EffectDescriptor& result) { + EXPECT_EQ(r, Result::OK); + EXPECT_EQ(result, allDescriptors[i]); + }); + } + EXPECT_TRUE(ret.isOk()); +} + +// Equalizer effect is required by CDD, but only the type is fixed. +// This is the same UUID as AudioEffect.EFFECT_TYPE_EQUALIZER in Java. +static const Uuid EQUALIZER_EFFECT_TYPE = { + 0x0bed4300, 0xddd6, 0x11db, 0x8f34, + std::array<uint8_t, 6>{{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}}; +// Loudness Enhancer effect is required by CDD, but only the type is fixed. +// This is the same UUID as AudioEffect.EFFECT_TYPE_LOUDNESS_ENHANCER in Java. +static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = { + 0xfe3199be, 0xaed0, 0x413f, 0x87bb, + std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}}; + +// The main test class for Audio Effect HIDL HAL. +class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + void SetUp() override { + effectsFactory = + ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>(); + ASSERT_NE(nullptr, effectsFactory.get()); + + findAndCreateEffect(getEffectType()); + ASSERT_NE(nullptr, effect.get()); + + Return<Result> ret = effect->init(); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, ret); + } + + void TearDown() override { + effect.clear(); + effectsFactory.clear(); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; } + + void findAndCreateEffect(const Uuid& type); + void findEffectInstance(const Uuid& type, Uuid* uuid); + void getChannelCount(uint32_t* channelCount); + + sp<IEffectsFactory> effectsFactory; + sp<IEffect> effect; +}; + +void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) { + Uuid effectUuid; + findEffectInstance(type, &effectUuid); + Return<void> ret = effectsFactory->createEffect( + effectUuid, 1 /*session*/, 1 /*ioHandle*/, + [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) { + if (r == Result::OK) { + effect = result; + } + }); + ASSERT_TRUE(ret.isOk()); +} + +void AudioEffectHidlTest::findEffectInstance(const Uuid& type, Uuid* uuid) { + bool effectFound = false; + Return<void> ret = effectsFactory->getAllDescriptors( + [&](Result r, const hidl_vec<EffectDescriptor>& result) { + if (r == Result::OK) { + for (const auto& desc : result) { + if (desc.type == type) { + effectFound = true; + *uuid = desc.uuid; + break; + } + } + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_TRUE(effectFound); +} + +void AudioEffectHidlTest::getChannelCount(uint32_t* channelCount) { + Result retval; + EffectConfig currentConfig; + Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { + retval = r; + if (r == Result::OK) { + currentConfig = conf; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); + ASSERT_TRUE(audio_channel_mask_is_valid( + static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels))); + *channelCount = audio_channel_count_from_out_mask( + static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)); +} + +TEST_F(AudioEffectHidlTest, Close) { + description("Verify that an effect can be closed"); + Return<Result> ret = effect->close(); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, GetDescriptor) { + description( + "Verify that an effect can return its own descriptor via GetDescriptor"); + Result retval = Result::NOT_INITIALIZED; + Uuid actualType; + Return<void> ret = + effect->getDescriptor([&](Result r, const EffectDescriptor& desc) { + retval = r; + if (r == Result::OK) { + actualType = desc.type; + } + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(getEffectType(), actualType); +} + +TEST_F(AudioEffectHidlTest, GetSetConfig) { + description( + "Verify that it is possible to manipulate effect config via Get / " + "SetConfig"); + Result retval = Result::NOT_INITIALIZED; + EffectConfig currentConfig; + Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { + retval = r; + if (r == Result::OK) { + currentConfig = conf; + } + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + Return<Result> ret2 = effect->setConfig(currentConfig, nullptr, nullptr); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, ret2); +} + +// Not generated automatically because AudioBuffer contains +// instances of hidl_memory which can't be compared properly +// in general case due to presence of handles. +// +// However, in this particular case, handles must not present +// thus comparison is possible. +// +// operator== must be defined in the same namespace as the structures. +namespace android { +namespace hardware { +namespace audio { +namespace effect { +namespace V2_0 { +inline bool operator==(const AudioBuffer& lhs, const AudioBuffer& rhs) { + return lhs.id == rhs.id && lhs.frameCount == rhs.frameCount && + lhs.data.handle() == nullptr && rhs.data.handle() == nullptr; +} + +inline bool operator==(const EffectBufferConfig& lhs, + const EffectBufferConfig& rhs) { + return lhs.buffer == rhs.buffer && lhs.samplingRateHz == rhs.samplingRateHz && + lhs.channels == rhs.channels && lhs.format == rhs.format && + lhs.accessMode == rhs.accessMode && lhs.mask == rhs.mask; +} + +inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) { + return lhs.inputCfg == rhs.inputCfg && lhs.outputCfg == rhs.outputCfg; +} +} // namespace V2_0 +} // namespace effect +} // namespace audio +} // namespace hardware +} // namespace android + +TEST_F(AudioEffectHidlTest, Reset) { + description("Verify that Reset preserves effect configuration"); + Result retval = Result::NOT_INITIALIZED; + EffectConfig originalConfig; + Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) { + retval = r; + if (r == Result::OK) { + originalConfig = conf; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); + Return<Result> ret2 = effect->reset(); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, ret2); + EffectConfig configAfterReset; + ret = effect->getConfig([&](Result r, const EffectConfig& conf) { + retval = r; + if (r == Result::OK) { + configAfterReset = conf; + } + }); + EXPECT_EQ(originalConfig, configAfterReset); +} + +TEST_F(AudioEffectHidlTest, DisableEnableDisable) { + description("Verify Disable -> Enable -> Disable sequence for an effect"); + Return<Result> ret = effect->disable(); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::INVALID_ARGUMENTS, ret); + ret = effect->enable(); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + ret = effect->disable(); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, SetDevice) { + description("Verify that SetDevice works for an output chain effect"); + Return<Result> ret = effect->setDevice(AudioDevice::OUT_SPEAKER); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, SetAndGetVolume) { + description("Verify that SetAndGetVolume method works for an effect"); + uint32_t channelCount; + getChannelCount(&channelCount); + hidl_vec<uint32_t> volumes; + volumes.resize(channelCount); + for (uint32_t i = 0; i < channelCount; ++i) { + volumes[i] = 0; + } + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = effect->setAndGetVolume( + volumes, [&](Result r, const hidl_vec<uint32_t>&) { retval = r; }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); +} + +TEST_F(AudioEffectHidlTest, VolumeChangeNotification) { + description("Verify that effect accepts VolumeChangeNotification"); + uint32_t channelCount; + getChannelCount(&channelCount); + hidl_vec<uint32_t> volumes; + volumes.resize(channelCount); + for (uint32_t i = 0; i < channelCount; ++i) { + volumes[i] = 0; + } + Return<Result> ret = effect->volumeChangeNotification(volumes); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, SetAudioMode) { + description("Verify that SetAudioMode works for an effect"); + Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, Offload) { + description("Verify that calling Offload methods works for an effect"); + EffectOffloadParameter offloadParam; + offloadParam.isOffload = false; + offloadParam.ioHandle = + static_cast<int>(AudioHandleConsts::AUDIO_IO_HANDLE_NONE); + Return<Result> ret = effect->offload(offloadParam); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); +} + +TEST_F(AudioEffectHidlTest, PrepareForProcessing) { + description("Verify that PrepareForProcessing method works for an effect"); + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = effect->prepareForProcessing( + [&](Result r, const MQDescriptorSync<Result>&) { retval = r; }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); +} + +TEST_F(AudioEffectHidlTest, SetProcessBuffers) { + description("Verify that SetProcessBuffers works for an effect"); + sp<IAllocator> ashmem = IAllocator::getService("ashmem"); + ASSERT_NE(nullptr, ashmem.get()); + bool success = false; + AudioBuffer buffer; + Return<void> ret = + ashmem->allocate(1024, [&](bool s, const hidl_memory& memory) { + success = s; + if (s) { + buffer.data = memory; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_TRUE(success); + Return<Result> ret2 = effect->setProcessBuffers(buffer, buffer); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, ret2); +} + +// Testing getConfigReverse, getAuxChannelsConfig, +// getSupportedAuxChannelsConfigs, setAudioSource, setConfigReverse, +// setInputDevice doesn't make sense, because normally they are not supported by +// the Equalizer, but it wouldn't be a problem if some vendor implementation +// supports them, thus we can't test these methods neither for success, nor for +// failure. + +// command, getParameter, getSupportedConfigsForFeature, +// getCurrentConfigForFeature, setCurrentConfigForFeature, setParameter are +// opaque channels between vendor apps and HALs, and can't be meaningfully +// tested with effects that don't support them. + +// The main test class for Equalizer Audio Effect HIDL HAL. +class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest { + public: + void SetUp() override { + AudioEffectHidlTest::SetUp(); + equalizer = IEqualizerEffect::castFrom(effect); + ASSERT_NE(nullptr, equalizer.get()); + } + + protected: + Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; } + void getNumBands(uint16_t* numBands); + void getLevelRange(int16_t* minLevel, int16_t* maxLevel); + void getBandFrequencyRange(uint16_t band, uint32_t* minFreq, + uint32_t* centerFreq, uint32_t* maxFreq); + void getPresetCount(size_t* count); + + sp<IEqualizerEffect> equalizer; +}; + +void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) { + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = equalizer->getNumBands([&](Result r, uint16_t b) { + retval = r; + if (retval == Result::OK) { + *numBands = b; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); +} + +void EqualizerAudioEffectHidlTest::getLevelRange(int16_t* minLevel, + int16_t* maxLevel) { + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = + equalizer->getLevelRange([&](Result r, int16_t min, int16_t max) { + retval = r; + if (retval == Result::OK) { + *minLevel = min; + *maxLevel = max; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); +} + +void EqualizerAudioEffectHidlTest::getBandFrequencyRange(uint16_t band, + uint32_t* minFreq, + uint32_t* centerFreq, + uint32_t* maxFreq) { + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = equalizer->getBandFrequencyRange( + band, [&](Result r, uint32_t min, uint32_t max) { + retval = r; + if (retval == Result::OK) { + *minFreq = min; + *maxFreq = max; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); + ret = equalizer->getBandCenterFrequency(band, [&](Result r, uint32_t center) { + retval = r; + if (retval == Result::OK) { + *centerFreq = center; + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); +} + +void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) { + Result retval = Result::NOT_INITIALIZED; + Return<void> ret = equalizer->getPresetNames( + [&](Result r, const hidl_vec<hidl_string>& names) { + retval = r; + if (retval == Result::OK) { + *count = names.size(); + } + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(Result::OK, retval); +} + +TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) { + description("Verify that Equalizer effect reports at least one band"); + uint16_t numBands = 0; + getNumBands(&numBands); + EXPECT_GT(numBands, 0); +} + +TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) { + description("Verify that Equalizer effect reports adequate band level range"); + int16_t minLevel = 0x7fff, maxLevel = 0; + getLevelRange(&minLevel, &maxLevel); + EXPECT_GT(maxLevel, minLevel); +} + +TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) { + description( + "Verify that manipulating band levels works for Equalizer effect"); + uint16_t numBands = 0; + getNumBands(&numBands); + ASSERT_GT(numBands, 0); + int16_t levels[3]{0x7fff, 0, 0}; + getLevelRange(&levels[0], &levels[2]); + ASSERT_GT(levels[2], levels[0]); + levels[1] = (levels[2] + levels[0]) / 2; + for (uint16_t i = 0; i < numBands; ++i) { + for (size_t j = 0; j < ARRAY_SIZE(levels); ++j) { + Return<Result> ret = equalizer->setBandLevel(i, levels[j]); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + Result retval = Result::NOT_INITIALIZED; + int16_t actualLevel; + Return<void> ret2 = equalizer->getBandLevel(i, [&](Result r, int16_t l) { + retval = r; + if (retval == Result::OK) { + actualLevel = l; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(levels[j], actualLevel); + } + } +} + +TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) { + description( + "Verify that Equalizer effect reports adequate band frequency range"); + uint16_t numBands = 0; + getNumBands(&numBands); + ASSERT_GT(numBands, 0); + for (uint16_t i = 0; i < numBands; ++i) { + uint32_t minFreq = 0xffffffff, centerFreq = 0xffffffff, + maxFreq = 0xffffffff; + getBandFrequencyRange(i, &minFreq, ¢erFreq, &maxFreq); + // Note: NXP legacy implementation reports "1" as upper bound for last band, + // so this check fails. + EXPECT_GE(maxFreq, centerFreq); + EXPECT_GE(centerFreq, minFreq); + } +} + +TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) { + description( + "Verify that Equalizer effect supports GetBandForFrequency correctly"); + uint16_t numBands = 0; + getNumBands(&numBands); + ASSERT_GT(numBands, 0); + for (uint16_t i = 0; i < numBands; ++i) { + uint32_t freqs[3]{0, 0, 0}; + getBandFrequencyRange(i, &freqs[0], &freqs[1], &freqs[2]); + // NXP legacy implementation reports "1" as upper bound for last band, some + // of the checks fail. + for (size_t j = 0; j < ARRAY_SIZE(freqs); ++j) { + if (j == 0) { + freqs[j]++; + } // Min frequency is an open interval. + Result retval = Result::NOT_INITIALIZED; + uint16_t actualBand = numBands + 1; + Return<void> ret = + equalizer->getBandForFrequency(freqs[j], [&](Result r, uint16_t b) { + retval = r; + if (retval == Result::OK) { + actualBand = b; + } + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(i, actualBand) << "Frequency: " << freqs[j]; + } + } +} + +TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) { + description("Verify that Equalizer effect reports at least one preset"); + size_t presetCount; + getPresetCount(&presetCount); + EXPECT_GT(presetCount, 0u); +} + +TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) { + description( + "Verify that manipulating the current preset for Equalizer effect"); + size_t presetCount; + getPresetCount(&presetCount); + ASSERT_GT(presetCount, 0u); + for (uint16_t i = 0; i < presetCount; ++i) { + Return<Result> ret = equalizer->setCurrentPreset(i); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + Result retval = Result::NOT_INITIALIZED; + uint16_t actualPreset = 0xffff; + Return<void> ret2 = equalizer->getCurrentPreset([&](Result r, uint16_t p) { + retval = r; + if (retval == Result::OK) { + actualPreset = p; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(i, actualPreset); + } +} + +TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) { + description( + "Verify that setting band levels and presets works via Get / " + "SetAllProperties for Equalizer effect"); + using AllProperties = + android::hardware::audio::effect::V2_0::IEqualizerEffect::AllProperties; + uint16_t numBands = 0; + getNumBands(&numBands); + ASSERT_GT(numBands, 0); + AllProperties props; + props.bandLevels.resize(numBands); + for (size_t i = 0; i < numBands; ++i) { + props.bandLevels[i] = 0; + } + + AllProperties actualProps; + Result retval = Result::NOT_INITIALIZED; + + // Verify setting of the band levels via properties. + props.curPreset = -1; + Return<Result> ret = equalizer->setAllProperties(props); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + Return<void> ret2 = + equalizer->getAllProperties([&](Result r, AllProperties p) { + retval = r; + if (retval == Result::OK) { + actualProps = p; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(props.bandLevels, actualProps.bandLevels); + + // Verify setting of the current preset via properties. + props.curPreset = 0; // Assuming there is at least one preset. + ret = equalizer->setAllProperties(props); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) { + retval = r; + if (retval == Result::OK) { + actualProps = p; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(props.curPreset, actualProps.curPreset); +} + +// The main test class for Equalizer Audio Effect HIDL HAL. +class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest { + public: + void SetUp() override { + AudioEffectHidlTest::SetUp(); + enhancer = ILoudnessEnhancerEffect::castFrom(effect); + ASSERT_NE(nullptr, enhancer.get()); + } + + protected: + Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; } + + sp<ILoudnessEnhancerEffect> enhancer; +}; + +TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) { + description( + "Verify that manipulating the target gain works for Loudness Enhancer " + "effect"); + const int32_t gain = 100; + Return<Result> ret = enhancer->setTargetGain(gain); + EXPECT_TRUE(ret.isOk()); + EXPECT_EQ(Result::OK, ret); + int32_t actualGain = 0; + Result retval; + Return<void> ret2 = enhancer->getTargetGain([&](Result r, int32_t g) { + retval = r; + if (retval == Result::OK) { + actualGain = g; + } + }); + EXPECT_TRUE(ret2.isOk()); + EXPECT_EQ(Result::OK, retval); + EXPECT_EQ(gain, actualGain); +}
diff --git a/audio/effect/Android.mk b/audio/effect/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/audio/effect/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/automotive/Android.bp b/automotive/Android.bp new file mode 100644 index 0000000..9b24ded --- /dev/null +++ b/automotive/Android.bp
@@ -0,0 +1,7 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "evs/1.0", + "evs/1.0/default", + "vehicle/2.0", + "vehicle/2.1", +]
diff --git a/automotive/evs/1.0/Android.bp b/automotive/evs/1.0/Android.bp new file mode 100644 index 0000000..042becd --- /dev/null +++ b/automotive/evs/1.0/Android.bp
@@ -0,0 +1,83 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.automotive.evs@1.0_hal", + srcs: [ + "types.hal", + "IEvsCamera.hal", + "IEvsCameraStream.hal", + "IEvsDisplay.hal", + "IEvsEnumerator.hal", + ], +} + +genrule { + name: "android.hardware.automotive.evs@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.evs@1.0", + srcs: [ + ":android.hardware.automotive.evs@1.0_hal", + ], + out: [ + "android/hardware/automotive/evs/1.0/types.cpp", + "android/hardware/automotive/evs/1.0/EvsCameraAll.cpp", + "android/hardware/automotive/evs/1.0/EvsCameraStreamAll.cpp", + "android/hardware/automotive/evs/1.0/EvsDisplayAll.cpp", + "android/hardware/automotive/evs/1.0/EvsEnumeratorAll.cpp", + ], +} + +genrule { + name: "android.hardware.automotive.evs@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.evs@1.0", + srcs: [ + ":android.hardware.automotive.evs@1.0_hal", + ], + out: [ + "android/hardware/automotive/evs/1.0/types.h", + "android/hardware/automotive/evs/1.0/IEvsCamera.h", + "android/hardware/automotive/evs/1.0/IHwEvsCamera.h", + "android/hardware/automotive/evs/1.0/BnHwEvsCamera.h", + "android/hardware/automotive/evs/1.0/BpHwEvsCamera.h", + "android/hardware/automotive/evs/1.0/BsEvsCamera.h", + "android/hardware/automotive/evs/1.0/IEvsCameraStream.h", + "android/hardware/automotive/evs/1.0/IHwEvsCameraStream.h", + "android/hardware/automotive/evs/1.0/BnHwEvsCameraStream.h", + "android/hardware/automotive/evs/1.0/BpHwEvsCameraStream.h", + "android/hardware/automotive/evs/1.0/BsEvsCameraStream.h", + "android/hardware/automotive/evs/1.0/IEvsDisplay.h", + "android/hardware/automotive/evs/1.0/IHwEvsDisplay.h", + "android/hardware/automotive/evs/1.0/BnHwEvsDisplay.h", + "android/hardware/automotive/evs/1.0/BpHwEvsDisplay.h", + "android/hardware/automotive/evs/1.0/BsEvsDisplay.h", + "android/hardware/automotive/evs/1.0/IEvsEnumerator.h", + "android/hardware/automotive/evs/1.0/IHwEvsEnumerator.h", + "android/hardware/automotive/evs/1.0/BnHwEvsEnumerator.h", + "android/hardware/automotive/evs/1.0/BpHwEvsEnumerator.h", + "android/hardware/automotive/evs/1.0/BsEvsEnumerator.h", + ], +} + +cc_library_shared { + name: "android.hardware.automotive.evs@1.0", + generated_sources: ["android.hardware.automotive.evs@1.0_genc++"], + generated_headers: ["android.hardware.automotive.evs@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.automotive.evs@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/automotive/evs/1.0/IEvsCamera.hal b/automotive/evs/1.0/IEvsCamera.hal new file mode 100644 index 0000000..1b55d1f --- /dev/null +++ b/automotive/evs/1.0/IEvsCamera.hal
@@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 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.automotive.evs@1.0; + +import types; +import IEvsCameraStream; + + +/** + * Represents a single camera and is the primary interface for capturing images. + */ +interface IEvsCamera { + + /** + * Returns the ID of this camera. + * + * Returns the string id of this camera. This must be the same value as reported in + * the camera_id field of the CameraDesc structure by EvsEnumerator::getCamerList(). + */ + getId() generates (string cameraId); + + /** + * Specifies the depth of the buffer chain the camera is asked to support. + * + * Up to this many frames may be held concurrently by the client of IEvsCamera. + * If this many frames have been delivered to the receiver without being returned + * by doneWithFrame, the stream must skip frames until a buffer is returned for reuse. + * It is legal for this call to come at any time, even while streams are already running, + * in which case buffers should be added or removed from the chain as appropriate. + * If no call is made to this entry point, the IEvsCamera must support at least one + * frame by default. More is acceptable. + * BUFFER_NOT_AVAILABLE is returned if the implementation cannot support the + * requested number of concurrent frames. + */ + setMaxFramesInFlight(uint32_t bufferCount) generates (EvsResult result); + + /** + * Request delivery of EVS camera frames from this camera. + * + * The IEvsCameraStream must begin receiving periodic calls with new image + * frames until stopVideoStream() is called. + */ + startVideoStream(IEvsCameraStream receiver) generates (EvsResult result); + + /** + * Return a frame that was delivered by to the IEvsCameraStream. + * + * When done consuming a frame delivered to the IEvsCameraStream + * interface, it must be returned to the IEvsCamera for reuse. + * A small, finite number of buffers are available (possibly as small + * as one), and if the supply is exhausted, no further frames may be + * delivered until a buffer is returned. + */ + oneway doneWithFrame(BufferDesc buffer); + + /** + * Stop the delivery of EVS camera frames. + * + * Because delivery is asynchronous, frames may continue to arrive for + * some time after this call returns. Each must be returned until the + * closure of the stream is signaled to the IEvsCameraStream. + * This function cannot fail and is simply ignored if the stream isn't running. + */ + stopVideoStream(); + + /** + * Request driver specific information from the HAL implementation. + * + * The values allowed for opaqueIdentifier are driver specific, + * but no value passed in may crash the driver. The driver should + * return 0 for any unrecognized opaqueIdentifier. + */ + getExtendedInfo(uint32_t opaqueIdentifier) generates (int32_t value); + + /** + * Send a driver specific value to the HAL implementation. + * + * This extension is provided to facilitate car specific + * extensions, but no HAL implementation may require this call + * in order to function in a default state. + * INVALID_ARG is returned if the opaqueValue is not meaningful to + * the driver implementation. + */ + setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) generates (EvsResult result); +};
diff --git a/automotive/evs/1.0/IEvsCameraStream.hal b/automotive/evs/1.0/IEvsCameraStream.hal new file mode 100644 index 0000000..4e743b2 --- /dev/null +++ b/automotive/evs/1.0/IEvsCameraStream.hal
@@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 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.automotive.evs@1.0; + + +/** + * Implemented on client side to receive asynchronous video frame deliveries. + */ +interface IEvsCameraStream { + + /** + * Receives calls from the HAL each time a video frame is ready for inspection. + * Buffer handles received by this method must be returned via calls to + * IEvsCamera::doneWithFrame(). When the video stream is stopped via a call + * to IEvsCamera::stopVideoStream(), this callback may continue to happen for + * some time as the pipeline drains. Each frame must still be returned. + * When the last frame in the stream has been delivered, a NULL bufferHandle + * must be delivered, signifying the end of the stream. No further frame + * deliveries may happen thereafter. + */ + oneway deliverFrame(BufferDesc buffer); +};
diff --git a/automotive/evs/1.0/IEvsDisplay.hal b/automotive/evs/1.0/IEvsDisplay.hal new file mode 100644 index 0000000..bbad428 --- /dev/null +++ b/automotive/evs/1.0/IEvsDisplay.hal
@@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 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.automotive.evs@1.0; + +import types; + + +/** + * Represents a single camera and is the primary interface for capturing images. + */ +interface IEvsDisplay { + + /** + * Returns basic information about the EVS display provided by the system. + * + * See the description of the DisplayDesc structure below for details. + */ + getDisplayInfo() generates (DisplayDesc info); + + + /** + * Clients may set the display state to express their desired state. + * + * The HAL implementation must gracefully accept a request for any state while in + * any other state, although the response may be to defer or ignore the request. The display + * is defined to start in the NOT_VISIBLE state upon initialization. The client is + * then expected to request the VISIBLE_ON_NEXT_FRAME state, and then begin providing + * video. When the display is no longer required, the client is expected to request + * the NOT_VISIBLE state after passing the last video frame. + * Returns INVALID_ARG if the requested state is not a recognized value. + */ + setDisplayState(DisplayState state) generates (EvsResult result); + + + /** + * This call requests the current state of the display + * + * The HAL implementation should report the actual current state, which might + * transiently differ from the most recently requested state. Note, however, that + * the logic responsible for changing display states should generally live above + * the device layer, making it undesirable for the HAL implementation to spontaneously + * change display states. + */ + getDisplayState() generates (DisplayState state); + + + /** + * This call returns a handle to a frame buffer associated with the display. + * + * The returned buffer may be locked and written to by software and/or GL. This buffer + * must be returned via a call to returnTargetBufferForDisplay() even if the + * display is no longer visible. + */ + getTargetBuffer() generates (BufferDesc buffer); + + + /** + * This call tells the display that the buffer is ready for display. + * + * The buffer is no longer valid for use by the client after this call. + * There is no maximum time the caller may hold onto the buffer before making this + * call. The buffer may be returned at any time and in any DisplayState, but all + * buffers are expected to be returned before the IEvsDisplay interface is destroyed. + */ + returnTargetBufferForDisplay(BufferDesc buffer) generates (EvsResult result); +};
diff --git a/automotive/evs/1.0/IEvsEnumerator.hal b/automotive/evs/1.0/IEvsEnumerator.hal new file mode 100644 index 0000000..334430b --- /dev/null +++ b/automotive/evs/1.0/IEvsEnumerator.hal
@@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 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.automotive.evs@1.0; + +import types; +import IEvsCamera; +import IEvsDisplay; + + +/** + * Provides the mechanism for EVS camera discovery + */ +interface IEvsEnumerator { + + /** + * Returns a list of all EVS cameras available to the system + */ + getCameraList() generates (vec<CameraDesc> cameras); + + + /** + * Get the IEvsCamera associated with a cameraId from a CameraDesc + * + * Given a camera's unique cameraId from ca CameraDesc, returns + * the ICamera interface assocaited with the specified camera. + * When done using the camera, it must be returned by calling + * closeCamera on the ICamera interface. + */ + openCamera(string cameraId) generates (IEvsCamera carCamera); + + /** + * Return the specified IEvsCamera interface as no longer in use + * + * When the IEvsCamera object is no longer required, it must be released. + * NOTE: Video streaming must be cleanly stopped before making this call. + */ + closeCamera(IEvsCamera carCamera); + + + /** + * Get exclusive access to IEvsDisplay for the system + * + * There can be at most one EVS display object for the system and this function + * requests access to it. If the EVS display is not available or is already in use, + * a null pointer is returned. + */ + openDisplay() generates (IEvsDisplay display); + + /** + * Return the specified IEvsDisplay interface as no longer in use + * + * When the IEvsDisplay object is no longer required, it must be released. + * NOTE: All buffer must have been returned to the display before making this call. + */ + closeDisplay(IEvsDisplay display); + + /** + * This call requests the current state of the display + * + * If there is no open display, this returns DisplayState::NOT_OPEN. otherwise, it returns + * the actual state of the active display. This call is replicated on the IEvsEnumerator + * interface in order to allow secondary clients to monitor the state of the EVS display + * without acquiring exclusive ownership of the display. + */ + getDisplayState() generates (DisplayState state); +}; +
diff --git a/automotive/evs/1.0/default/Android.bp b/automotive/evs/1.0/default/Android.bp new file mode 100644 index 0000000..8b214e3 --- /dev/null +++ b/automotive/evs/1.0/default/Android.bp
@@ -0,0 +1,26 @@ +cc_binary { + name: "android.hardware.automotive.evs@1.0-service", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: [ + "service.cpp", + "EvsCamera.cpp", + "EvsEnumerator.cpp", + "EvsDisplay.cpp" + ], + init_rc: ["android.hardware.automotive.evs@1.0-service.rc"], + + shared_libs: [ + "android.hardware.automotive.evs@1.0", + "libui", + "libbase", + "libbinder", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], +}
diff --git a/automotive/evs/1.0/default/EvsCamera.cpp b/automotive/evs/1.0/default/EvsCamera.cpp new file mode 100644 index 0000000..c4436ee --- /dev/null +++ b/automotive/evs/1.0/default/EvsCamera.cpp
@@ -0,0 +1,493 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.automotive.evs@1.0-service" + +#include "EvsCamera.h" + +#include <ui/GraphicBufferAllocator.h> +#include <ui/GraphicBufferMapper.h> + + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_0 { +namespace implementation { + + +// These are the special camera names for which we'll initialize custom test data +const char EvsCamera::kCameraName_Backup[] = "backup"; +const char EvsCamera::kCameraName_RightTurn[] = "Right Turn"; + +// Arbitrary limit on number of graphics buffers allowed to be allocated +// Safeguards against unreasonable resource consumption and provides a testable limit +const unsigned MAX_BUFFERS_IN_FLIGHT = 100; + + +// TODO(b/31632518): Need to get notification when our client dies so we can close the camera. +// As it stands, if the client dies suddenly, the buffer may be stranded. + +EvsCamera::EvsCamera(const char *id) : + mFramesAllowed(0), + mFramesInUse(0), + mStreamState(STOPPED) { + + ALOGD("EvsCamera instantiated"); + + mDescription.cameraId = id; + + // Set up dummy data for testing + if (mDescription.cameraId == kCameraName_Backup) { + mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_REVERSE); + mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value + mDescription.defaultHorResolution = 320; // 1/2 NTSC/VGA + mDescription.defaultVerResolution = 240; // 1/2 NTSC/VGA + } else if (mDescription.cameraId == kCameraName_RightTurn) { + // Nothing but the name and the usage hint + mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_RIGHT_TURN); + } else { + // Leave empty for a minimalist camera description without even a hint + } + + + // Set our buffer properties + mWidth = (mDescription.defaultHorResolution) ? mDescription.defaultHorResolution : 640; + mHeight = (mDescription.defaultVerResolution) ? mDescription.defaultVerResolution : 480; + + mFormat = HAL_PIXEL_FORMAT_RGBA_8888; + mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE | + GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY; +} + + +EvsCamera::~EvsCamera() { + ALOGD("EvsCamera being destroyed"); + std::lock_guard<std::mutex> lock(mAccessLock); + + // Make sure our output stream is cleaned up + // (It really should be already) + stopVideoStream(); + + // Drop all the graphics buffers we've been using + GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); + for (auto&& rec : mBuffers) { + if (rec.inUse) { + ALOGE("Error - releasing buffer despite remote ownership"); + } + alloc.free(rec.handle); + rec.handle = nullptr; + } + + ALOGD("EvsCamera destroyed"); +} + + +// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow. +Return<void> EvsCamera::getId(getId_cb id_cb) { + ALOGD("getId"); + + id_cb(mDescription.cameraId); + + return Void(); +} + + +Return<EvsResult> EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) { + ALOGD("setMaxFramesInFlight"); + std::lock_guard<std::mutex> lock(mAccessLock); + + // We cannot function without at least one video buffer to send data + if (bufferCount < 1) { + ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested"); + return EvsResult::INVALID_ARG; + } + + // Update our internal state + if (setAvailableFrames_Locked(bufferCount)) { + return EvsResult::OK; + } else { + return EvsResult::BUFFER_NOT_AVAILABLE; + } +} + + +Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStream>& stream) { + ALOGD("startVideoStream"); + std::lock_guard<std::mutex> lock(mAccessLock); + + if (mStreamState != STOPPED) { + ALOGE("ignoring startVideoStream call when a stream is already running."); + return EvsResult::STREAM_ALREADY_RUNNING; + } + + // If the client never indicated otherwise, configure ourselves for a single streaming buffer + if (mFramesAllowed < 1) { + if (!setAvailableFrames_Locked(1)) { + ALOGE("Failed to start stream because we couldn't get a graphics buffer"); + return EvsResult::BUFFER_NOT_AVAILABLE; + } + } + + // Record the user's callback for use when we have a frame ready + mStream = stream; + + // Start the frame generation thread + mStreamState = RUNNING; + mCaptureThread = std::thread([this](){ generateFrames(); }); + + return EvsResult::OK; +} + + +Return<void> EvsCamera::doneWithFrame(const BufferDesc& buffer) { + ALOGD("doneWithFrame"); + { // lock context + std::lock_guard <std::mutex> lock(mAccessLock); + + if (buffer.memHandle == nullptr) { + ALOGE("ignoring doneWithFrame called with null handle"); + } else if (buffer.bufferId >= mBuffers.size()) { + ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)", + buffer.bufferId, mBuffers.size()-1); + } else if (!mBuffers[buffer.bufferId].inUse) { + ALOGE("ignoring doneWithFrame called on frame %d which is already free", + buffer.bufferId); + } else { + // Mark the frame as available + mBuffers[buffer.bufferId].inUse = false; + mFramesInUse--; + + // If this frame's index is high in the array, try to move it down + // to improve locality after mFramesAllowed has been reduced. + if (buffer.bufferId >= mFramesAllowed) { + // Find an empty slot lower in the array (which should always exist in this case) + for (auto&& rec : mBuffers) { + if (rec.handle == nullptr) { + rec.handle = mBuffers[buffer.bufferId].handle; + mBuffers[buffer.bufferId].handle = nullptr; + break; + } + } + } + } + } + + return Void(); +} + + +Return<void> EvsCamera::stopVideoStream() { + ALOGD("stopVideoStream"); + std::unique_lock <std::mutex> lock(mAccessLock); + + if (mStreamState == RUNNING) { + // Tell the GenerateFrames loop we want it to stop + mStreamState = STOPPING; + + // Block outside the mutex until the "stop" flag has been acknowledged + // We won't send any more frames, but the client might still get some already in flight + ALOGD("Waiting for stream thread to end..."); + lock.unlock(); + mCaptureThread.join(); + lock.lock(); + + mStreamState = STOPPED; + ALOGD("Stream marked STOPPED."); + } + + return Void(); +} + + +Return<int32_t> EvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) { + ALOGD("getExtendedInfo"); + std::lock_guard<std::mutex> lock(mAccessLock); + + // For any single digit value, return the index itself as a test value + if (opaqueIdentifier <= 9) { + return opaqueIdentifier; + } + + // Return zero by default as required by the spec + return 0; +} + + +Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int32_t /*opaqueValue*/) { + ALOGD("setExtendedInfo"); + std::lock_guard<std::mutex> lock(mAccessLock); + + // We don't store any device specific information in this implementation + return EvsResult::INVALID_ARG; +} + + +bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) { + if (bufferCount < 1) { + ALOGE("Ignoring request to set buffer count to zero"); + return false; + } + if (bufferCount > MAX_BUFFERS_IN_FLIGHT) { + ALOGE("Rejecting buffer request in excess of internal limit"); + return false; + } + + // Is an increase required? + if (mFramesAllowed < bufferCount) { + // An increase is required + unsigned needed = bufferCount - mFramesAllowed; + ALOGI("Allocating %d buffers for camera frames", needed); + + unsigned added = increaseAvailableFrames_Locked(needed); + if (added != needed) { + // If we didn't add all the frames we needed, then roll back to the previous state + ALOGE("Rolling back to previous frame queue size"); + decreaseAvailableFrames_Locked(added); + return false; + } + } else if (mFramesAllowed > bufferCount) { + // A decrease is required + unsigned framesToRelease = mFramesAllowed - bufferCount; + ALOGI("Returning %d camera frame buffers", framesToRelease); + + unsigned released = decreaseAvailableFrames_Locked(framesToRelease); + if (released != framesToRelease) { + // This shouldn't happen with a properly behaving client because the client + // should only make this call after returning sufficient outstanding buffers + // to allow a clean resize. + ALOGE("Buffer queue shrink failed -- too many buffers currently in use?"); + } + } + + return true; +} + + +unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) { + // Acquire the graphics buffer allocator + GraphicBufferAllocator &alloc(GraphicBufferAllocator::get()); + + unsigned added = 0; + + while (added < numToAdd) { + buffer_handle_t memHandle = nullptr; + status_t result = alloc.allocate(mWidth, mHeight, + mFormat, 1, + mUsage, mUsage, + &memHandle, &mStride, 0, "EvsCamera"); + if (result != NO_ERROR) { + ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight); + break; + } + if (!memHandle) { + ALOGE("We didn't get a buffer handle back from the allocator"); + break; + } + + // Find a place to store the new buffer + bool stored = false; + for (auto&& rec : mBuffers) { + if (rec.handle == nullptr) { + // Use this existing entry + rec.handle = memHandle; + rec.inUse = false; + stored = true; + break; + } + } + if (!stored) { + // Add a BufferRecord wrapping this handle to our set of available buffers + mBuffers.emplace_back(memHandle); + } + + mFramesAllowed++; + added++; + } + + return added; +} + + +unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) { + // Acquire the graphics buffer allocator + GraphicBufferAllocator &alloc(GraphicBufferAllocator::get()); + + unsigned removed = 0; + + for (auto&& rec : mBuffers) { + // Is this record not in use, but holding a buffer that we can free? + if ((rec.inUse == false) && (rec.handle != nullptr)) { + // Release buffer and update the record so we can recognize it as "empty" + alloc.free(rec.handle); + rec.handle = nullptr; + + mFramesAllowed--; + removed++; + + if (removed == numToRemove) { + break; + } + } + } + + return removed; +} + + +// This is the asynchronous frame generation thread that runs in parallel with the +// main serving thread. There is one for each active camera instance. +void EvsCamera::generateFrames() { + ALOGD("Frame generation loop started"); + + unsigned idx; + + while (true) { + bool timeForFrame = false; + // Lock scope + { + std::lock_guard<std::mutex> lock(mAccessLock); + + if (mStreamState != RUNNING) { + // Break out of our main thread loop + break; + } + + // Are we allowed to issue another buffer? + if (mFramesInUse >= mFramesAllowed) { + // Can't do anything right now -- skip this frame + ALOGW("Skipped a frame because too many are in flight\n"); + } else { + // Identify an available buffer to fill + for (idx = 0; idx < mBuffers.size(); idx++) { + if (!mBuffers[idx].inUse) { + if (mBuffers[idx].handle != nullptr) { + // Found an available record, so stop looking + break; + } + } + } + if (idx >= mBuffers.size()) { + // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed + ALOGE("Failed to find an available buffer slot\n"); + } else { + // We're going to make the frame busy + mBuffers[idx].inUse = true; + mFramesInUse++; + timeForFrame = true; + } + } + } + + if (timeForFrame) { + // Assemble the buffer description we'll transmit below + BufferDesc buff = {}; + buff.width = mWidth; + buff.height = mHeight; + buff.stride = mStride; + buff.format = mFormat; + buff.usage = mUsage; + buff.bufferId = idx; + buff.memHandle = mBuffers[idx].handle; + + // Write test data into the image buffer + fillTestFrame(buff); + + // Issue the (asynchronous) callback to the client -- can't be holding the lock + auto result = mStream->deliverFrame(buff); + if (result.isOk()) { + ALOGD("Delivered %p as id %d", buff.memHandle.getNativeHandle(), buff.bufferId); + } else { + // This can happen if the client dies and is likely unrecoverable. + // To avoid consuming resources generating failing calls, we stop sending + // frames. Note, however, that the stream remains in the "STREAMING" state + // until cleaned up on the main thread. + ALOGE("Frame delivery call failed in the transport layer."); + + // Since we didn't actually deliver it, mark the frame as available + std::lock_guard<std::mutex> lock(mAccessLock); + mBuffers[idx].inUse = false; + mFramesInUse--; + + break; + } + } + + // We arbitrarily choose to generate frames at 10 fps (1/10 * uSecPerSec) + usleep(100000); + } + + // If we've been asked to stop, send one last NULL frame to signal the actual end of stream + BufferDesc nullBuff = {}; + auto result = mStream->deliverFrame(nullBuff); + if (!result.isOk()) { + ALOGE("Error delivering end of stream marker"); + } + + return; +} + + +void EvsCamera::fillTestFrame(const BufferDesc& buff) { + // Lock our output buffer for writing + uint32_t *pixels = nullptr; + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + mapper.lock(buff.memHandle, + GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER, + android::Rect(buff.width, buff.height), + (void **) &pixels); + + // If we failed to lock the pixel buffer, we're about to crash, but log it first + if (!pixels) { + ALOGE("Camera failed to gain access to image buffer for writing"); + } + + // Fill in the test pixels + for (unsigned row = 0; row < buff.height; row++) { + for (unsigned col = 0; col < buff.width; col++) { + // Index into the row to check the pixel at this column. + // We expect 0xFF in the LSB channel, a vertical gradient in the + // second channel, a horitzontal gradient in the third channel, and + // 0xFF in the MSB. + // The exception is the very first 32 bits which is used for the + // time varying frame signature to avoid getting fooled by a static image. + uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB + ((row & 0xFF) << 8) | // vertical gradient + ((col & 0xFF) << 16); // horizontal gradient + if ((row | col) == 0) { + static uint32_t sFrameTicker = 0; + expectedPixel = (sFrameTicker) & 0xFF; + sFrameTicker++; + } + pixels[col] = expectedPixel; + } + // Point to the next row + // NOTE: stride retrieved from gralloc is in units of pixels + pixels = pixels + buff.stride; + } + + // Release our output buffer + mapper.unlock(buff.memHandle); +} + + +} // namespace implementation +} // namespace V1_0 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/evs/1.0/default/EvsCamera.h b/automotive/evs/1.0/default/EvsCamera.h new file mode 100644 index 0000000..ee91ca4 --- /dev/null +++ b/automotive/evs/1.0/default/EvsCamera.h
@@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERA_H +#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERA_H + +#include <android/hardware/automotive/evs/1.0/types.h> +#include <android/hardware/automotive/evs/1.0/IEvsCamera.h> +#include <ui/GraphicBuffer.h> + +#include <thread> + + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_0 { +namespace implementation { + + +class EvsCamera : public IEvsCamera { +public: + // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow. + Return<void> getId(getId_cb id_cb) override; + + Return <EvsResult> setMaxFramesInFlight(uint32_t bufferCount) override; + + Return <EvsResult> startVideoStream(const ::android::sp<IEvsCameraStream>& stream) override; + + Return<void> doneWithFrame(const BufferDesc& buffer) override; + + Return<void> stopVideoStream() override; + + Return <int32_t> getExtendedInfo(uint32_t opaqueIdentifier) override; + + Return <EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override; + + // Implementation details + EvsCamera(const char* id); + + virtual ~EvsCamera() override; + + const CameraDesc& getDesc() { return mDescription; }; + + static const char kCameraName_Backup[]; + static const char kCameraName_RightTurn[]; + +private: + // These three functions are expected to be called while mAccessLock is held + bool setAvailableFrames_Locked(unsigned bufferCount); + + unsigned increaseAvailableFrames_Locked(unsigned numToAdd); + + unsigned decreaseAvailableFrames_Locked(unsigned numToRemove); + + void generateFrames(); + + void fillTestFrame(const BufferDesc& buff); + + CameraDesc mDescription = {}; // The properties of this camera + + std::thread mCaptureThread; // The thread we'll use to synthesize frames + + uint32_t mWidth = 0; // Horizontal pixel count in the buffers + uint32_t mHeight = 0; // Vertical pixel count in the buffers + uint32_t mFormat = 0; // Values from android_pixel_format_t [TODO: YUV? Leave opaque?] + uint32_t mUsage = 0; // Values from from Gralloc.h + uint32_t mStride = 0; // Bytes per line in the buffers + + sp <IEvsCameraStream> mStream = nullptr; // The callback used to deliver each frame + + struct BufferRecord { + buffer_handle_t handle; + bool inUse; + + explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false) {}; + }; + + std::vector <BufferRecord> mBuffers; // Graphics buffers to transfer images + unsigned mFramesAllowed; // How many buffers are we currently using + unsigned mFramesInUse; // How many buffers are currently outstanding + + enum StreamStateValues { + STOPPED, + RUNNING, + STOPPING, + }; + StreamStateValues mStreamState; + + // Syncrhonization necessary to deconflict mCaptureThread from the main service thread + std::mutex mAccessLock; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERA_H
diff --git a/automotive/evs/1.0/default/EvsDisplay.cpp b/automotive/evs/1.0/default/EvsDisplay.cpp new file mode 100644 index 0000000..a1a76d0 --- /dev/null +++ b/automotive/evs/1.0/default/EvsDisplay.cpp
@@ -0,0 +1,308 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.automotive.evs@1.0-service" + +#include "EvsDisplay.h" + +#include <ui/GraphicBufferAllocator.h> +#include <ui/GraphicBufferMapper.h> + + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_0 { +namespace implementation { + + +// TODO(b/31632518): Need to get notification when our client dies so we can close the camera. +// As it stands, if the client dies suddently, the buffer may be stranded. +// As possible work around would be to give the client a HIDL object to exclusively hold +// and use it's destructor to perform some work in the server side. + + +EvsDisplay::EvsDisplay() { + ALOGD("EvsDisplay instantiated"); + + // Set up our self description + // NOTE: These are arbitrary values chosen for testing + mInfo.displayId = "Mock Display"; + mInfo.vendorFlags = 3870; + mInfo.defaultHorResolution = 320; + mInfo.defaultVerResolution = 240; +} + + +EvsDisplay::~EvsDisplay() { + ALOGD("EvsDisplay being destroyed"); + std::lock_guard<std::mutex> lock(mAccessLock); + + // Report if we're going away while a buffer is outstanding + if (mFrameBusy) { + ALOGE("EvsDisplay going down while client is holding a buffer"); + } + + // Make sure we release our frame buffer + if (mBuffer.memHandle) { + // Drop the graphics buffer we've been using + GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); + alloc.free(mBuffer.memHandle); + mBuffer.memHandle = nullptr; + } + ALOGD("EvsDisplay destroyed"); +} + + +/** + * Returns basic information about the EVS display provided by the system. + * See the description of the DisplayDesc structure below for details. + */ +Return<void> EvsDisplay::getDisplayInfo(getDisplayInfo_cb _hidl_cb) { + ALOGD("getDisplayInfo"); + + // Send back our self description + _hidl_cb(mInfo); + return Void(); +} + + +/** + * Clients may set the display state to express their desired state. + * The HAL implementation must gracefully accept a request for any state + * while in any other state, although the response may be to ignore the request. + * The display is defined to start in the NOT_VISIBLE state upon initialization. + * The client is then expected to request the VISIBLE_ON_NEXT_FRAME state, and + * then begin providing video. When the display is no longer required, the client + * is expected to request the NOT_VISIBLE state after passing the last video frame. + */ +Return<EvsResult> EvsDisplay::setDisplayState(DisplayState state) { + ALOGD("setDisplayState"); + std::lock_guard<std::mutex> lock(mAccessLock); + + // Ensure we recognize the requested state so we don't go off the rails + if (state < DisplayState::NUM_STATES) { + // Record the requested state + mRequestedState = state; + return EvsResult::OK; + } + else { + // Turn off the display if asked for an unrecognized state + mRequestedState = DisplayState::NOT_VISIBLE; + return EvsResult::INVALID_ARG; + } +} + + +/** + * The HAL implementation should report the actual current state, which might + * transiently differ from the most recently requested state. Note, however, that + * the logic responsible for changing display states should generally live above + * the device layer, making it undesirable for the HAL implementation to + * spontaneously change display states. + */ +Return<DisplayState> EvsDisplay::getDisplayState() { + ALOGD("getDisplayState"); + std::lock_guard<std::mutex> lock(mAccessLock); + + // At the moment, we treat the requested state as immediately active + DisplayState currentState = mRequestedState; + + return currentState; +} + + +/** + * This call returns a handle to a frame buffer associated with the display. + * This buffer may be locked and written to by software and/or GL. This buffer + * must be returned via a call to returnTargetBufferForDisplay() even if the + * display is no longer visible. + */ +// TODO: We need to know if/when our client dies so we can get the buffer back! (blocked b/31632518) +Return<void> EvsDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb) { + ALOGD("getTargetBuffer"); + std::lock_guard<std::mutex> lock(mAccessLock); + + // If we don't already have a buffer, allocate one now + if (!mBuffer.memHandle) { + // Assemble the buffer description we'll use for our render target + mBuffer.width = mInfo.defaultHorResolution; + mBuffer.height = mInfo.defaultVerResolution; + mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888; + mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER; + mBuffer.bufferId = 0x3870; // Arbitrary magic number for self recognition + + buffer_handle_t handle = nullptr; + GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); + status_t result = alloc.allocate(mBuffer.width, mBuffer.height, + mBuffer.format, 1, mBuffer.usage, + mBuffer.usage, &handle, + &mBuffer.stride, + 0, "EvsDisplay"); + if (result != NO_ERROR) { + ALOGE("Error %d allocating %d x %d graphics buffer", + result, mBuffer.width, mBuffer.height); + BufferDesc nullBuff = {}; + _hidl_cb(nullBuff); + return Void(); + } + if (!handle) { + ALOGE("We didn't get a buffer handle back from the allocator"); + BufferDesc nullBuff = {}; + _hidl_cb(nullBuff); + return Void(); + } + + mBuffer.memHandle = handle; + mFrameBusy = false; + ALOGD("Allocated new buffer %p with stride %u", + mBuffer.memHandle.getNativeHandle(), mBuffer.stride); + } + + // Do we have a frame available? + if (mFrameBusy) { + // This means either we have a 2nd client trying to compete for buffers + // (an unsupported mode of operation) or else the client hasn't returned + // a previously issued buffer yet (they're behaving badly). + // NOTE: We have to make the callback even if we have nothing to provide + ALOGE("getTargetBuffer called while no buffers available."); + BufferDesc nullBuff = {}; + _hidl_cb(nullBuff); + return Void(); + } else { + // Mark our buffer as busy + mFrameBusy = true; + + // Send the buffer to the client + ALOGD("Providing display buffer handle %p as id %d", + mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId); + _hidl_cb(mBuffer); + return Void(); + } +} + + +/** + * This call tells the display that the buffer is ready for display. + * The buffer is no longer valid for use by the client after this call. + */ +Return<EvsResult> EvsDisplay::returnTargetBufferForDisplay(const BufferDesc& buffer) { + ALOGD("returnTargetBufferForDisplay %p", buffer.memHandle.getNativeHandle()); + std::lock_guard<std::mutex> lock(mAccessLock); + + // Nobody should call us with a null handle + if (!buffer.memHandle.getNativeHandle()) { + ALOGE ("returnTargetBufferForDisplay called without a valid buffer handle.\n"); + return EvsResult::INVALID_ARG; + } + if (buffer.bufferId != mBuffer.bufferId) { + ALOGE ("Got an unrecognized frame returned.\n"); + return EvsResult::INVALID_ARG; + } + if (!mFrameBusy) { + ALOGE ("A frame was returned with no outstanding frames.\n"); + return EvsResult::BUFFER_NOT_AVAILABLE; + } + + mFrameBusy = false; + + // If we were waiting for a new frame, this is it! + if (mRequestedState == DisplayState::VISIBLE_ON_NEXT_FRAME) { + mRequestedState = DisplayState::VISIBLE; + } + + // Validate we're in an expected state + if (mRequestedState != DisplayState::VISIBLE) { + // We shouldn't get frames back when we're not visible. + ALOGE ("Got an unexpected frame returned while not visible - ignoring.\n"); + } else { + // This is where the buffer would be made visible. + // For now we simply validate it has the data we expect in it by reading it back + + // Lock our display buffer for reading + uint32_t* pixels = nullptr; + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + mapper.lock(mBuffer.memHandle, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, + android::Rect(mBuffer.width, mBuffer.height), + (void **)&pixels); + + // If we failed to lock the pixel buffer, we're about to crash, but log it first + if (!pixels) { + ALOGE("Display failed to gain access to image buffer for reading"); + } + + // Check the test pixels + bool frameLooksGood = true; + for (unsigned row = 0; row < mInfo.defaultVerResolution; row++) { + for (unsigned col = 0; col < mInfo.defaultHorResolution; col++) { + // Index into the row to check the pixel at this column. + // We expect 0xFF in the LSB channel, a vertical gradient in the + // second channel, a horitzontal gradient in the third channel, and + // 0xFF in the MSB. + // The exception is the very first 32 bits which is used for the + // time varying frame signature to avoid getting fooled by a static image. + uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB + ((row & 0xFF) << 8) | // vertical gradient + ((col & 0xFF) << 16); // horizontal gradient + if ((row | col) == 0) { + // we'll check the "uniqueness" of the frame signature below + continue; + } + // Walk across this row (we'll step rows below) + uint32_t receivedPixel = pixels[col]; + if (receivedPixel != expectedPixel) { + ALOGE("Pixel check mismatch in frame buffer"); + frameLooksGood = false; + break; + } + } + + if (!frameLooksGood) { + break; + } + + // Point to the next row (NOTE: gralloc reports stride in units of pixels) + pixels = pixels + mBuffer.stride; + } + + // Ensure we don't see the same buffer twice without it being rewritten + static uint32_t prevSignature = ~0; + uint32_t signature = pixels[0] & 0xFF; + if (prevSignature == signature) { + frameLooksGood = false; + ALOGE("Duplicate, likely stale frame buffer detected"); + } + + + // Release our output buffer + mapper.unlock(mBuffer.memHandle); + + if (!frameLooksGood) { + return EvsResult::UNDERLYING_SERVICE_ERROR; + } + } + + return EvsResult::OK; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/evs/1.0/default/EvsDisplay.h b/automotive/evs/1.0/default/EvsDisplay.h new file mode 100644 index 0000000..fcf4a06 --- /dev/null +++ b/automotive/evs/1.0/default/EvsDisplay.h
@@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSDISPLAY_H +#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSDISPLAY_H + +#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h> +#include <ui/GraphicBuffer.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_0 { +namespace implementation { + +class EvsDisplay : public IEvsDisplay { +public: + // Methods from ::android::hardware::automotive::evs::V1_0::IEvsDisplay follow. + Return<void> getDisplayInfo(getDisplayInfo_cb _hidl_cb) override; + Return<EvsResult> setDisplayState(DisplayState state) override; + Return<DisplayState> getDisplayState() override; + Return<void> getTargetBuffer(getTargetBuffer_cb _hidl_cb) override; + Return<EvsResult> returnTargetBufferForDisplay(const BufferDesc& buffer) override; + + // Implementation details + EvsDisplay(); + virtual ~EvsDisplay() override; + +private: + DisplayDesc mInfo = {}; + BufferDesc mBuffer = {}; // A graphics buffer into which we'll store images + + bool mFrameBusy = false; // A flag telling us our buffer is in use + DisplayState mRequestedState = DisplayState::NOT_VISIBLE; + + std::mutex mAccessLock; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSDISPLAY_H
diff --git a/automotive/evs/1.0/default/EvsEnumerator.cpp b/automotive/evs/1.0/default/EvsEnumerator.cpp new file mode 100644 index 0000000..e54f699 --- /dev/null +++ b/automotive/evs/1.0/default/EvsEnumerator.cpp
@@ -0,0 +1,174 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.automotive.evs@1.0-service" + +#include "EvsEnumerator.h" +#include "EvsCamera.h" +#include "EvsDisplay.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_0 { +namespace implementation { + + +// TODO(b/31632518): Need to get notification when our client dies so we can close the camera. +// As it stands, if the client dies suddenly, the camera will be stuck "open". +// NOTE: Display should already be safe by virtue of holding only a weak pointer. + + +EvsEnumerator::EvsEnumerator() { + ALOGD("EvsEnumerator created"); + + // Add sample camera data to our list of cameras + // NOTE: The id strings trigger special initialization inside the EvsCamera constructor + mCameraList.emplace_back( new EvsCamera(EvsCamera::kCameraName_Backup), false ); + mCameraList.emplace_back( new EvsCamera("LaneView"), false ); + mCameraList.emplace_back( new EvsCamera(EvsCamera::kCameraName_RightTurn), false ); +} + +// Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow. +Return<void> EvsEnumerator::getCameraList(getCameraList_cb _hidl_cb) { + ALOGD("getCameraList"); + + const unsigned numCameras = mCameraList.size(); + + // Build up a packed array of CameraDesc for return + // NOTE: Only has to live until the callback returns + std::vector<CameraDesc> descriptions; + descriptions.reserve(numCameras); + for (const auto& cam : mCameraList) { + descriptions.push_back( cam.pCamera->getDesc() ); + } + + // Encapsulate our camera descriptions in the HIDL vec type + hidl_vec<CameraDesc> hidlCameras(descriptions); + + // Send back the results + ALOGD("reporting %zu cameras available", hidlCameras.size()); + _hidl_cb(hidlCameras); + + // HIDL convention says we return Void if we sent our result back via callback + return Void(); +} + +Return<sp<IEvsCamera>> EvsEnumerator::openCamera(const hidl_string& cameraId) { + ALOGD("openCamera"); + + // Find the named camera + CameraRecord *pRecord = nullptr; + for (auto &&cam : mCameraList) { + if (cam.pCamera->getDesc().cameraId == cameraId) { + // Found a match! + pRecord = &cam; + break; + } + } + + if (!pRecord) { + ALOGE("Requested camera %s not found", cameraId.c_str()); + return nullptr; + } else if (pRecord->inUse) { + ALOGE("Cannot open camera %s which is already in use", cameraId.c_str()); + return nullptr; + } else { + pRecord->inUse = true; + return(pRecord->pCamera); + } +} + +Return<void> EvsEnumerator::closeCamera(const ::android::sp<IEvsCamera>& camera) { + ALOGD("closeCamera"); + + if (camera == nullptr) { + ALOGE("Ignoring call to closeCamera with null camera pointer"); + } else { + // Find this camera in our list + auto it = std::find_if(mCameraList.begin(), + mCameraList.end(), + [camera](const CameraRecord& rec) { + return (rec.pCamera == camera); + }); + if (it == mCameraList.end()) { + ALOGE("Ignoring close on unrecognized camera"); + } else { + // Make sure the camera has stopped streaming + camera->stopVideoStream(); + + it->inUse = false; + } + } + + return Void(); +} + +Return<sp<IEvsDisplay>> EvsEnumerator::openDisplay() { + ALOGD("openDisplay"); + + // If we already have a display active, then this request must be denied + sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote(); + if (pActiveDisplay != nullptr) { + ALOGW("Rejecting openDisplay request the display is already in use."); + return nullptr; + } else { + // Create a new display interface and return it + pActiveDisplay = new EvsDisplay(); + mActiveDisplay = pActiveDisplay; + ALOGD("Returning new EvsDisplay object %p", pActiveDisplay.get()); + return pActiveDisplay; + } +} + +Return<void> EvsEnumerator::closeDisplay(const ::android::sp<IEvsDisplay>& display) { + ALOGD("closeDisplay"); + + // Do we still have a display object we think should be active? + sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote(); + + if (pActiveDisplay == nullptr) { + ALOGE("Ignoring closeDisplay when there is no active display."); + } else if (display != pActiveDisplay) { + ALOGE("Ignoring closeDisplay on a display we didn't issue"); + ALOGI("Got %p while active display is %p.", display.get(), pActiveDisplay.get()); + } else { + // Drop the active display + mActiveDisplay = nullptr; + } + + return Void(); +} + +Return<DisplayState> EvsEnumerator::getDisplayState() { + ALOGD("getDisplayState"); + + // Do we still have a display object we think should be active? + sp<IEvsDisplay> pActiveDisplay = mActiveDisplay.promote(); + if (pActiveDisplay != nullptr) { + return pActiveDisplay->getDisplayState(); + } else { + return DisplayState::NOT_OPEN; + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/evs/1.0/default/EvsEnumerator.h b/automotive/evs/1.0/default/EvsEnumerator.h new file mode 100644 index 0000000..3d6e264 --- /dev/null +++ b/automotive/evs/1.0/default/EvsEnumerator.h
@@ -0,0 +1,65 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H +#define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H + +#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h> +#include <android/hardware/automotive/evs/1.0/IEvsCamera.h> + +#include <list> + +#include "EvsCamera.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace evs { +namespace V1_0 { +namespace implementation { + +class EvsEnumerator : public IEvsEnumerator { +public: + // Methods from ::android::hardware::automotive::evs::V1_0::IEvsEnumerator follow. + Return<void> getCameraList(getCameraList_cb _hidl_cb) override; + Return<sp<IEvsCamera>> openCamera(const hidl_string& cameraId) override; + Return<void> closeCamera(const ::android::sp<IEvsCamera>& carCamera) override; + Return<sp<IEvsDisplay>> openDisplay() override; + Return<void> closeDisplay(const ::android::sp<IEvsDisplay>& display) override; + Return<DisplayState> getDisplayState() override; + + // Implementation details + EvsEnumerator(); + +private: + struct CameraRecord { + sp<EvsCamera> pCamera; + bool inUse; + CameraRecord(EvsCamera* p, bool b) : pCamera(p), inUse(b) {} + }; + std::list<CameraRecord> mCameraList; + + wp<IEvsDisplay> mActiveDisplay; // Weak pointer -> object destructs if client dies +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace evs +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_0_EVSCAMERAENUMERATOR_H
diff --git a/automotive/evs/1.0/default/ServiceNames.h b/automotive/evs/1.0/default/ServiceNames.h new file mode 100644 index 0000000..d20a37f --- /dev/null +++ b/automotive/evs/1.0/default/ServiceNames.h
@@ -0,0 +1,17 @@ +/* + * Copyright (C) 2016 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. + */ + +const static char kEnumeratorServiceName[] = "EvsEnumeratorHw-Mock";
diff --git a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc new file mode 100644 index 0000000..8957ecf --- /dev/null +++ b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
@@ -0,0 +1,4 @@ +service evs-hal-1-0 /vendor/bin/hw/android.hardware.automotive.evs@1.0-service + class hal + user cameraserver + group camera
diff --git a/automotive/evs/1.0/default/service.cpp b/automotive/evs/1.0/default/service.cpp new file mode 100644 index 0000000..1b64e44 --- /dev/null +++ b/automotive/evs/1.0/default/service.cpp
@@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.automotive.evs@1.0-service" + +#include <unistd.h> + +#include <hidl/HidlTransportSupport.h> +#include <utils/Errors.h> +#include <utils/StrongPointer.h> +#include <utils/Log.h> + +#include "ServiceNames.h" +#include "EvsEnumerator.h" +#include "EvsDisplay.h" + + +// libhidl: +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; + +// Generated HIDL files +using android::hardware::automotive::evs::V1_0::IEvsEnumerator; +using android::hardware::automotive::evs::V1_0::IEvsDisplay; + +// The namespace in which all our implementation code lives +using namespace android::hardware::automotive::evs::V1_0::implementation; +using namespace android; + + +int main() { + ALOGI("EVS Hardware Enumerator service is starting"); + android::sp<IEvsEnumerator> service = new EvsEnumerator(); + + configureRpcThreadpool(1, true /* callerWillJoin */); + + // Register our service -- if somebody is already registered by our name, + // they will be killed (their thread pool will throw an exception). + status_t status = service->registerAsService(kEnumeratorServiceName); + if (status == OK) { + ALOGD("%s is ready.", kEnumeratorServiceName); + joinRpcThreadpool(); + } else { + ALOGE("Could not register service %s (%d).", kEnumeratorServiceName, status); + } + + // In normal operation, we don't expect the thread pool to exit + ALOGE("EVS Hardware Enumerator is shutting down"); + return 1; +}
diff --git a/automotive/evs/1.0/types.hal b/automotive/evs/1.0/types.hal new file mode 100644 index 0000000..661c2a9 --- /dev/null +++ b/automotive/evs/1.0/types.hal
@@ -0,0 +1,122 @@ +/* + * Copyright (C) 2016 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.automotive.evs@1.0; + + +/* + * Bit flags indicating suggested uses for a given EVS camera + * + * The values in the UsageHint bit field provide a generic expression of how a + * given camera is intended to be used. The values for these flags support + * existing use cases, and are used by the default EVS application to select + * appropriate cameras for display based on observed vehicle state (such as + * turn signal activation or selection of reverse gear). When implementing + * their own specialized EVS Applications, OEMs are free to use these flags + * and/or the opaque vendor_flags to drive their own vehicle specific logic. + */ +enum UsageHint : uint32_t { + USAGE_HINT_REVERSE = 0x00000001, + USAGE_HINT_LEFT_TURN = 0x00000002, + USAGE_HINT_RIGHT_TURN = 0x00000004, +}; + + +/* + * Structure describing the basic properties of an EVS camera + * + * The HAL is responsible for filling out this structure for each + * EVS camera in the system. Attention should be given to the field + * of view, direction of view, and location parameters as these may + * be used to (if available) to project overlay graphics into the + * scene by an EVS application. + * Any of these values for which the HAL does not have reasonable values + * should be set to ZERO. + */ +struct CameraDesc { + string cameraId; + bitfield<UsageHint> hints; // Mask of usage hints + uint32_t vendorFlags; // Opaque value from driver + uint32_t defaultHorResolution; // Units of pixels + uint32_t defaultVerResolution; // Units of pixels +}; + + +/* + * Structure describing the basic properties of an EVS display + * + * The HAL is responsible for filling out this structure to describe + * the EVS display. As an implementation detail, this may be a physical + * display or a virtual display that is overlaid or mixed with another + * presentation device. + */ +struct DisplayDesc { + string displayId; + uint32_t vendorFlags; // Opaque value from driver + uint32_t defaultHorResolution; // Units of pixels + uint32_t defaultVerResolution; // Units of pixels +}; + + +/* + * Structure representing an image buffer through our APIs + * + * In addition to the handle to the graphics memory, we need to retain + * the properties of the buffer for easy reference and reconstruction of + * an ANativeWindowBuffer object on the remote side of API calls. + * (Not least because OpenGL expect an ANativeWindowBuffer* for us as a + * texture via eglCreateImageKHR(). + * See also related types from android.hardware.graphics.common + * TODO: b/34722508 Review details of interaction of this structure with gralloc and OpenGL. + * Specifically consider if format and/or usage should become enumerated types. + */ +struct BufferDesc { + uint32_t width; // Units of pixels + uint32_t height; // Units of pixels + uint32_t stride; // Units of bytes + uint32_t format; // May contain values from android_pixel_format_t + uint32_t usage; // May contain values from from Gralloc.h + uint32_t bufferId; // Opaque value from driver + handle memHandle; // gralloc memory buffer handle +}; + + +/* + * States for control of the EVS display + * + * The DisplayInfo structure describes the basic properties of an EVS display. Any EVS + * implementation is required to have one. The HAL is responsible for filling out this + * structure to describe the EVS display. As an implementation detail, this may be a + * physical display or a virtual display that is overlaid or mixed with another + * presentation device. + */ +enum DisplayState : uint32_t { + NOT_OPEN = 0, // Display has not been requested by any application + NOT_VISIBLE, // Display is inhibited + VISIBLE_ON_NEXT_FRAME, // Will become visible with next frame + VISIBLE, // Display is currently active + NUM_STATES // Must be last +}; + + +/* Error codes used in EVS HAL interface. */ +enum EvsResult : uint32_t { + OK = 0, + INVALID_ARG, + STREAM_ALREADY_RUNNING, + BUFFER_NOT_AVAILABLE, + UNDERLYING_SERVICE_ERROR, +}; \ No newline at end of file
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp new file mode 100644 index 0000000..e08d3ca --- /dev/null +++ b/automotive/vehicle/2.0/Android.bp
@@ -0,0 +1,69 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.automotive.vehicle@2.0_hal", + srcs: [ + "types.hal", + "IVehicle.hal", + "IVehicleCallback.hal", + ], +} + +genrule { + name: "android.hardware.automotive.vehicle@2.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.0", + srcs: [ + ":android.hardware.automotive.vehicle@2.0_hal", + ], + out: [ + "android/hardware/automotive/vehicle/2.0/types.cpp", + "android/hardware/automotive/vehicle/2.0/VehicleAll.cpp", + "android/hardware/automotive/vehicle/2.0/VehicleCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.automotive.vehicle@2.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.0", + srcs: [ + ":android.hardware.automotive.vehicle@2.0_hal", + ], + out: [ + "android/hardware/automotive/vehicle/2.0/types.h", + "android/hardware/automotive/vehicle/2.0/IVehicle.h", + "android/hardware/automotive/vehicle/2.0/IHwVehicle.h", + "android/hardware/automotive/vehicle/2.0/BnHwVehicle.h", + "android/hardware/automotive/vehicle/2.0/BpHwVehicle.h", + "android/hardware/automotive/vehicle/2.0/BsVehicle.h", + "android/hardware/automotive/vehicle/2.0/IVehicleCallback.h", + "android/hardware/automotive/vehicle/2.0/IHwVehicleCallback.h", + "android/hardware/automotive/vehicle/2.0/BnHwVehicleCallback.h", + "android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h", + "android/hardware/automotive/vehicle/2.0/BsVehicleCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.automotive.vehicle@2.0", + generated_sources: ["android.hardware.automotive.vehicle@2.0_genc++"], + generated_headers: ["android.hardware.automotive.vehicle@2.0_genc++_headers"], + export_generated_headers: ["android.hardware.automotive.vehicle@2.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/automotive/vehicle/2.0/Android.mk b/automotive/vehicle/2.0/Android.mk new file mode 100644 index 0000000..d093017 --- /dev/null +++ b/automotive/vehicle/2.0/Android.mk
@@ -0,0 +1,1950 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.automotive.vehicle@2.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (StatusCode) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/StatusCode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.StatusCode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SubscribeFlags) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeFlags.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.SubscribeFlags + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SubscribeOptions) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeOptions.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.SubscribeOptions + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerBootupReason) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerBootupReason.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerBootupReason + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerSetState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerSetState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerSetState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerStateConfigFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateConfigFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateConfigFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerStateIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerStateShutdownParam) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateShutdownParam.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateShutdownParam + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleArea) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleArea.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleArea + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaConfig) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaConfig.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaConfig + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaDoor) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaDoor.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaDoor + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaMirror) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaMirror.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaMirror + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaSeat) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaSeat.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaSeat + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaWindow) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaWindow.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaWindow + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaZone) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaZone.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaZone + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioContextFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioContextFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioContextFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioExtFocusFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioExtFocusFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioExtFocusFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioFocusIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioFocusRequest) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusRequest.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusRequest + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioFocusState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioHwVariantConfigFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioHwVariantConfigFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioHwVariantConfigFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioRoutingPolicyIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioRoutingPolicyIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioRoutingPolicyIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioStream) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStream.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioStream + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioStreamFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStreamFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioStreamFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioVolumeCapabilityFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeCapabilityFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeCapabilityFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioVolumeIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioVolumeLimitIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeLimitIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeLimitIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioVolumeState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleDisplay) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDisplay.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleDisplay + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleDrivingStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDrivingStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleDrivingStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleGear) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleGear.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleGear + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleHvacFanDirection) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHvacFanDirection.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleHvacFanDirection + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleHwKeyInputAction) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHwKeyInputAction.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleHwKeyInputAction + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleIgnitionState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleIgnitionState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleIgnitionState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleInstrumentClusterType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleInstrumentClusterType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleInstrumentClusterType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropConfig) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropConfig.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropConfig + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropValue) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropValue.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropValue + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleProperty) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleProperty.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleProperty + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyAccess) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyAccess.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyAccess + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyChangeMode) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyChangeMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyChangeMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyGroup) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyGroup.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyGroup + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyOperation) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyOperation.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyOperation + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleRadioConstants) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleRadioConstants.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleRadioConstants + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleTurnSignal) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleTurnSignal.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleTurnSignal + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleUnit) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleUnit.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleUnit + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Wheel) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Wheel.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Wheel + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IVehicle.hal +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicle.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IVehicleCallback.hal +$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::IVehicle + +$(GEN): $(LOCAL_PATH)/IVehicle.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IVehicleCallback.hal +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicleCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicleCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::IVehicleCallback + +$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.automotive.vehicle@2.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (StatusCode) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/StatusCode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.StatusCode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SubscribeFlags) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeFlags.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.SubscribeFlags + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SubscribeOptions) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeOptions.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.SubscribeOptions + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerBootupReason) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerBootupReason.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerBootupReason + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerSetState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerSetState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerSetState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerStateConfigFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateConfigFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateConfigFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerStateIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleApPowerStateShutdownParam) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateShutdownParam.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateShutdownParam + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleArea) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleArea.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleArea + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaConfig) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaConfig.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaConfig + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaDoor) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaDoor.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaDoor + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaMirror) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaMirror.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaMirror + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaSeat) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaSeat.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaSeat + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaWindow) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaWindow.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaWindow + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAreaZone) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaZone.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAreaZone + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioContextFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioContextFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioContextFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioExtFocusFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioExtFocusFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioExtFocusFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioFocusIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioFocusRequest) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusRequest.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusRequest + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioFocusState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioHwVariantConfigFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioHwVariantConfigFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioHwVariantConfigFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioRoutingPolicyIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioRoutingPolicyIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioRoutingPolicyIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioStream) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStream.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioStream + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioStreamFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStreamFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioStreamFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioVolumeCapabilityFlag) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeCapabilityFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeCapabilityFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioVolumeIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioVolumeLimitIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeLimitIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeLimitIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleAudioVolumeState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleDisplay) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDisplay.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleDisplay + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleDrivingStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDrivingStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleDrivingStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleGear) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleGear.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleGear + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleHvacFanDirection) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHvacFanDirection.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleHvacFanDirection + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleHwKeyInputAction) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHwKeyInputAction.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleHwKeyInputAction + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleIgnitionState) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleIgnitionState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleIgnitionState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleInstrumentClusterType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleInstrumentClusterType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleInstrumentClusterType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropConfig) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropConfig.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropConfig + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropValue) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropValue.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropValue + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleProperty) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleProperty.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleProperty + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyAccess) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyAccess.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyAccess + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyChangeMode) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyChangeMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyChangeMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyGroup) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyGroup.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyGroup + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyOperation) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyOperation.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyOperation + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehiclePropertyType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehiclePropertyType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleRadioConstants) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleRadioConstants.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleRadioConstants + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleTurnSignal) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleTurnSignal.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleTurnSignal + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleUnit) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleUnit.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.VehicleUnit + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Wheel) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Wheel.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::types.Wheel + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IVehicle.hal +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicle.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IVehicleCallback.hal +$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::IVehicle + +$(GEN): $(LOCAL_PATH)/IVehicle.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IVehicleCallback.hal +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicleCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicleCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.0::IVehicleCallback + +$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/automotive/vehicle/2.0/IVehicle.hal b/automotive/vehicle/2.0/IVehicle.hal new file mode 100644 index 0000000..5de416f --- /dev/null +++ b/automotive/vehicle/2.0/IVehicle.hal
@@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 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.automotive.vehicle@2.0; + +import IVehicleCallback; + +interface IVehicle { + /** + * Returns a list of all property configurations supported by this vehicle + * HAL. + */ + getAllPropConfigs() generates (vec<VehiclePropConfig> propConfigs); + + /* + * Returns a list of property configurations for given properties. + * + * If requested VehicleProperty wasn't found it must return + * StatusCode::INVALID_ARG, otherwise a list of vehicle property + * configurations with StatusCode::OK + */ + getPropConfigs(vec<int32_t> props) + generates (StatusCode status, vec<VehiclePropConfig> propConfigs); + + /** + * Get a vehicle property value. + * + * For VehiclePropertyChangeMode::STATIC properties, this method must always + * return the same value always. + * For VehiclePropertyChangeMode::ON_CHANGE properties, it must return the + * latest available value. + * + * Some properties like AUDIO_VOLUME requires to pass additional data in + * GET request in VehiclePropValue object. + * + * If there is no data available yet, which can happen during initial stage, + * this call must return immediately with an error code of + * StatusCode::TRY_AGAIN. + */ + get(VehiclePropValue requestedPropValue) + generates (StatusCode status, VehiclePropValue propValue); + + /** + * Set a vehicle property value. + * + * Timestamp of data must be ignored for set operation. + * + * Setting some properties require having initial state available. If initial + * data is not available yet this call must return StatusCode::TRY_AGAIN. + * For a property with separate power control this call must return + * StatusCode::NOT_AVAILABLE error if property is not powered on. + */ + set(VehiclePropValue propValue) generates (StatusCode status); + + /** + * Subscribes to property events. + * + * Clients must be able to subscribe to multiple properties at a time + * depending on data provided in options argument. + * + * @param listener This client must be called on appropriate event. + * @param options List of options to subscribe. SubscribeOption contains + * information such as property Id, area Id, sample rate, etc. + */ + subscribe(IVehicleCallback callback, vec<SubscribeOptions> options) + generates (StatusCode status); + + /** + * Unsubscribes from property events. + * + * If this client wasn't subscribed to the given property, this method + * must return StatusCode::INVALID_ARG. + */ + unsubscribe(IVehicleCallback callback, int32_t propId) + generates (StatusCode status); + + /** + * Print out debugging state for the vehicle hal. + * + * The text must be in ASCII encoding only. + * + * Performance requirements: + * + * The HAL must return from this call in less than 10ms. This call must avoid + * deadlocks, as it may be called at any point of operation. Any synchronization + * primitives used (such as mutex locks or semaphores) must be acquired + * with a timeout. + * + */ + debugDump() generates (string s); +};
diff --git a/automotive/vehicle/2.0/IVehicleCallback.hal b/automotive/vehicle/2.0/IVehicleCallback.hal new file mode 100644 index 0000000..167e5e1 --- /dev/null +++ b/automotive/vehicle/2.0/IVehicleCallback.hal
@@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 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.automotive.vehicle@2.0; + +interface IVehicleCallback { + + /* + * Event callback happens whenever a variable that the API user has + * subscribed to needs to be reported. This may be based purely on + * threshold and frequency (a regular subscription, see subscribe call's + * arguments) or when the IVehicle#set method was called and the actual + * change needs to be reported. + * + * These callbacks are chunked. + * + * @param values that has been updated. + */ + oneway onPropertyEvent(vec<VehiclePropValue> propValues); + + /* + * This method gets called if the client was subscribed to a property using + * SubscribeFlags::SET_CALL flag and IVehicle#set(...) method was called. + * + * These events must be delivered to subscriber immediately without any + * batching. + * + * @param value Value that was set by a client. + */ + oneway onPropertySet(VehiclePropValue propValue); + + /* + * Set property value is usually asynchronous operation. Thus even if + * client received StatusCode::OK from the IVehicle::set(...) this + * doesn't guarantee that the value was successfully propagated to the + * vehicle network. If such rare event occurs this method must be called. + * + * @param errorCode - any value from StatusCode enum. + * @param property - a property where error has happened. + * @param areaId - bitmask that specifies in which areas the problem has + * occurred, must be 0 for global properties + */ + oneway onPropertySetError(StatusCode errorCode, + int32_t propId, + int32_t areaId); +};
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk new file mode 100644 index 0000000..4a010e9 --- /dev/null +++ b/automotive/vehicle/2.0/default/Android.mk
@@ -0,0 +1,172 @@ +# Copyright (C) 2016 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. + +LOCAL_PATH := $(call my-dir) + +vhal_v2_0 = android.hardware.automotive.vehicle@2.0 + +############################################################################### +# Vehicle reference implementation lib +############################################################################### +include $(CLEAR_VARS) +LOCAL_MODULE := $(vhal_v2_0)-manager-lib +LOCAL_SRC_FILES := \ + common/src/AccessControlConfigParser.cpp \ + common/src/SubscriptionManager.cpp \ + common/src/VehicleHalManager.cpp \ + common/src/VehicleObjectPool.cpp \ + common/src/VehicleUtils.cpp \ + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/common/include/vhal_v2_0 + +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/common/include + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + liblog \ + libutils \ + $(vhal_v2_0) \ + +include $(BUILD_STATIC_LIBRARY) + +############################################################################### +# Vehicle HAL Protobuf library +############################################################################### +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(call all-proto-files-under, impl/vhal_v2_0/proto) + +LOCAL_PROTOC_OPTIMIZE_TYPE := nano + +LOCAL_MODULE := $(vhal_v2_0)-libproto-native +LOCAL_MODULE_CLASS := STATIC_LIBRARIES + +LOCAL_MODULE_TAGS := optional + +LOCAL_STRIP_MODULE := keep_symbols + +generated_sources_dir := $(call local-generated-sources-dir) +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(generated_sources_dir)/proto/$(LOCAL_PATH)/impl/vhal_v2_0/proto + +include $(BUILD_STATIC_LIBRARY) + + +############################################################################### +# Vehicle default VehicleHAL implementation +############################################################################### +include $(CLEAR_VARS) + +LOCAL_MODULE:= $(vhal_v2_0)-default-impl-lib +LOCAL_SRC_FILES:= \ + impl/vhal_v2_0/DefaultVehicleHal.cpp \ + impl/vhal_v2_0/PipeComm.cpp \ + impl/vhal_v2_0/SocketComm.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/impl/vhal_v2_0 + +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/impl + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + $(vhal_v2_0)-manager-lib \ + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libbinder \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + liblog \ + libprotobuf-cpp-lite \ + libutils \ + $(vhal_v2_0) \ + +LOCAL_STATIC_LIBRARIES := \ + $(vhal_v2_0)-libproto-native \ + +LOCAL_CFLAGS += -Wall -Wextra -Werror + +include $(BUILD_STATIC_LIBRARY) + + +############################################################################### +# Vehicle reference implementation unit tests +############################################################################### +include $(CLEAR_VARS) + +LOCAL_MODULE:= $(vhal_v2_0)-manager-unit-tests + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + $(vhal_v2_0)-manager-lib \ + +LOCAL_SRC_FILES:= \ + tests/AccessControlConfigParser_test.cpp \ + tests/RecurrentTimer_test.cpp \ + tests/SubscriptionManager_test.cpp \ + tests/VehicleHalManager_test.cpp \ + tests/VehicleObjectPool_test.cpp \ + tests/VehiclePropConfigIndex_test.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + liblog \ + libutils \ + $(vhal_v2_0) \ + +LOCAL_CFLAGS += -Wall -Wextra -Werror +LOCAL_MODULE_TAGS := tests + +include $(BUILD_NATIVE_TEST) + + +############################################################################### +# Vehicle HAL service +############################################################################### +include $(CLEAR_VARS) +LOCAL_MODULE := $(vhal_v2_0)-service +LOCAL_INIT_RC := $(vhal_v2_0)-service.rc +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw + +LOCAL_SRC_FILES := \ + VehicleService.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libbinder \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + liblog \ + libprotobuf-cpp-lite \ + libutils \ + $(vhal_v2_0) \ + +LOCAL_STATIC_LIBRARIES := \ + $(vhal_v2_0)-manager-lib \ + $(vhal_v2_0)-default-impl-lib \ + $(vhal_v2_0)-libproto-native \ + +LOCAL_CFLAGS += -Wall -Wextra -Werror + +include $(BUILD_EXECUTABLE)
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp new file mode 100644 index 0000000..95057cc --- /dev/null +++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "automotive.vehicle@2.0-service" +#include <android/log.h> +#include <hidl/HidlTransportSupport.h> + +#include <iostream> + +#include <vhal_v2_0/VehicleHalManager.h> +#include <vhal_v2_0/DefaultVehicleHal.h> + +using namespace android; +using namespace android::hardware; +using namespace android::hardware::automotive::vehicle::V2_0; + +int main(int /* argc */, char* /* argv */ []) { + auto hal = std::make_unique<impl::DefaultVehicleHal>(); + auto service = std::make_unique<VehicleHalManager>(hal.get()); + + configureRpcThreadpool(1, true /* callerWillJoin */); + + ALOGI("Registering as service..."); + service->registerAsService(); + + ALOGI("Ready"); + joinRpcThreadpool(); +}
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc new file mode 100644 index 0000000..30e249e --- /dev/null +++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
@@ -0,0 +1,4 @@ +service vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-service + class hal + user vehicle_network + group system inet
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/AccessControlConfigParser.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/AccessControlConfigParser.h new file mode 100644 index 0000000..8ef6f5a --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/AccessControlConfigParser.h
@@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_AccessControlConfigParser_H_ +#define android_hardware_automotive_vehicle_V2_0_AccessControlConfigParser_H_ + +#include <string> +#include <vector> +#include <unordered_map> +#include <list> + +#include <android/hardware/automotive/vehicle/2.0/types.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +struct PropertyAcl { + int32_t propId; + unsigned uid; + VehiclePropertyAccess access; +}; + +using PropertyAclMap = std::unordered_multimap<int32_t, PropertyAcl>; + +/** + * Parser for per-property access control in vehicle HAL. + * + * It supports the following format: + * Set ALIAS_NAME UID + * {S,V}:0x0305 {ALIAS_NAME,UID} {R,W,RW} + * + * ALIAS_NAME is just an alias for UID + * S - for system properties (VehiclePropertyGroup::SYSTEM) + * V - for vendor properties (VehiclePropertyGroup::VENDOR) + * + * Example: + * + * Set AID_AUDIO 1004 + * Set AID_MY_APP 10022 + * + * S:0x0305 AID_AUDIO RW + * S:0x0305 10021 R + * V:0x0101 AID_MY_APP R + */ +class AccessControlConfigParser { +public: + /** + * Creates an instance of AccessControlConfigParser + * + * @param properties - properties supported by HAL implementation + */ + AccessControlConfigParser(const std::vector<int32_t>& properties); + + /** + * Parses config content from given stream and writes results to + * propertyAclMap. + */ + bool parseFromStream(std::istream* stream, PropertyAclMap* propertyAclMap); + +private: + bool processTokens(std::list<std::string>* tokens, + PropertyAclMap* propertyAclMap); + + bool parsePropertyGroup(char group, + VehiclePropertyGroup* outPropertyGroup) const; + + bool parsePropertyId(const std::string& strPropId, + VehiclePropertyGroup propertyGroup, + int32_t* outVehicleProperty) const; + + bool parseUid(const std::string& strUid, unsigned* outUid) const; + + bool parseAccess(const std::string& strAccess, + VehiclePropertyAccess* outAccess) const; + + + std::string readNextToken(std::list<std::string>* tokens) const; + + static bool parseInt(const char* strValue, int* outIntValue); + static void split(const std::string& line, + std::list<std::string>* outTokens); + +private: + std::unordered_map<std::string, unsigned> mUidMap {}; // Contains UID + // aliases. + + // Map property ids w/o TYPE and AREA to VehicleProperty. + std::unordered_map<int32_t, int32_t> mStrippedToVehiclePropertyMap; +}; + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_AccessControlConfigParser_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/ConcurrentQueue.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/ConcurrentQueue.h new file mode 100644 index 0000000..b63429f --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/ConcurrentQueue.h
@@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_ConcurrentQueue_H_ +#define android_hardware_automotive_vehicle_V2_0_ConcurrentQueue_H_ + +#include <queue> +#include <atomic> +#include <thread> +#include <condition_variable> +#include <iostream> + +namespace android { + +template<typename T> +class ConcurrentQueue { +public: + void waitForItems() { + std::unique_lock<std::mutex> g(mLock); + while (mQueue.empty() && mIsActive) { + mCond.wait(g); + } + } + + std::vector<T> flush() { + std::vector<T> items; + + MuxGuard g(mLock); + if (mQueue.empty() || !mIsActive) { + return items; + } + while (!mQueue.empty()) { + items.push_back(std::move(mQueue.front())); + mQueue.pop(); + } + return items; + } + + void push(T&& item) { + { + MuxGuard g(mLock); + if (!mIsActive) { + return; + } + mQueue.push(std::move(item)); + } + mCond.notify_one(); + } + + /* Deactivates the queue, thus no one can push items to it, also + * notifies all waiting thread. + */ + void deactivate() { + { + MuxGuard g(mLock); + mIsActive = false; + } + mCond.notify_all(); // To unblock all waiting consumers. + } + + ConcurrentQueue() = default; + + ConcurrentQueue(const ConcurrentQueue &) = delete; + ConcurrentQueue &operator=(const ConcurrentQueue &) = delete; +private: + using MuxGuard = std::lock_guard<std::mutex>; + + bool mIsActive = true; + mutable std::mutex mLock; + std::condition_variable mCond; + std::queue<T> mQueue; +}; + +template<typename T> +class BatchingConsumer { +private: + enum class State { + INIT = 0, + RUNNING = 1, + STOP_REQUESTED = 2, + STOPPED = 3, + }; + +public: + BatchingConsumer() : mState(State::INIT) {} + + BatchingConsumer(const BatchingConsumer &) = delete; + BatchingConsumer &operator=(const BatchingConsumer &) = delete; + + using OnBatchReceivedFunc = std::function<void(const std::vector<T>& vec)>; + + void run(ConcurrentQueue<T>* queue, + std::chrono::nanoseconds batchInterval, + const OnBatchReceivedFunc& func) { + mQueue = queue; + mBatchInterval = batchInterval; + + mWorkerThread = std::thread( + &BatchingConsumer<T>::runInternal, this, func); + } + + void requestStop() { + mState = State::STOP_REQUESTED; + } + + void waitStopped() { + if (mWorkerThread.joinable()) { + mWorkerThread.join(); + } + } + +private: + void runInternal(const OnBatchReceivedFunc& onBatchReceived) { + if (mState.exchange(State::RUNNING) == State::INIT) { + while (State::RUNNING == mState) { + mQueue->waitForItems(); + if (State::STOP_REQUESTED == mState) break; + + std::this_thread::sleep_for(mBatchInterval); + if (State::STOP_REQUESTED == mState) break; + + std::vector<T> items = mQueue->flush(); + + if (items.size() > 0) { + onBatchReceived(items); + } + } + } + + mState = State::STOPPED; + } + +private: + std::thread mWorkerThread; + + std::atomic<State> mState; + std::chrono::nanoseconds mBatchInterval; + ConcurrentQueue<T>* mQueue; +}; + +} // namespace android + +#endif //android_hardware_automotive_vehicle_V2_0_ConcurrentQueue_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h new file mode 100644 index 0000000..be25adc --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
@@ -0,0 +1,149 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_ +#define android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_ + +#include <atomic> +#include <chrono> +#include <condition_variable> +#include <functional> +#include <list> +#include <mutex> +#include <set> +#include <thread> +#include <unordered_map> + +/** + * This class allows to specify multiple time intervals to receive + * notifications. A single thread is used internally. + */ +class RecurrentTimer { +private: + using Nanos = std::chrono::nanoseconds; + using Clock = std::chrono::steady_clock; + using TimePoint = std::chrono::time_point<Clock, Nanos>; +public: + using Action = std::function<void(const std::vector<int32_t>& cookies)>; + + RecurrentTimer(const Action& action) : mAction(action) { + mTimerThread = std::thread(&RecurrentTimer::loop, this, action); + } + + virtual ~RecurrentTimer() { + stop(); + } + + /** + * Registers recurrent event for a given interval. Registred events are distinguished by + * cookies thus calling this method multiple times with the same cookie will override the + * interval provided before. + */ + void registerRecurrentEvent(std::chrono::nanoseconds interval, int32_t cookie) { + TimePoint now = Clock::now(); + // Align event time point among all intervals. Thus if we have two intervals 1ms and 2ms, + // during every second wake-up both intervals will be triggered. + TimePoint absoluteTime = now - Nanos(now.time_since_epoch().count() % interval.count()); + + { + std::lock_guard<std::mutex> g(mLock); + mCookieToEventsMap[cookie] = { interval, cookie, absoluteTime }; + } + mCond.notify_one(); + } + + void unregisterRecurrentEvent(int32_t cookie) { + { + std::lock_guard<std::mutex> g(mLock); + mCookieToEventsMap.erase(cookie); + } + mCond.notify_one(); + } + + +private: + + struct RecurrentEvent { + Nanos interval; + int32_t cookie; + TimePoint absoluteTime; // Absolute time of the next event. + + void updateNextEventTime(TimePoint now) { + // We want to move time to next event by adding some number of intervals (usually 1) + // to previous absoluteTime. + int intervalMultiplier = (now - absoluteTime) / interval; + if (intervalMultiplier <= 0) intervalMultiplier = 1; + absoluteTime += intervalMultiplier * interval; + } + }; + + void loop(const Action& action) { + static constexpr auto kInvalidTime = TimePoint(Nanos::max()); + + std::vector<int32_t> cookies; + + while (!mStopRequested) { + auto now = Clock::now(); + auto nextEventTime = kInvalidTime; + cookies.clear(); + + { + std::unique_lock<std::mutex> g(mLock); + + for (auto&& it : mCookieToEventsMap) { + RecurrentEvent& event = it.second; + if (event.absoluteTime <= now) { + event.updateNextEventTime(now); + cookies.push_back(event.cookie); + } + + if (nextEventTime > event.absoluteTime) { + nextEventTime = event.absoluteTime; + } + } + } + + if (cookies.size() != 0) { + action(cookies); + } + + std::unique_lock<std::mutex> g(mLock); + mCond.wait_until(g, nextEventTime); // nextEventTime can be nanoseconds::max() + } + } + + void stop() { + mStopRequested = true; + { + std::lock_guard<std::mutex> g(mLock); + mCookieToEventsMap.clear(); + } + mCond.notify_one(); + if (mTimerThread.joinable()) { + mTimerThread.join(); + } + } +private: + mutable std::mutex mLock; + std::thread mTimerThread; + std::condition_variable mCond; + std::atomic_bool mStopRequested { false }; + Action mAction; + std::unordered_map<int32_t, RecurrentEvent> mCookieToEventsMap; +}; + + +#endif // android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h new file mode 100644 index 0000000..a808c66 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
@@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_SubscriptionManager_H_ +#define android_hardware_automotive_vehicle_V2_0_SubscriptionManager_H_ + +#include <memory> +#include <map> +#include <set> +#include <list> + +#include <android/log.h> +#include <hidl/HidlSupport.h> +#include <hwbinder/IPCThreadState.h> + +#include <android/hardware/automotive/vehicle/2.0/IVehicle.h> + +#include "ConcurrentQueue.h" +#include "VehicleObjectPool.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +class HalClient : public android::RefBase { +public: + HalClient(const sp<IVehicleCallback> &callback, + int32_t pid, + int32_t uid) + : mCallback(callback), mPid(pid), mUid(uid) {} + + virtual ~HalClient() {} +public: + sp<IVehicleCallback> getCallback() const { + return mCallback; + } + + void addOrUpdateSubscription(const SubscribeOptions &opts); + bool isSubscribed(int32_t propId, int32_t areaId, SubscribeFlags flags); + std::vector<int32_t> getSubscribedProperties() const; + +private: + const sp<IVehicleCallback> mCallback; + const int32_t mPid; + const int32_t mUid; + + std::map<int32_t, SubscribeOptions> mSubscriptions; +}; + +class HalClientVector : private SortedVector<sp<HalClient>> , public RefBase { +public: + virtual ~HalClientVector() {} + + inline void addOrUpdate(const sp<HalClient> &client) { + SortedVector::add(client); + } + + using SortedVector::remove; + using SortedVector::size; + using SortedVector::indexOf; + using SortedVector::itemAt; + using SortedVector::isEmpty; +}; + +struct HalClientValues { + sp<HalClient> client; + std::list<VehiclePropValue *> values; +}; + +class SubscriptionManager { +public: + using OnPropertyUnsubscribed = std::function<void(int32_t)>; + + /** + * Constructs SubscriptionManager + * + * @param onPropertyUnsubscribed - this callback function will be called when there are no + * more client subscribed to particular property. + */ + SubscriptionManager(const OnPropertyUnsubscribed& onPropertyUnsubscribed) + : mOnPropertyUnsubscribed(onPropertyUnsubscribed), + mCallbackDeathRecipient(new DeathRecipient( + std::bind(&SubscriptionManager::onCallbackDead, this, std::placeholders::_1))) + {} + + ~SubscriptionManager() = default; + + /** + * Updates subscription. Returns the vector of properties subscription that + * needs to be updated in VehicleHAL. + */ + StatusCode addOrUpdateSubscription(const sp<IVehicleCallback>& callback, + const hidl_vec<SubscribeOptions>& optionList, + std::list<SubscribeOptions>* outUpdatedOptions); + + /** + * Returns a list of IVehicleCallback -> list of VehiclePropValue ready for + * dispatching to its clients. + */ + std::list<HalClientValues> distributeValuesToClients( + const std::vector<recyclable_ptr<VehiclePropValue>>& propValues, + SubscribeFlags flags) const; + + std::list<sp<HalClient>> getSubscribedClients(int32_t propId, + int32_t area, + SubscribeFlags flags) const; + /** + * If there are no clients subscribed to given properties than callback function provided + * in the constructor will be called. + */ + void unsubscribe(const sp<IVehicleCallback>& callback, int32_t propId); +private: + std::list<sp<HalClient>> getSubscribedClientsLocked(int32_t propId, + int32_t area, + SubscribeFlags flags) const; + + bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts, SubscribeOptions* out); + + void addClientToPropMapLocked(int32_t propId, const sp<HalClient>& client); + + sp<HalClientVector> getClientsForPropertyLocked(int32_t propId) const; + + sp<HalClient> getOrCreateHalClientLocked(const sp<IVehicleCallback> &callback); + + void onCallbackDead(uint64_t cookie); + +private: + using OnClientDead = std::function<void(uint64_t)>; + + class DeathRecipient : public hidl_death_recipient { + public: + DeathRecipient(const OnClientDead& onClientDead) + : mOnClientDead(onClientDead) {} + ~DeathRecipient() = default; + + DeathRecipient(const DeathRecipient& ) = delete; + DeathRecipient& operator=(const DeathRecipient&) = delete; + + void serviceDied(uint64_t cookie, + const wp<::android::hidl::base::V1_0::IBase>& /* who */) override { + mOnClientDead(cookie); + } + private: + OnClientDead mOnClientDead; + }; + +private: + using MuxGuard = std::lock_guard<std::mutex>; + + mutable std::mutex mLock; + + std::map<sp<IVehicleCallback>, sp<HalClient>> mClients; + std::map<int32_t, sp<HalClientVector>> mPropToClients; + std::map<int32_t, SubscribeOptions> mHalEventSubscribeOptions; + + OnPropertyUnsubscribed mOnPropertyUnsubscribed; + sp<DeathRecipient> mCallbackDeathRecipient; +}; + + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + +#endif // android_hardware_automotive_vehicle_V2_0_SubscriptionManager_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h new file mode 100644 index 0000000..8203a1e --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
@@ -0,0 +1,115 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_VehicleHal_H +#define android_hardware_automotive_vehicle_V2_0_VehicleHal_H + +#include <android/hardware/automotive/vehicle/2.0/IVehicle.h> +#include "VehicleObjectPool.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +/** + * This is a low-level vehicle hal interface that should be implemented by + * Vendor. + */ +class VehicleHal { +public: + using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>; + + using HalEventFunction = std::function<void(VehiclePropValuePtr)>; + using HalErrorFunction = std::function<void( + StatusCode errorCode, int32_t property, int32_t areaId)>; + + virtual ~VehicleHal() {} + + virtual std::vector<VehiclePropConfig> listProperties() = 0; + virtual VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue, + StatusCode* outStatus) = 0; + + virtual StatusCode set(const VehiclePropValue& propValue) = 0; + + /** + * Subscribe to HAL property events. This method might be called multiple + * times for the same vehicle property to update subscribed areas or sample + * rate. + * + * @param property to subscribe + * @param areas a bitwise vehicle areas or 0 for all supported areas + * @param sampleRate sample rate in Hz for properties that support sample + * rate, e.g. for properties with + * VehiclePropertyChangeMode::CONTINUOUS + */ + virtual StatusCode subscribe(int32_t property, + int32_t areas, + float sampleRate) = 0; + + /** + * Unsubscribe from HAL events for given property + * + * @param property vehicle property to unsubscribe + */ + virtual StatusCode unsubscribe(int32_t property) = 0; + + /** + * Override this method if you need to do one-time initialization. + */ + virtual void onCreate() {} + + void init( + VehiclePropValuePool* valueObjectPool, + const HalEventFunction& onHalEvent, + const HalErrorFunction& onHalError) { + mValuePool = valueObjectPool; + mOnHalEvent = onHalEvent; + mOnHalPropertySetError = onHalError; + + onCreate(); + } + + VehiclePropValuePool* getValuePool() { + return mValuePool; + } +protected: + /* Propagates property change events to vehicle HAL clients. */ + void doHalEvent(VehiclePropValuePtr v) { + mOnHalEvent(std::move(v)); + } + + /* Propagates error during set operation to the vehicle HAL clients. */ + void doHalPropertySetError(StatusCode errorCode, + int32_t propId, + int32_t areaId) { + mOnHalPropertySetError(errorCode, propId, areaId); + } + +private: + HalEventFunction mOnHalEvent; + HalErrorFunction mOnHalPropertySetError; + VehiclePropValuePool* mValuePool; +}; + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif //android_hardware_automotive_vehicle_V2_0_VehicleHal_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h new file mode 100644 index 0000000..b8ab309 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
@@ -0,0 +1,143 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_ +#define android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_ + +#include <inttypes.h> +#include <stdint.h> +#include <sys/types.h> + +#include <list> +#include <map> +#include <memory> +#include <set> + +#include <android/hardware/automotive/vehicle/2.0/IVehicle.h> +#include <hwbinder/IPCThreadState.h> + +#include "AccessControlConfigParser.h" +#include "ConcurrentQueue.h" +#include "SubscriptionManager.h" +#include "VehicleHal.h" +#include "VehicleObjectPool.h" +#include "VehiclePropConfigIndex.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +struct Caller { + pid_t pid; + uid_t uid; +}; + +/** + * This class is a thick proxy between IVehicle HIDL interface and vendor's implementation. + * + * It has some boilerplate code like batching and caching property values, checking permissions, + * etc. Vendors must implement VehicleHal class. + */ +class VehicleHalManager : public IVehicle { +public: + VehicleHalManager(VehicleHal* vehicleHal) + : mHal(vehicleHal), + mSubscriptionManager(std::bind(&VehicleHalManager::onAllClientsUnsubscribed, + this, std::placeholders::_1)) { + init(); + } + + virtual ~VehicleHalManager(); + + void init(); + + // --------------------------------------------------------------------------------------------- + // Methods derived from IVehicle + Return<void> getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) override; + Return<void> getPropConfigs(const hidl_vec<int32_t>& properties, + getPropConfigs_cb _hidl_cb) override; + Return<void> get(const VehiclePropValue& requestedPropValue, + get_cb _hidl_cb) override; + Return<StatusCode> set(const VehiclePropValue& value) override; + Return<StatusCode> subscribe(const sp<IVehicleCallback>& callback, + const hidl_vec<SubscribeOptions>& options) override; + Return<StatusCode> unsubscribe(const sp<IVehicleCallback>& callback, + int32_t propId) override; + Return<void> debugDump(debugDump_cb _hidl_cb = nullptr) override; + +private: + using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr; + // Returns true if needs to call again shortly. + using RetriableAction = std::function<bool()>; + + // --------------------------------------------------------------------------------------------- + // Events received from VehicleHal + void onHalEvent(VehiclePropValuePtr v); + void onHalPropertySetError(StatusCode errorCode, int32_t property, + int32_t areaId); + + // --------------------------------------------------------------------------------------------- + // This method will be called from BatchingConsumer thread + void onBatchHalEvent(const std::vector<VehiclePropValuePtr >& values); + + void handlePropertySetEvent(const VehiclePropValue& value); + + const VehiclePropConfig* getPropConfigOrNull(int32_t prop) const; + + bool checkWritePermission(const VehiclePropConfig &config, + const Caller& callee) const; + bool checkReadPermission(const VehiclePropConfig &config, + const Caller& caller) const; + bool checkAcl(uid_t callerUid, + int32_t propertyId, + VehiclePropertyAccess requiredAccess) const; + + void onAllClientsUnsubscribed(int32_t propertyId); + + static bool isSubscribable(const VehiclePropConfig& config, + SubscribeFlags flags); + static bool isSampleRateFixed(VehiclePropertyChangeMode mode); + static float checkSampleRate(const VehiclePropConfig& config, + float sampleRate); + static void readAndParseAclConfig(const char* filename, + AccessControlConfigParser* parser, + PropertyAclMap* outAclMap); + + static Caller getCaller(); + +private: + VehicleHal* mHal; + std::unique_ptr<VehiclePropConfigIndex> mConfigIndex; + SubscriptionManager mSubscriptionManager; + + hidl_vec<VehiclePropValue> mHidlVecOfVehiclePropValuePool; + + ConcurrentQueue<VehiclePropValuePtr> mEventQueue; + BatchingConsumer<VehiclePropValuePtr> mBatchingConsumer; + VehiclePropValuePool mValueObjectPool; + PropertyAclMap mPropertyAclMap; +}; + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + +#endif // android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h new file mode 100644 index 0000000..05c649b --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
@@ -0,0 +1,246 @@ +/* + * Copyright (C) 2016 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. + */ + + +#ifndef android_hardware_automotive_vehicle_V2_0_VehicleObjectPool_H_ +#define android_hardware_automotive_vehicle_V2_0_VehicleObjectPool_H_ + +#include <deque> +#include <map> +#include <mutex> + +#include <android/hardware/automotive/vehicle/2.0/types.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +// Handy metric mostly for unit tests and debug. +#define INC_METRIC_IF_DEBUG(val) PoolStats::instance()->val++; +struct PoolStats { + std::atomic<uint32_t> Obtained {0}; + std::atomic<uint32_t> Created {0}; + std::atomic<uint32_t> Recycled {0}; + + static PoolStats* instance() { + static PoolStats inst; + return &inst; + } +}; + +template<typename T> +struct Deleter { + using OnDeleteFunc = std::function<void(T*)>; + + Deleter(const OnDeleteFunc& f) : mOnDelete(f) {}; + + Deleter() = default; + Deleter(const Deleter&) = default; + + void operator()(T* o) { + mOnDelete(o); + } +private: + OnDeleteFunc mOnDelete; +}; + +/** + * This is std::unique_ptr<> with custom delete operation that typically moves + * the pointer it holds back to ObjectPool. + */ +template <typename T> +using recyclable_ptr = typename std::unique_ptr<T, Deleter<T>>; + +/** + * Generic abstract object pool class. Users of this class must implement + * #createObject method. + * + * This class is thread-safe. Concurrent calls to #obtain(...) method from + * multiple threads is OK, also client can obtain an object in one thread and + * then move ownership to another thread. + * + */ +template<typename T> +class ObjectPool { +public: + ObjectPool() = default; + virtual ~ObjectPool() = default; + + virtual recyclable_ptr<T> obtain() { + std::lock_guard<std::mutex> g(mLock); + INC_METRIC_IF_DEBUG(Obtained) + if (mObjects.empty()) { + INC_METRIC_IF_DEBUG(Created) + return wrap(createObject()); + } + + auto o = wrap(mObjects.front().release()); + mObjects.pop_front(); + + return o; + } + + ObjectPool& operator =(const ObjectPool &) = delete; + ObjectPool(const ObjectPool &) = delete; + +protected: + virtual T* createObject() = 0; + + virtual void recycle(T* o) { + INC_METRIC_IF_DEBUG(Recycled) + std::lock_guard<std::mutex> g(mLock); + mObjects.push_back(std::unique_ptr<T> { o } ); + } + +private: + const Deleter<T>& getDeleter() { + if (!mDeleter.get()) { + Deleter<T> *d = new Deleter<T>(std::bind( + &ObjectPool::recycle, this, std::placeholders::_1)); + mDeleter.reset(d); + } + return *mDeleter.get(); + } + + recyclable_ptr<T> wrap(T* raw) { + return recyclable_ptr<T> { raw, getDeleter() }; + } + +private: + mutable std::mutex mLock; + std::deque<std::unique_ptr<T>> mObjects; + std::unique_ptr<Deleter<T>> mDeleter; +}; + +/** + * This class provides a pool of recycable VehiclePropertyValue objects. + * + * It has only one overloaded public method - obtain(...), users must call this + * method when new object is needed with given VehiclePropertyType and vector + * size (for vector properties). This method returns a recycable smart pointer + * to VehiclePropertyValue, essentially this is a std::unique_ptr with custom + * delete function, so recycable object has only one owner and developers can + * safely pass it around. Once this object goes out of scope, it will be + * returned the the object pool. + * + * Some objects are not recycable: strings and vector data types with + * vector length > maxRecyclableVectorSize (provided in the constructor). These + * objects will be deleted immediately once the go out of scope. There's no + * synchornization penalty for these objects since we do not store them in the + * pool. + * + * This class is thread-safe. Users can obtain an object in one thread and pass + * it to another. + * + * Sample usage: + * + * VehiclePropValuePool pool; + * auto v = pool.obtain(VehiclePropertyType::INT32); + * v->propId = VehicleProperty::HVAC_FAN_SPEED; + * v->areaId = VehicleAreaZone::ROW_1_LEFT; + * v->timestamp = elapsedRealtimeNano(); + * v->value->int32Values[0] = 42; + * + * + */ +class VehiclePropValuePool { +public: + using RecyclableType = recyclable_ptr<VehiclePropValue>; + + /** + * Creates VehiclePropValuePool + * + * @param maxRecyclableVectorSize - vector value types (e.g. + * VehiclePropertyType::INT32_VEC) with size equal or less to this value + * will be stored in the pool. If users tries to obtain value with vector + * size greater than maxRecyclableVectorSize user will receive appropriate + * object, but once it goes out of scope it will be deleted immediately, not + * returning back to the object pool. + * + */ + VehiclePropValuePool(size_t maxRecyclableVectorSize = 4) : + mMaxRecyclableVectorSize(maxRecyclableVectorSize) {}; + + RecyclableType obtain(VehiclePropertyType type); + + RecyclableType obtain(VehiclePropertyType type, size_t vecSize); + RecyclableType obtain(const VehiclePropValue& src); + RecyclableType obtainBoolean(bool value); + RecyclableType obtainInt32(int32_t value); + RecyclableType obtainInt64(int64_t value); + RecyclableType obtainFloat(float value); + RecyclableType obtainString(const char* cstr); + RecyclableType obtainComplex(); + + VehiclePropValuePool(VehiclePropValuePool& ) = delete; + VehiclePropValuePool& operator=(VehiclePropValuePool&) = delete; +private: + bool isDisposable(VehiclePropertyType type, size_t vecSize) const { + return vecSize > mMaxRecyclableVectorSize || + VehiclePropertyType::STRING == type || + VehiclePropertyType::COMPLEX == type; + } + + RecyclableType obtainDisposable(VehiclePropertyType valueType, + size_t vectorSize) const; + RecyclableType obtainRecylable(VehiclePropertyType type, + size_t vecSize); + + class InternalPool: public ObjectPool<VehiclePropValue> { + public: + InternalPool(VehiclePropertyType type, size_t vectorSize) + : mPropType(type), mVectorSize(vectorSize) {} + + RecyclableType obtain() { + return ObjectPool<VehiclePropValue>::obtain(); + } + protected: + VehiclePropValue* createObject() override; + void recycle(VehiclePropValue* o) override; + private: + bool check(VehiclePropValue::RawValue* v); + + template <typename VecType> + bool check(hidl_vec<VecType>* vec, bool expected) { + return vec->size() == (expected ? mVectorSize : 0); + } + private: + VehiclePropertyType mPropType; + size_t mVectorSize; + }; + +private: + const Deleter<VehiclePropValue> mDisposableDeleter { + [] (VehiclePropValue* v) { + delete v; + } + }; + +private: + mutable std::mutex mLock; + const size_t mMaxRecyclableVectorSize; + std::map<int32_t, std::unique_ptr<InternalPool>> mValueTypePools; +}; + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_VehicleObjectPool_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropConfigIndex.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropConfigIndex.h new file mode 100644 index 0000000..0528f68 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehiclePropConfigIndex.h
@@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_VehiclePropConfigIndex_H_ +#define android_hardware_automotive_vehicle_V2_0_VehiclePropConfigIndex_H_ + +#include <utils/KeyedVector.h> + +#include <android/hardware/automotive/vehicle/2.0/IVehicle.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +/* + * This is thread-safe immutable class to hold vehicle property configuration + * data. + */ +class VehiclePropConfigIndex { +public: + VehiclePropConfigIndex( + const std::vector<VehiclePropConfig>& properties) + : mConfigs(properties), mPropToConfig(mConfigs) + {} + + bool hasConfig(int32_t property) const { + return mPropToConfig.indexOfKey(property) >= 0; + } + + const VehiclePropConfig& getConfig(int32_t property) const { + return *mPropToConfig.valueFor(property); + } + + const std::vector<VehiclePropConfig>& getAllConfigs() const { + return mConfigs; + } + +private: + typedef KeyedVector<int32_t, const VehiclePropConfig*> PropConfigMap; + class ImmutablePropConfigMap : private PropConfigMap { + public: + ImmutablePropConfigMap(const std::vector<VehiclePropConfig>& configs) { + setCapacity(configs.size()); + for (auto& config : configs) { + add(config.prop, &config); + } + } + public: + using PropConfigMap::valueFor; + using PropConfigMap::indexOfKey; + }; + +private: + const std::vector<VehiclePropConfig> mConfigs; + const ImmutablePropConfigMap mPropToConfig; // mConfigs must be declared + // first. +}; + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_VehiclePropConfigIndex_H_
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h new file mode 100644 index 0000000..ce0b163 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
@@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_VehicleUtils_H_ +#define android_hardware_automotive_vehicle_V2_0_VehicleUtils_H_ + +#include <memory> + +#include <hidl/HidlSupport.h> + +#include <android/hardware/automotive/vehicle/2.0/types.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +/** Represents all supported areas for a property. Can be used is */ +constexpr int32_t kAllSupportedAreas = 0; + +/** Returns underlying (integer) value for given enum. */ +template<typename ENUM> +inline constexpr typename std::underlying_type<ENUM>::type toInt( + ENUM const value) { + return static_cast<typename std::underlying_type<ENUM>::type>(value); +} + +inline constexpr VehiclePropertyType getPropType(int32_t prop) { + return static_cast<VehiclePropertyType>( + prop & toInt(VehiclePropertyType::MASK)); +} + +inline constexpr VehiclePropertyGroup getPropGroup(int32_t prop) { + return static_cast<VehiclePropertyGroup>( + prop & toInt(VehiclePropertyGroup::MASK)); +} + +inline constexpr VehicleArea getPropArea(int32_t prop) { + return static_cast<VehicleArea>(prop & toInt(VehicleArea::MASK)); +} + +inline constexpr bool isGlobalProp(int32_t prop) { + return getPropArea(prop) == VehicleArea::GLOBAL; +} + +inline constexpr bool isSystemProperty(int32_t prop) { + return VehiclePropertyGroup::SYSTEM == getPropGroup(prop); +} + +std::unique_ptr<VehiclePropValue> createVehiclePropValue( + VehiclePropertyType type, size_t vecSize); + +size_t getVehicleRawValueVectorSize( + const VehiclePropValue::RawValue& value, VehiclePropertyType type); + +void copyVehicleRawValue(VehiclePropValue::RawValue* dest, + const VehiclePropValue::RawValue& src); + +template<typename T> +void shallowCopyHidlVec(hidl_vec<T>* dest, const hidl_vec<T>& src); + +void shallowCopyHidlStr(hidl_string* dest, const hidl_string& src); + +void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src); + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_VehicleUtils_H_
diff --git a/automotive/vehicle/2.0/default/common/src/AccessControlConfigParser.cpp b/automotive/vehicle/2.0/default/common/src/AccessControlConfigParser.cpp new file mode 100644 index 0000000..6a3f8e5 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/src/AccessControlConfigParser.cpp
@@ -0,0 +1,228 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "automotive.vehicle@2.0-impl" + +#include "AccessControlConfigParser.h" +#include "VehicleUtils.h" + +#include <fstream> +#include <iostream> +#include <sstream> + +#include <log/log.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +AccessControlConfigParser::AccessControlConfigParser( + const std::vector<int32_t>& properties) { + // Property Id in the config file doesn't include information about + // type and area. So we want to create a map from these kind of + // *stripped* properties to the whole VehicleProperty. + // We also want to filter out ACL to the properties that supported + // by concrete Vehicle HAL implementation. + for (auto prop : properties) { + auto strippedProp = prop + & ~toInt(VehiclePropertyType::MASK) + & ~toInt(VehicleArea::MASK); + mStrippedToVehiclePropertyMap.emplace(strippedProp, prop); + } +} + +bool AccessControlConfigParser::parseFromStream( + std::istream* stream, PropertyAclMap* propertyAclMap) { + std::list<std::string> tokens; + std::string line; + int lineNo = 0; + bool warnings = false; + for (;std::getline(*stream, line); lineNo++) { + split(line, &tokens); + if (!processTokens(&tokens, propertyAclMap)) { + warnings = true; + ALOGW("Failed to parse line %d : %s", lineNo, line.c_str()); + } + } + return !warnings; +} + + +bool AccessControlConfigParser::processTokens(std::list<std::string>* tokens, + PropertyAclMap* propertyAclMap) { + std::string token = readNextToken(tokens); + if (token.empty() || token[0] == '#') { // Ignore comment. + return true; + } + + if (token == "Set") { + std::string alias = readNextToken(tokens); + std::string strUid = readNextToken(tokens); + if (alias.empty() || strUid.empty()) { + ALOGW("Expected alias and UID must be specified"); + return false; + } + int uid; + if (!parseInt(strUid.c_str(), &uid)) { + ALOGW("Invalid UID: %d", uid); + } + mUidMap.emplace(std::move(alias), uid); + } else if (token.size() > 2 && token[1] == ':') { + VehiclePropertyGroup propGroup; + if (!parsePropertyGroup(token[0], &propGroup)) { + return false; + } + std::string strUid = readNextToken(tokens); + std::string strAccess = readNextToken(tokens); + if (strUid.empty() || strAccess.empty()) { + ALOGW("Expected UID and access for property: %s", + token.c_str()); + } + + + PropertyAcl acl; + if (parsePropertyId(token.substr(2), propGroup, &acl.propId) + && parseUid(strUid, &acl.uid) + && parseAccess(strAccess, &acl.access)) { + propertyAclMap->emplace(acl.propId, std::move(acl)); + } else { + return false; + } + } else { + ALOGW("Unexpected token: %s", token.c_str()); + return false; + } + + return true; +} + +bool AccessControlConfigParser::parsePropertyGroup( + char group, VehiclePropertyGroup* outPropertyGroup) const { + switch (group) { + case 'S': // Fall through. + case 's': + *outPropertyGroup = VehiclePropertyGroup::SYSTEM; + break; + case 'V': // Fall through. + case 'v': + *outPropertyGroup = VehiclePropertyGroup::VENDOR; + break; + default: + ALOGW("Unexpected group: %c", group); + return false; + } + return true; +} + +bool AccessControlConfigParser::parsePropertyId( + const std::string& strPropId, + VehiclePropertyGroup propertyGroup, + int32_t* outVehicleProperty) const { + int32_t propId; + if (!parseInt(strPropId.c_str(), &propId)) { + ALOGW("Failed to convert property id to integer: %s", + strPropId.c_str()); + return false; + } + propId |= static_cast<int>(propertyGroup); + auto it = mStrippedToVehiclePropertyMap.find(propId); + if (it == mStrippedToVehiclePropertyMap.end()) { + ALOGW("Property Id not found or not supported: 0x%x", propId); + return false; + } + *outVehicleProperty = it->second; + return true; +} + +bool AccessControlConfigParser::parseInt(const char* strValue, + int* outIntValue) { + char* end; + long num = std::strtol(strValue, &end, 0 /* auto detect base */); + bool success = *end == 0 && errno != ERANGE; + if (success) { + *outIntValue = static_cast<int>(num); + } + + return success; +} + +bool AccessControlConfigParser::parseUid(const std::string& strUid, + unsigned* outUid) const { + auto element = mUidMap.find(strUid); + if (element != mUidMap.end()) { + *outUid = element->second; + } else { + int val; + if (!parseInt(strUid.c_str(), &val)) { + ALOGW("Failed to convert UID '%s' to integer", strUid.c_str()); + return false; + } + *outUid = static_cast<unsigned>(val); + } + return true; +} + +bool AccessControlConfigParser::parseAccess( + const std::string& strAccess, VehiclePropertyAccess* outAccess) const { + if (strAccess.size() == 0 || strAccess.size() > 2) { + ALOGW("Unknown access mode '%s'", strAccess.c_str()); + return false; + } + int32_t access = static_cast<int32_t>(VehiclePropertyAccess::NONE); + for (char c : strAccess) { + if (c == 'R' || c == 'r') { + access |= VehiclePropertyAccess::READ; + } else if (c == 'W' || c == 'w') { + access |= VehiclePropertyAccess::WRITE; + } else { + ALOGW("Unknown access mode: %c", c); + return false; + } + } + *outAccess = static_cast<VehiclePropertyAccess>(access); + return true; +} + +void AccessControlConfigParser::split(const std::string& line, + std::list<std::string>* outTokens) { + outTokens->clear(); + std::istringstream iss(line); + + while (!iss.eof()) { + std::string token; + iss >> token; + outTokens->push_back(std::move(token)); + } +} + +std::string AccessControlConfigParser::readNextToken( + std::list<std::string>* tokens) const { + if (tokens->empty()) { + return ""; + } + + std::string token = tokens->front(); + tokens->pop_front(); + return token; +} + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp new file mode 100644 index 0000000..4493a41 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
@@ -0,0 +1,313 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "automotive.vehicle@2.0-impl" + +#include "SubscriptionManager.h" + +#include <cmath> +#include <inttypes.h> + +#include <android/log.h> + +#include "VehicleUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +bool mergeSubscribeOptions(const SubscribeOptions &oldOpts, + const SubscribeOptions &newOpts, + SubscribeOptions *outResult) { + + int32_t updatedAreas = oldOpts.vehicleAreas; + if (updatedAreas != kAllSupportedAreas) { + updatedAreas = newOpts.vehicleAreas != kAllSupportedAreas + ? updatedAreas | newOpts.vehicleAreas + : kAllSupportedAreas; + } + + float updatedRate = std::max(oldOpts.sampleRate, newOpts.sampleRate); + SubscribeFlags updatedFlags = SubscribeFlags(oldOpts.flags | newOpts.flags); + + bool updated = updatedRate > oldOpts.sampleRate + || updatedAreas != oldOpts.vehicleAreas + || updatedFlags != oldOpts.flags; + if (updated) { + *outResult = oldOpts; + outResult->vehicleAreas = updatedAreas; + outResult->sampleRate = updatedRate; + outResult->flags = updatedFlags; + } + + return updated; +} + +void HalClient::addOrUpdateSubscription(const SubscribeOptions &opts) { + ALOGI("%s opts.propId: 0x%x", __func__, opts.propId); + + auto it = mSubscriptions.find(opts.propId); + if (it == mSubscriptions.end()) { + mSubscriptions.emplace(opts.propId, opts); + } else { + const SubscribeOptions& oldOpts = it->second; + SubscribeOptions updatedOptions; + if (mergeSubscribeOptions(oldOpts, opts, &updatedOptions)) { + mSubscriptions.erase(it); + mSubscriptions.emplace(opts.propId, updatedOptions); + } + } +} + +bool HalClient::isSubscribed(int32_t propId, + int32_t areaId, + SubscribeFlags flags) { + auto it = mSubscriptions.find(propId); + if (it == mSubscriptions.end()) { + return false; + } + const SubscribeOptions& opts = it->second; + bool res = (opts.flags & flags) + && (opts.vehicleAreas == 0 || areaId == 0 || opts.vehicleAreas & areaId); + return res; +} + +std::vector<int32_t> HalClient::getSubscribedProperties() const { + std::vector<int32_t> props; + for (const auto& subscription : mSubscriptions) { + ALOGI("%s propId: 0x%x, propId: 0x%x", __func__, subscription.first, subscription.second.propId); + props.push_back(subscription.first); + } + return props; +} + +StatusCode SubscriptionManager::addOrUpdateSubscription( + const sp<IVehicleCallback> &callback, + const hidl_vec<SubscribeOptions> &optionList, + std::list<SubscribeOptions>* outUpdatedSubscriptions) { + outUpdatedSubscriptions->clear(); + + MuxGuard g(mLock); + + ALOGI("SubscriptionManager::addOrUpdateSubscription, callback: %p", callback.get()); + + const sp<HalClient>& client = getOrCreateHalClientLocked(callback); + if (client.get() == nullptr) { + return StatusCode::INTERNAL_ERROR; + } + + for (size_t i = 0; i < optionList.size(); i++) { + const SubscribeOptions& opts = optionList[i]; + ALOGI("SubscriptionManager::addOrUpdateSubscription, prop: 0x%x", opts.propId); + client->addOrUpdateSubscription(opts); + + addClientToPropMapLocked(opts.propId, client); + + if (SubscribeFlags::HAL_EVENT & opts.flags) { + SubscribeOptions updated; + if (updateHalEventSubscriptionLocked(opts, &updated)) { + outUpdatedSubscriptions->push_back(updated); + } + } + } + + return StatusCode::OK; +} + +std::list<HalClientValues> SubscriptionManager::distributeValuesToClients( + const std::vector<recyclable_ptr<VehiclePropValue>>& propValues, + SubscribeFlags flags) const { + std::map<sp<HalClient>, std::list<VehiclePropValue*>> clientValuesMap; + + { + MuxGuard g(mLock); + for (const auto& propValue: propValues) { + VehiclePropValue* v = propValue.get(); + auto clients = getSubscribedClientsLocked( + v->prop, v->areaId, flags); + for (const auto& client : clients) { + clientValuesMap[client].push_back(v); + } + } + } + + std::list<HalClientValues> clientValues; + for (const auto& entry : clientValuesMap) { + clientValues.push_back(HalClientValues { + .client = entry.first, + .values = entry.second + }); + } + + return clientValues; +} + +std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients( + int32_t propId, int32_t area, SubscribeFlags flags) const { + MuxGuard g(mLock); + return getSubscribedClientsLocked(propId, area, flags); +} + +std::list<sp<HalClient>> SubscriptionManager::getSubscribedClientsLocked( + int32_t propId, int32_t area, SubscribeFlags flags) const { + std::list<sp<HalClient>> subscribedClients; + + sp<HalClientVector> propClients = getClientsForPropertyLocked(propId); + if (propClients.get() != nullptr) { + for (size_t i = 0; i < propClients->size(); i++) { + const auto& client = propClients->itemAt(i); + if (client->isSubscribed(propId, area, flags)) { + subscribedClients.push_back(client); + } + } + } + + return subscribedClients; +} + +bool SubscriptionManager::updateHalEventSubscriptionLocked( + const SubscribeOptions &opts, SubscribeOptions *outUpdated) { + bool updated = false; + auto it = mHalEventSubscribeOptions.find(opts.propId); + if (it == mHalEventSubscribeOptions.end()) { + *outUpdated = opts; + mHalEventSubscribeOptions.emplace(opts.propId, opts); + updated = true; + } else { + const SubscribeOptions& oldOpts = it->second; + + if (mergeSubscribeOptions(oldOpts, opts, outUpdated)) { + mHalEventSubscribeOptions.erase(opts.propId); + mHalEventSubscribeOptions.emplace(opts.propId, *outUpdated); + updated = true; + } + } + + return updated; +} + +void SubscriptionManager::addClientToPropMapLocked( + int32_t propId, const sp<HalClient> &client) { + auto it = mPropToClients.find(propId); + sp<HalClientVector> propClients; + if (it == mPropToClients.end()) { + propClients = new HalClientVector(); + mPropToClients.insert(std::make_pair(propId, propClients)); + } else { + propClients = it->second; + } + propClients->addOrUpdate(client); +} + +sp<HalClientVector> SubscriptionManager::getClientsForPropertyLocked( + int32_t propId) const { + auto it = mPropToClients.find(propId); + return it == mPropToClients.end() ? nullptr : it->second; +} + +sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked( + const sp<IVehicleCallback>& callback) { + auto it = mClients.find(callback); + if (it == mClients.end()) { + uint64_t cookie = reinterpret_cast<uint64_t>(callback.get()); + ALOGI("Creating new client and linking to death recipient, cookie: 0x%" PRIx64, cookie); + auto res = callback->linkToDeath(mCallbackDeathRecipient, cookie); + if (!res.isOk()) { // Client is already dead? + ALOGW("%s failed to link to death, client %p, err: %s", + __func__, callback.get(), res.description().c_str()); + return nullptr; + } + IPCThreadState* self = IPCThreadState::self(); + pid_t pid = self->getCallingPid(); + uid_t uid = self->getCallingUid(); + sp<HalClient> client = new HalClient(callback, pid, uid); + mClients.emplace(callback, client); + return client; + } else { + return it->second; + } +} + +void SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback, + int32_t propId) { + MuxGuard g(mLock); + auto propertyClients = getClientsForPropertyLocked(propId); + auto clientIter = mClients.find(callback); + if (clientIter == mClients.end()) { + ALOGW("Unable to unsubscribe: no callback found, propId: 0x%x", propId); + } else { + auto client = clientIter->second; + + if (propertyClients != nullptr) { + propertyClients->remove(client); + + if (propertyClients->isEmpty()) { + mPropToClients.erase(propId); + } + } + + bool isClientSubscribedToOtherProps = false; + for (const auto& propClient : mPropToClients) { + if (propClient.second->indexOf(client) >= 0) { + isClientSubscribedToOtherProps = true; + break; + } + } + + if (!isClientSubscribedToOtherProps) { + auto res = client->getCallback()->unlinkToDeath(mCallbackDeathRecipient); + if (!res.isOk()) { + ALOGW("%s failed to unlink to death, client: %p, err: %s", + __func__, client->getCallback().get(), res.description().c_str()); + } + mClients.erase(clientIter); + } + } + + if (propertyClients == nullptr || propertyClients->isEmpty()) { + mHalEventSubscribeOptions.erase(propId); + mOnPropertyUnsubscribed(propId); + } +} + +void SubscriptionManager::onCallbackDead(uint64_t cookie) { + ALOGI("%s, cookie: 0x%" PRIx64, __func__, cookie); + IVehicleCallback* callback = reinterpret_cast<IVehicleCallback*>(cookie); + + std::vector<int32_t> props; + { + MuxGuard g(mLock); + const auto& it = mClients.find(callback); + if (it == mClients.end()) { + return; // Nothing to do here, client wasn't subscribed to any properties. + } + const auto& halClient = it->second; + props = halClient->getSubscribedProperties(); + } + + for (int32_t propId : props) { + unsubscribe(callback, propId); + } +} + + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp new file mode 100644 index 0000000..8906f6e --- /dev/null +++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -0,0 +1,397 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "automotive.vehicle@2.0-impl" + +#include "VehicleHalManager.h" + +#include <fstream> + +#include <android/log.h> +#include <private/android_filesystem_config.h> + +#include "VehicleUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +using namespace std::placeholders; + +constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10); + +const VehiclePropValue kEmptyValue{}; + +/** + * Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want + * to store in reusable object pool. + */ +constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20; + +Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) { + ALOGI("getAllPropConfigs called"); + hidl_vec<VehiclePropConfig> hidlConfigs; + auto& halConfig = mConfigIndex->getAllConfigs(); + + hidlConfigs.setToExternal( + const_cast<VehiclePropConfig *>(halConfig.data()), + halConfig.size()); + + _hidl_cb(hidlConfigs); + + return Void(); +} + +Return<void> VehicleHalManager::getPropConfigs(const hidl_vec<int32_t> &properties, + getPropConfigs_cb _hidl_cb) { + std::vector<VehiclePropConfig> configs; + for (size_t i = 0; i < properties.size(); i++) { + auto prop = properties[i]; + if (mConfigIndex->hasConfig(prop)) { + configs.push_back(mConfigIndex->getConfig(prop)); + } else { + ALOGW("Requested config for undefined property: 0x%x", prop); + _hidl_cb(StatusCode::INVALID_ARG, hidl_vec<VehiclePropConfig>()); + } + } + + _hidl_cb(StatusCode::OK, configs); + + return Void(); +} + +Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) { + const auto* config = getPropConfigOrNull(requestedPropValue.prop); + if (config == nullptr) { + ALOGE("Failed to get value: config not found, property: 0x%x", + requestedPropValue.prop); + _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue); + return Void(); + } + + if (!checkReadPermission(*config, getCaller())) { + _hidl_cb(StatusCode::ACCESS_DENIED, kEmptyValue); + return Void(); + } + + StatusCode status; + auto value = mHal->get(requestedPropValue, &status); + _hidl_cb(status, value.get() ? *value : kEmptyValue); + + + return Void(); +} + +Return<StatusCode> VehicleHalManager::set(const VehiclePropValue &value) { + auto prop = value.prop; + const auto* config = getPropConfigOrNull(prop); + if (config == nullptr) { + ALOGE("Failed to set value: config not found, property: 0x%x", prop); + return StatusCode::INVALID_ARG; + } + + if (!checkWritePermission(*config, getCaller())) { + return StatusCode::ACCESS_DENIED; + } + + handlePropertySetEvent(value); + + auto status = mHal->set(value); + + return Return<StatusCode>(status); +} + +Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback, + const hidl_vec<SubscribeOptions> &options) { + hidl_vec<SubscribeOptions> verifiedOptions(options); + auto caller = getCaller(); + for (size_t i = 0; i < verifiedOptions.size(); i++) { + SubscribeOptions& ops = verifiedOptions[i]; + auto prop = ops.propId; + + const auto* config = getPropConfigOrNull(prop); + if (config == nullptr) { + ALOGE("Failed to subscribe: config not found, property: 0x%x", + prop); + return StatusCode::INVALID_ARG; + } + + if (ops.flags == SubscribeFlags::UNDEFINED) { + ALOGE("Failed to subscribe: undefined flag in options provided"); + return StatusCode::INVALID_ARG; + } + + if (!checkAcl(caller.uid, config->prop, VehiclePropertyAccess::READ)) { + return StatusCode::ACCESS_DENIED; + } + + if (!isSubscribable(*config, ops.flags)) { + ALOGE("Failed to subscribe: property 0x%x is not subscribable", + prop); + return StatusCode::INVALID_ARG; + } + + int32_t areas = isGlobalProp(prop) ? 0 : ops.vehicleAreas; + if (areas != 0 && ((areas & config->supportedAreas) != areas)) { + ALOGE("Failed to subscribe property 0x%x. Requested areas 0x%x are " + "out of supported range of 0x%x", prop, ops.vehicleAreas, + config->supportedAreas); + return StatusCode::INVALID_ARG; + } + + ops.vehicleAreas = areas; + ops.sampleRate = checkSampleRate(*config, ops.sampleRate); + } + + std::list<SubscribeOptions> updatedOptions; + auto res = mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions, + &updatedOptions); + if (StatusCode::OK != res) { + ALOGW("%s failed to subscribe, error code: %d", __func__, res); + return res; + } + + for (auto opt : updatedOptions) { + mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate); + } + + return StatusCode::OK; +} + +Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback, + int32_t propId) { + mSubscriptionManager.unsubscribe(callback, propId); + return StatusCode::OK; +} + +Return<void> VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) { + _hidl_cb(""); + return Void(); +} + +void VehicleHalManager::init() { + ALOGI("VehicleHalManager::init"); + + mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize); + + + mBatchingConsumer.run(&mEventQueue, + kHalEventBatchingTimeWindow, + std::bind(&VehicleHalManager::onBatchHalEvent, + this, _1)); + + mHal->init(&mValueObjectPool, + std::bind(&VehicleHalManager::onHalEvent, this, _1), + std::bind(&VehicleHalManager::onHalPropertySetError, this, + _1, _2, _3)); + + // Initialize index with vehicle configurations received from VehicleHal. + auto supportedPropConfigs = mHal->listProperties(); + mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs)); + + std::vector<int32_t> supportedProperties( + supportedPropConfigs.size()); + for (const auto& config : supportedPropConfigs) { + supportedProperties.push_back(config.prop); + } + + AccessControlConfigParser aclParser(supportedProperties); + const char* configs[] = { "/system/etc/vehicle_access.conf", + "/vendor/etc/vehicle_access.conf" }; + for (const char* filename : configs) { + readAndParseAclConfig(filename, &aclParser, &mPropertyAclMap); + } +} + +VehicleHalManager::~VehicleHalManager() { + mBatchingConsumer.requestStop(); + mEventQueue.deactivate(); + // We have to wait until consumer thread is fully stopped because it may + // be in a state of running callback (onBatchHalEvent). + mBatchingConsumer.waitStopped(); + ALOGI("VehicleHalManager::dtor"); +} + +void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) { + mEventQueue.push(std::move(v)); +} + +void VehicleHalManager::onHalPropertySetError(StatusCode errorCode, + int32_t property, + int32_t areaId) { + const auto& clients = mSubscriptionManager.getSubscribedClients( + property, 0, SubscribeFlags::HAL_EVENT); + + for (auto client : clients) { + client->getCallback()->onPropertySetError(errorCode, property, areaId); + } +} + +void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) { + const auto& clientValues = mSubscriptionManager.distributeValuesToClients( + values, SubscribeFlags::HAL_EVENT); + + for (const HalClientValues& cv : clientValues) { + auto vecSize = cv.values.size(); + hidl_vec<VehiclePropValue> vec; + if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) { + vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize); + } else { + vec.resize(vecSize); + } + + int i = 0; + for (VehiclePropValue* pValue : cv.values) { + shallowCopy(&(vec)[i++], *pValue); + } + auto status = cv.client->getCallback()->onPropertyEvent(vec); + if (!status.isOk()) { + ALOGE("Failed to notify client %s, err: %s", + toString(cv.client->getCallback()).c_str(), + status.description().c_str()); + } + } +} + +bool VehicleHalManager::isSampleRateFixed(VehiclePropertyChangeMode mode) { + return (mode & VehiclePropertyChangeMode::ON_SET) + || (mode & VehiclePropertyChangeMode::ON_CHANGE); +} + +float VehicleHalManager::checkSampleRate(const VehiclePropConfig &config, + float sampleRate) { + if (isSampleRateFixed(config.changeMode)) { + if (std::abs(sampleRate) > std::numeric_limits<float>::epsilon()) { + ALOGW("Sample rate is greater than zero for on change type. " + "Ignoring it."); + } + return 0.0; + } else { + if (sampleRate > config.maxSampleRate) { + ALOGW("Sample rate %f is higher than max %f. Setting sampling rate " + "to max.", sampleRate, config.maxSampleRate); + return config.maxSampleRate; + } + if (sampleRate < config.minSampleRate) { + ALOGW("Sample rate %f is lower than min %f. Setting sampling rate " + "to min.", sampleRate, config.minSampleRate); + return config.minSampleRate; + } + } + return sampleRate; // Provided sample rate was good, no changes. +} + +bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config, + SubscribeFlags flags) { + bool isReadable = config.access & VehiclePropertyAccess::READ; + + if (!isReadable && (SubscribeFlags::HAL_EVENT & flags)) { + ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop); + return false; + } + if (config.changeMode == VehiclePropertyChangeMode::STATIC) { + ALOGW("Cannot subscribe, property 0x%x is static", config.prop); + return false; + } + + //TODO: extend to support event notification for set from android + if (config.changeMode == VehiclePropertyChangeMode::POLL) { + ALOGW("Cannot subscribe, property 0x%x is poll only", config.prop); + return false; + } + return true; +} + +bool VehicleHalManager::checkAcl(uid_t callerUid, int32_t propertyId, + VehiclePropertyAccess requiredAccess) const { + if (callerUid == AID_SYSTEM && isSystemProperty(propertyId)) { + return true; + } + + auto range = mPropertyAclMap.equal_range(propertyId); + for (auto it = range.first; it != range.second; ++it) { + auto& acl = it->second; + if (acl.uid == callerUid && (acl.access & requiredAccess)) { + return true; + } + } + return false; +} + +bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config, + const Caller& caller) const { + if (!(config.access & VehiclePropertyAccess::WRITE)) { + ALOGW("Property 0%x has no write access", config.prop); + return false; + } + return checkAcl(caller.uid, config.prop, VehiclePropertyAccess::WRITE); +} + +bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config, + const Caller& caller) const { + if (!(config.access & VehiclePropertyAccess::READ)) { + ALOGW("Property 0%x has no read access", config.prop); + return false; + } + + return checkAcl(caller.uid, config.prop, VehiclePropertyAccess::READ); +} + +void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) { + auto clients = mSubscriptionManager.getSubscribedClients( + value.prop, value.areaId, SubscribeFlags::SET_CALL); + for (auto client : clients) { + client->getCallback()->onPropertySet(value); + } +} + +const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull( + int32_t prop) const { + return mConfigIndex->hasConfig(prop) + ? &mConfigIndex->getConfig(prop) : nullptr; +} + +Caller VehicleHalManager::getCaller() { + Caller caller; + IPCThreadState* self = IPCThreadState::self(); + caller.pid = self->getCallingPid(); + caller.uid = self->getCallingUid(); + + return caller; +} + +void VehicleHalManager::readAndParseAclConfig(const char* filename, + AccessControlConfigParser* parser, + PropertyAclMap* outAclMap) { + std::ifstream file(filename); + if (file.is_open()) { + ALOGI("Parsing file: %s", filename); + parser->parseFromStream(&file, outAclMap); + file.close(); + } +} + +void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) { + mHal->unsubscribe(propertyId); +} + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp new file mode 100644 index 0000000..ac1245a --- /dev/null +++ b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
@@ -0,0 +1,163 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "automotive.vehicle@2.0-impl" + +#include "VehicleObjectPool.h" + +#include <log/log.h> + +#include "VehicleUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtain( + VehiclePropertyType type, size_t vecSize) { + return isDisposable(type, vecSize) + ? obtainDisposable(type, vecSize) + : obtainRecylable(type, vecSize); +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtain( + const VehiclePropValue& src) { + if (src.prop == toInt(VehicleProperty::INVALID)) { + ALOGE("Unable to obtain an object from pool for unknown property"); + return RecyclableType(); + } + VehiclePropertyType type = getPropType(src.prop); + size_t vecSize = getVehicleRawValueVectorSize(src.value, type);; + auto dest = obtain(type, vecSize); + + dest->prop = src.prop; + dest->areaId = src.areaId; + dest->timestamp = src.timestamp; + copyVehicleRawValue(&dest->value, src.value); + + return dest; +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainInt32( + int32_t value) { + auto val = obtain(VehiclePropertyType::INT32); + val->value.int32Values[0] = value; + return val; +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainInt64( + int64_t value) { + auto val = obtain(VehiclePropertyType::INT64); + val->value.int64Values[0] = value; + return val; +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainFloat( + float value) { + auto val = obtain(VehiclePropertyType::FLOAT); + val->value.floatValues[0] = value; + return val; +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainString( + const char* cstr) { + auto val = obtain(VehiclePropertyType::STRING); + val->value.stringValue = cstr; + return val; +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainComplex() { + return obtain(VehiclePropertyType::COMPLEX); +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainRecylable( + VehiclePropertyType type, size_t vecSize) { + // VehiclePropertyType is not overlapping with vectorSize. + int32_t key = static_cast<int32_t>(type) + | static_cast<int32_t>(vecSize); + + std::lock_guard<std::mutex> g(mLock); + auto it = mValueTypePools.find(key); + + if (it == mValueTypePools.end()) { + auto newPool(std::make_unique<InternalPool>(type, vecSize)); + it = mValueTypePools.emplace(key, std::move(newPool)).first; + } + return it->second->obtain(); +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainBoolean( + bool value) { + return obtainInt32(value); +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainDisposable( + VehiclePropertyType valueType, size_t vectorSize) const { + return RecyclableType { + createVehiclePropValue(valueType, vectorSize).release(), + mDisposableDeleter + }; +} + +VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtain( + VehiclePropertyType type) { + return obtain(type, 1); +} + + +void VehiclePropValuePool::InternalPool::recycle(VehiclePropValue* o) { + if (o == nullptr) { + ALOGE("Attempt to recycle nullptr"); + return; + } + + if (!check(&o->value)) { + ALOGE("Discarding value for prop 0x%x because it contains " + "data that is not consistent with this pool. " + "Expected type: %d, vector size: %zu", + o->prop, mPropType, mVectorSize); + delete o; + } else { + ObjectPool<VehiclePropValue>::recycle(o); + } +} + +bool VehiclePropValuePool::InternalPool::check(VehiclePropValue::RawValue* v) { + return check(&v->int32Values, + (VehiclePropertyType::INT32 == mPropType + || VehiclePropertyType::INT32_VEC == mPropType + || VehiclePropertyType::BOOLEAN == mPropType)) + && check(&v->floatValues, + (VehiclePropertyType::FLOAT == mPropType + || VehiclePropertyType::FLOAT_VEC == mPropType)) + && check(&v->int64Values, + VehiclePropertyType::INT64 == mPropType) + && check(&v->bytes, + VehiclePropertyType::BYTES == mPropType) + && v->stringValue.size() == 0; +} + +VehiclePropValue* VehiclePropValuePool::InternalPool::createObject() { + return createVehiclePropValue(mPropType, mVectorSize).release(); +} + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp new file mode 100644 index 0000000..311cdef --- /dev/null +++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -0,0 +1,130 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "automotive.vehicle@2.0-impl" + +#include "VehicleUtils.h" + +#include <log/log.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +//namespace utils { + +std::unique_ptr<VehiclePropValue> createVehiclePropValue( + VehiclePropertyType type, size_t vecSize) { + auto val = std::unique_ptr<VehiclePropValue>(new VehiclePropValue); + switch (type) { + case VehiclePropertyType::INT32: // fall through + case VehiclePropertyType::INT32_VEC: // fall through + case VehiclePropertyType::BOOLEAN: + val->value.int32Values.resize(vecSize); + break; + case VehiclePropertyType::FLOAT: // fall through + case VehiclePropertyType::FLOAT_VEC: + val->value.floatValues.resize(vecSize); + break; + case VehiclePropertyType::INT64: + val->value.int64Values.resize(vecSize); + break; + case VehiclePropertyType::BYTES: + val->value.bytes.resize(vecSize); + break; + case VehiclePropertyType::STRING: + case VehiclePropertyType::COMPLEX: + break; // Valid, but nothing to do. + default: + ALOGE("createVehiclePropValue: unknown type: %d", type); + val.reset(nullptr); + } + return val; +} + +size_t getVehicleRawValueVectorSize( + const VehiclePropValue::RawValue& value, VehiclePropertyType type) { + switch (type) { + case VehiclePropertyType::INT32: // fall through + case VehiclePropertyType::INT32_VEC: // fall through + case VehiclePropertyType::BOOLEAN: + return value.int32Values.size(); + case VehiclePropertyType::FLOAT: // fall through + case VehiclePropertyType::FLOAT_VEC: + return value.floatValues.size(); + case VehiclePropertyType::INT64: + return value.int64Values.size(); + case VehiclePropertyType::BYTES: + return value.bytes.size(); + default: + return 0; + } +} + +template<typename T> +inline void copyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) { + for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) { + (*dest)[i] = src[i]; + } +} + +void copyVehicleRawValue(VehiclePropValue::RawValue* dest, + const VehiclePropValue::RawValue& src) { + dest->int32Values = src.int32Values; + dest->floatValues = src.floatValues; + dest->int64Values = src.int64Values; + dest->bytes = src.bytes; + dest->stringValue = src.stringValue; +} + +template<typename T> +void shallowCopyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) { + if (src.size() > 0) { + dest->setToExternal(const_cast<T*>(&src[0]), src.size()); + } else if (dest->size() > 0) { + dest->resize(0); + } +} + +void shallowCopyHidlStr(hidl_string* dest, const hidl_string& src) { + if (!src.empty()) { + dest->setToExternal(src.c_str(), src.size()); + } else if (dest->size() > 0) { + dest->setToExternal(0, 0); + } +} + +void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src) { + dest->prop = src.prop; + dest->areaId = src.areaId; + dest->timestamp = src.timestamp; + shallowCopyHidlVec(&dest->value.int32Values, src.value.int32Values); + shallowCopyHidlVec(&dest->value.int64Values, src.value.int64Values); + shallowCopyHidlVec(&dest->value.floatValues, src.value.floatValues); + shallowCopyHidlVec(&dest->value.bytes, src.value.bytes); + shallowCopyHidlStr(&dest->value.stringValue, src.value.stringValue); +} + + +//} // namespace utils + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h new file mode 100644 index 0000000..6832ad3 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h
@@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_ + +#include <string> +#include <vector> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +/** + * This is the communications base class. It defines the interface used in DefaultVehicleHal to + * send and receive data to and from the emulator. + */ +class CommBase { +public: + virtual ~CommBase() = default; + + /** + * Closes a connection if it is open. + */ + virtual void stop() {} + + /** + * Creates a connection to the other side. + * + * @return int Returns fd or socket number if connection is successful. + * Otherwise, returns -1 if no connection is availble. + */ + virtual int connect() { return 0; } + + /** + * Opens the communications channel. + * + * @return int Returns 0 if channel is opened, else -errno if failed. + */ + virtual int open() = 0; + + /** + * Blocking call to read data from the connection. + * + * @return std::vector<uint8_t> Serialized protobuf data received from emulator. This will be + * an empty vector if the connection was closed or some other error occurred. + */ + virtual std::vector<uint8_t> read() = 0; + + /** + * Transmits a string of data to the emulator. + * + * @param data Serialized protobuf data to transmit. + * + * @return int Number of bytes transmitted, or -1 if failed. + */ + virtual int write(const std::vector<uint8_t>& data) = 0; +}; + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + +#endif // android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h new file mode 100644 index 0000000..95ca37b --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -0,0 +1,217 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_ + +#include <android/hardware/automotive/vehicle/2.0/IVehicle.h> +#include <vhal_v2_0/VehicleUtils.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +const VehicleProperty kHvacPowerProperties[] = { + VehicleProperty::HVAC_FAN_SPEED, + VehicleProperty::HVAC_FAN_DIRECTION, +}; + +const VehiclePropConfig kVehicleProperties[] = { + { + .prop = toInt(VehicleProperty::INFO_MAKE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + + { + .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + + { + .prop = toInt(VehicleProperty::CURRENT_GEAR), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + + { + .prop = toInt(VehicleProperty::PARKING_BRAKE_ON), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + + { + .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + + { + .prop = toInt(VehicleProperty::HVAC_POWER_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .supportedAreas = toInt(VehicleAreaZone::ROW_1), + // TODO(bryaneyler): Ideally, this is generated dynamically from + // kHvacPowerProperties. + .configString = "0x12400500,0x12400501" // HVAC_FAN_SPEED,HVAC_FAN_DIRECTION + }, + + { + .prop = toInt(VehicleProperty::HVAC_DEFROSTER), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .supportedAreas = + VehicleAreaWindow::FRONT_WINDSHIELD + | VehicleAreaWindow::REAR_WINDSHIELD + }, + + { + .prop = toInt(VehicleProperty::HVAC_RECIRC_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .supportedAreas = toInt(VehicleAreaZone::ROW_1) + }, + + { + .prop = toInt(VehicleProperty::HVAC_AC_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .supportedAreas = toInt(VehicleAreaZone::ROW_1) + }, + + { + .prop = toInt(VehicleProperty::HVAC_AUTO_ON), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .supportedAreas = toInt(VehicleAreaZone::ROW_1) + }, + + { + .prop = toInt(VehicleProperty::HVAC_FAN_SPEED), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .supportedAreas = toInt(VehicleAreaZone::ROW_1), + .areaConfigs = { + VehicleAreaConfig { + .areaId = toInt(VehicleAreaZone::ROW_1), + .minInt32Value = 1, + .maxInt32Value = 7 + } + } + }, + + { + .prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .supportedAreas = toInt(VehicleAreaZone::ROW_1), + }, + + { + .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .supportedAreas = + VehicleAreaZone::ROW_1_LEFT + | VehicleAreaZone::ROW_1_RIGHT, + .areaConfigs = { + VehicleAreaConfig { + .areaId = toInt(VehicleAreaZone::ROW_1_LEFT), + .minFloatValue = 16, + .maxFloatValue = 32, + }, + VehicleAreaConfig { + .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT), + .minFloatValue = 16, + .maxFloatValue = 32, + } + } + }, + + { + .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE), + .access = VehiclePropertyAccess::READ, + // TODO(bryaneyler): Support ON_CHANGE as well. + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 1.0f, + .maxSampleRate = 2.0f, + }, + + { + .prop = toInt(VehicleProperty::NIGHT_MODE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + + { + .prop = toInt(VehicleProperty::DRIVING_STATUS), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + + { + .prop = toInt(VehicleProperty::GEAR_SELECTION), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + + { + .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + }, + + { + .prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = { + VehicleAreaConfig { + .minInt32Value = 0, + .maxInt32Value = 10 + } + } + }, + + { + .prop = toInt(VehicleProperty::IGNITION_STATE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + + { + .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::CONTINUOUS, + .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds + .maxSampleRate = 10, // 10 Hz, every 100 ms + } +}; + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp new file mode 100644 index 0000000..808aafb --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
@@ -0,0 +1,679 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "DefaultVehicleHal_v2_0" +#include <android/log.h> + +#include <algorithm> +#include <android-base/properties.h> +#include <cstdio> + +#include "DefaultVehicleHal.h" +#include "PipeComm.h" +#include "SocketComm.h" +#include "VehicleHalProto.pb.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +void DefaultVehicleHal::doGetConfig(emulator::EmulatorMessage& rxMsg, + emulator::EmulatorMessage& respMsg) { + std::vector<VehiclePropConfig> configs = listProperties(); + emulator::VehiclePropGet getProp = rxMsg.prop(0); + + respMsg.set_msg_type(emulator::GET_CONFIG_RESP); + respMsg.set_status(emulator::ERROR_INVALID_PROPERTY); + + for (auto& config : configs) { + // Find the config we are looking for + if (config.prop == getProp.prop()) { + emulator::VehiclePropConfig* protoCfg = respMsg.add_config(); + populateProtoVehicleConfig(protoCfg, config); + respMsg.set_status(emulator::RESULT_OK); + break; + } + } +} + +void DefaultVehicleHal::doGetConfigAll(emulator::EmulatorMessage& /* rxMsg */, + emulator::EmulatorMessage& respMsg) { + std::vector<VehiclePropConfig> configs = listProperties(); + + respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP); + respMsg.set_status(emulator::RESULT_OK); + + for (auto& config : configs) { + emulator::VehiclePropConfig* protoCfg = respMsg.add_config(); + populateProtoVehicleConfig(protoCfg, config); + } +} + +void DefaultVehicleHal::doGetProperty(emulator::EmulatorMessage& rxMsg, + emulator::EmulatorMessage& respMsg) { + int32_t areaId = 0; + emulator::VehiclePropGet getProp = rxMsg.prop(0); + int32_t propId = getProp.prop(); + emulator::Status status = emulator::ERROR_INVALID_PROPERTY; + VehiclePropValue* val; + + respMsg.set_msg_type(emulator::GET_PROPERTY_RESP); + + if (getProp.has_area_id()) { + areaId = getProp.area_id(); + } + + { + std::lock_guard<std::mutex> lock(mPropsMutex); + + val = getVehiclePropValueLocked(propId, areaId); + if (val != nullptr) { + emulator::VehiclePropValue* protoVal = respMsg.add_value(); + populateProtoVehiclePropValue(protoVal, val); + status = emulator::RESULT_OK; + } + } + + respMsg.set_status(status); +} + +void DefaultVehicleHal::doGetPropertyAll(emulator::EmulatorMessage& /* rxMsg */, + emulator::EmulatorMessage& respMsg) { + respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP); + respMsg.set_status(emulator::RESULT_OK); + + { + std::lock_guard<std::mutex> lock(mPropsMutex); + + for (auto& prop : mProps) { + emulator::VehiclePropValue* protoVal = respMsg.add_value(); + populateProtoVehiclePropValue(protoVal, prop.second.get()); + } + } +} + +void DefaultVehicleHal::doSetProperty(emulator::EmulatorMessage& rxMsg, + emulator::EmulatorMessage& respMsg) { + emulator::VehiclePropValue protoVal = rxMsg.value(0); + VehiclePropValue val; + + respMsg.set_msg_type(emulator::SET_PROPERTY_RESP); + + val.prop = protoVal.prop(); + val.areaId = protoVal.area_id(); + val.timestamp = elapsedRealtimeNano(); + + // Copy value data if it is set. This automatically handles complex data types if needed. + if (protoVal.has_string_value()) { + val.value.stringValue = protoVal.string_value().c_str(); + } + + if (protoVal.has_bytes_value()) { + std::vector<uint8_t> tmp(protoVal.bytes_value().begin(), protoVal.bytes_value().end()); + val.value.bytes = tmp; + } + + if (protoVal.int32_values_size() > 0) { + std::vector<int32_t> int32Values = std::vector<int32_t>(protoVal.int32_values_size()); + for (int i=0; i<protoVal.int32_values_size(); i++) { + int32Values[i] = protoVal.int32_values(i); + } + val.value.int32Values = int32Values; + } + + if (protoVal.int64_values_size() > 0) { + std::vector<int64_t> int64Values = std::vector<int64_t>(protoVal.int64_values_size()); + for (int i=0; i<protoVal.int64_values_size(); i++) { + int64Values[i] = protoVal.int64_values(i); + } + val.value.int64Values = int64Values; + } + + if (protoVal.float_values_size() > 0) { + std::vector<float> floatValues = std::vector<float>(protoVal.float_values_size()); + for (int i=0; i<protoVal.float_values_size(); i++) { + floatValues[i] = protoVal.float_values(i); + } + val.value.floatValues = floatValues; + } + + if (updateProperty(val) == StatusCode::OK) { + // Send property up to VehicleHalManager via callback + auto& pool = *getValuePool(); + VehiclePropValuePtr v = pool.obtain(val); + + doHalEvent(std::move(v)); + respMsg.set_status(emulator::RESULT_OK); + } else { + respMsg.set_status(emulator::ERROR_INVALID_PROPERTY); + } +} + +// This function should only be called while mPropsMutex is locked. +VehiclePropValue* DefaultVehicleHal::getVehiclePropValueLocked(int32_t propId, int32_t areaId) { + if (getPropArea(propId) == VehicleArea::GLOBAL) { + // In VehicleHal, global properties have areaId = -1. We use 0. + areaId = 0; + } + + auto prop = mProps.find(std::make_pair(propId, areaId)); + if (prop != mProps.end()) { + return prop->second.get(); + } + ALOGW("%s: Property not found: propId = 0x%x, areaId = 0x%x", __func__, propId, areaId); + return nullptr; +} + +void DefaultVehicleHal::parseRxProtoBuf(std::vector<uint8_t>& msg) { + emulator::EmulatorMessage rxMsg; + emulator::EmulatorMessage respMsg; + + if (rxMsg.ParseFromArray(msg.data(), msg.size())) { + switch (rxMsg.msg_type()) { + case emulator::GET_CONFIG_CMD: + doGetConfig(rxMsg, respMsg); + break; + case emulator::GET_CONFIG_ALL_CMD: + doGetConfigAll(rxMsg, respMsg); + break; + case emulator::GET_PROPERTY_CMD: + doGetProperty(rxMsg, respMsg); + break; + case emulator::GET_PROPERTY_ALL_CMD: + doGetPropertyAll(rxMsg, respMsg); + break; + case emulator::SET_PROPERTY_CMD: + doSetProperty(rxMsg, respMsg); + break; + default: + ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type()); + respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD); + break; + } + + // Send the reply + txMsg(respMsg); + } else { + ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size())); + } +} + +// Copies internal VehiclePropConfig data structure to protobuf VehiclePropConfig +void DefaultVehicleHal::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg, + const VehiclePropConfig& cfg) { + protoCfg->set_prop(cfg.prop); + protoCfg->set_access(toInt(cfg.access)); + protoCfg->set_change_mode(toInt(cfg.changeMode)); + protoCfg->set_value_type(toInt(getPropType(cfg.prop))); + + if (!isGlobalProp(cfg.prop)) { + protoCfg->set_supported_areas(cfg.supportedAreas); + } + + for (auto& configElement : cfg.configArray) { + protoCfg->add_config_array(configElement); + } + + if (cfg.configString.size() > 0) { + protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size()); + } + + // Populate the min/max values based on property type + switch (getPropType(cfg.prop)) { + case VehiclePropertyType::STRING: + case VehiclePropertyType::BOOLEAN: + case VehiclePropertyType::INT32_VEC: + case VehiclePropertyType::FLOAT_VEC: + case VehiclePropertyType::BYTES: + case VehiclePropertyType::COMPLEX: + // Do nothing. These types don't have min/max values + break; + case VehiclePropertyType::INT64: + if (cfg.areaConfigs.size() > 0) { + emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); + aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value); + aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value); + } + break; + case VehiclePropertyType::FLOAT: + if (cfg.areaConfigs.size() > 0) { + emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); + aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue); + aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue); + } + break; + case VehiclePropertyType::INT32: + if (cfg.areaConfigs.size() > 0) { + emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs(); + aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value); + aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value); + } + break; + default: + ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop))); + break; + } + + protoCfg->set_min_sample_rate(cfg.minSampleRate); + protoCfg->set_max_sample_rate(cfg.maxSampleRate); +} + +// Copies internal VehiclePropValue data structure to protobuf VehiclePropValue +void DefaultVehicleHal::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal, + const VehiclePropValue* val) { + protoVal->set_prop(val->prop); + protoVal->set_value_type(toInt(getPropType(val->prop))); + protoVal->set_timestamp(val->timestamp); + protoVal->set_area_id(val->areaId); + + // Copy value data if it is set. + // - for bytes and strings, this is indicated by size > 0 + // - for int32, int64, and float, copy the values if vectors have data + if (val->value.stringValue.size() > 0) { + protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size()); + } + + if (val->value.bytes.size() > 0) { + protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size()); + } + + for (auto& int32Value : val->value.int32Values) { + protoVal->add_int32_values(int32Value); + } + + for (auto& int64Value : val->value.int64Values) { + protoVal->add_int64_values(int64Value); + } + + for (auto& floatValue : val->value.floatValues) { + protoVal->add_float_values(floatValue); + } +} + +void DefaultVehicleHal::rxMsg() { + int numBytes = 0; + + while (mExit == 0) { + std::vector<uint8_t> msg = mComm->read(); + + if (msg.size() > 0) { + // Received a message. + parseRxProtoBuf(msg); + } else { + // This happens when connection is closed + ALOGD("%s: numBytes=%d, msgSize=%d", __func__, numBytes, + static_cast<int32_t>(msg.size())); + break; + } + } +} + +void DefaultVehicleHal::rxThread() { + bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false); + + if (isEmulator) { + // Initialize pipe to Emulator + mComm.reset(new PipeComm); + } else { + // Initialize socket over ADB + mComm.reset(new SocketComm); + } + + int retVal = mComm->open(); + + if (retVal == 0) { + // Comms are properly opened + while (mExit == 0) { + retVal = mComm->connect(); + + if (retVal >= 0) { + rxMsg(); + } + + // Check every 100ms for a new connection + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } +} + +// This function sets the default value of a property if we are interested in setting it. +// TODO: Co-locate the default values with the configuration structure, to make it easier to +// add new properties and their defaults. +void DefaultVehicleHal::setDefaultValue(VehiclePropValue* prop) { + switch (prop->prop) { + case toInt(VehicleProperty::INFO_MAKE): + prop->value.stringValue = "Default Car"; + break; + case toInt(VehicleProperty::PERF_VEHICLE_SPEED): + prop->value.floatValues[0] = 0; + break; + case toInt(VehicleProperty::CURRENT_GEAR): + prop->value.int32Values[0] = toInt(VehicleGear::GEAR_PARK); + break; + case toInt(VehicleProperty::PARKING_BRAKE_ON): + prop->value.int32Values[0] = 1; + break; + case toInt(VehicleProperty::FUEL_LEVEL_LOW): + prop->value.int32Values[0] = 0; + break; + case toInt(VehicleProperty::HVAC_POWER_ON): + prop->value.int32Values[0] = 1; + break; + case toInt(VehicleProperty::HVAC_DEFROSTER): + prop->value.int32Values[0] = 0; + break; + case toInt(VehicleProperty::HVAC_RECIRC_ON): + prop->value.int32Values[0] = 1; + break; + case toInt(VehicleProperty::HVAC_AC_ON): + prop->value.int32Values[0] = 1; + break; + case toInt(VehicleProperty::HVAC_AUTO_ON): + prop->value.int32Values[0] = 1; + break; + case toInt(VehicleProperty::HVAC_FAN_SPEED): + prop->value.int32Values[0] = 3; + break; + case toInt(VehicleProperty::HVAC_FAN_DIRECTION): + prop->value.int32Values[0] = toInt(VehicleHvacFanDirection::FACE); + break; + case toInt(VehicleProperty::HVAC_TEMPERATURE_SET): + prop->value.floatValues[0] = 16; + break; + case toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE): + prop->value.floatValues[0] = 25; + break; + case toInt(VehicleProperty::NIGHT_MODE): + prop->value.int32Values[0] = 0; + break; + case toInt(VehicleProperty::DRIVING_STATUS): + prop->value.int32Values[0] = toInt(VehicleDrivingStatus::UNRESTRICTED); + break; + case toInt(VehicleProperty::GEAR_SELECTION): + prop->value.int32Values[0] = toInt(VehicleGear::GEAR_PARK); + break; + case toInt(VehicleProperty::INFO_FUEL_CAPACITY): + prop->value.floatValues[0] = 123000.0f; // In milliliters + break; + case toInt(VehicleProperty::ENGINE_OIL_TEMP): + prop->value.floatValues[0] = 101; + break; + case toInt(VehicleProperty::DISPLAY_BRIGHTNESS): + prop->value.int32Values[0] = 7; + break; + case toInt(VehicleProperty::IGNITION_STATE): + prop->value.int32Values[0] = toInt(VehicleIgnitionState::ON); + break; + default: + ALOGW("%s: propId=0x%x not found", __func__, prop->prop); + break; + } +} + +// Transmit a reply back to the emulator +void DefaultVehicleHal::txMsg(emulator::EmulatorMessage& txMsg) { + int numBytes = txMsg.ByteSize(); + std::vector<uint8_t> msg(numBytes); + + if (txMsg.SerializeToArray(msg.data(), msg.size())) { + int retVal = 0; + + // Send the message + if (mExit == 0) { + mComm->write(msg); + } + + if (retVal < 0) { + ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno); + } + } else { + ALOGE("%s: SerializeToString failed!", __func__); + } +} + +// Updates the property value held in the HAL +StatusCode DefaultVehicleHal::updateProperty(const VehiclePropValue& propValue) { + auto propId = propValue.prop; + auto areaId = propValue.areaId; + StatusCode status = StatusCode::INVALID_ARG; + + { + std::lock_guard<std::mutex> lock(mPropsMutex); + + VehiclePropValue* internalPropValue = getVehiclePropValueLocked(propId, areaId); + if (internalPropValue != nullptr) { + internalPropValue->value = propValue.value; + internalPropValue->timestamp = propValue.timestamp; + status = StatusCode::OK; + } + } + return status; +} + +VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get( + const VehiclePropValue& requestedPropValue, StatusCode* outStatus) { + auto areaId = requestedPropValue.areaId; + auto& pool = *getValuePool(); + auto propId = requestedPropValue.prop; + StatusCode status; + VehiclePropValuePtr v = nullptr; + + switch (propId) { + default: + { + std::lock_guard<std::mutex> lock(mPropsMutex); + + VehiclePropValue *internalPropValue = getVehiclePropValueLocked(propId, areaId); + if (internalPropValue != nullptr) { + v = pool.obtain(*internalPropValue); + } + } + + if (v != nullptr) { + status = StatusCode::OK; + } else { + status = StatusCode::INVALID_ARG; + } + break; + } + + *outStatus = status; + return v; +} + +StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) { + auto propId = propValue.prop; + StatusCode status; + switch (propId) { + default: + if (mHvacPowerProps.find(VehicleProperty(propId)) != + mHvacPowerProps.end()) { + auto prop = mProps.find( + std::make_pair(toInt(VehicleProperty::HVAC_POWER_ON), 0)); + if (prop != mProps.end()) { + if (prop->second->value.int32Values.size() == 1 && + prop->second->value.int32Values[0] == 0) { + status = StatusCode::NOT_AVAILABLE; + break; + } + } + } + status = updateProperty(propValue); + if (status == StatusCode::OK) { + // Send property update to emulator + emulator::EmulatorMessage msg; + emulator::VehiclePropValue *val = msg.add_value(); + populateProtoVehiclePropValue(val, &propValue); + msg.set_status(emulator::RESULT_OK); + msg.set_msg_type(emulator::SET_PROPERTY_ASYNC); + txMsg(msg); + } + break; + } + + return status; +} + +// Parse supported properties list and generate vector of property values to hold current values. +void DefaultVehicleHal::onCreate() { + // Initialize member variables + mExit = 0; + + for (auto& prop : kHvacPowerProperties) { + mHvacPowerProps.insert(prop); + } + + // Get the list of configurations supported by this HAL + std::vector<VehiclePropConfig> configs = listProperties(); + + for (auto& cfg : configs) { + VehiclePropertyType propType = getPropType(cfg.prop); + int32_t supportedAreas = cfg.supportedAreas; + int32_t vecSize; + + // Set the vector size based on property type + switch (propType) { + case VehiclePropertyType::BOOLEAN: + case VehiclePropertyType::INT32: + case VehiclePropertyType::INT64: + case VehiclePropertyType::FLOAT: + vecSize = 1; + break; + case VehiclePropertyType::INT32_VEC: + case VehiclePropertyType::FLOAT_VEC: + case VehiclePropertyType::BYTES: + // TODO: Add proper support for these types + vecSize = 1; + break; + case VehiclePropertyType::STRING: + // Require individual handling + vecSize = 0; + break; + case VehiclePropertyType::COMPLEX: + switch (cfg.prop) { + default: + // Need to handle each complex property separately + break; + } + continue; + default: + ALOGE("%s: propType=0x%x not found", __func__, propType); + vecSize = 0; + break; + } + + // A global property will have supportedAreas = 0 + if (getPropArea(cfg.prop) == VehicleArea::GLOBAL) { + supportedAreas = 0; + } + + // This loop is a do-while so it executes at least once to handle global properties + do { + int32_t curArea = supportedAreas; + + // Clear the right-most bit of supportedAreas + supportedAreas &= supportedAreas - 1; + + // Set curArea to the previously cleared bit + curArea ^= supportedAreas; + + // Create a separate instance for each individual zone + std::unique_ptr<VehiclePropValue> prop = createVehiclePropValue(propType, vecSize); + prop->areaId = curArea; + prop->prop = cfg.prop; + setDefaultValue(prop.get()); + mProps[std::make_pair(prop->prop, prop->areaId)] = std::move(prop); + } while (supportedAreas != 0); + } + + // Start rx thread + mThread = std::thread(&DefaultVehicleHal::rxThread, this); +} + +void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) { + VehiclePropValuePtr v; + + auto& pool = *getValuePool(); + + for (int32_t property : properties) { + if (isContinuousProperty(property)) { + // In real implementation this value should be read from sensor, random + // value used for testing purpose only. + std::lock_guard<std::mutex> lock(mPropsMutex); + + VehiclePropValue *internalPropValue = getVehiclePropValueLocked(property); + if (internalPropValue != nullptr) { + v = pool.obtain(*internalPropValue); + } + if (VehiclePropertyType::FLOAT == getPropType(property)) { + // Just get some randomness to continuous properties to see slightly differnt values + // on the other end. + v->value.floatValues[0] = v->value.floatValues[0] + std::rand() % 5; + } + } else { + ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property); + } + + if (v.get()) { + v->timestamp = elapsedRealtimeNano(); + doHalEvent(std::move(v)); + } + } +} + +StatusCode DefaultVehicleHal::subscribe(int32_t property, int32_t, + float sampleRate) { + ALOGI("subscribe called for property: 0x%x, sampleRate: %f", property, sampleRate); + + if (isContinuousProperty(property)) { + mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property); + } + return StatusCode::OK; +} + +StatusCode DefaultVehicleHal::unsubscribe(int32_t property) { + ALOGI("%s propId: 0x%x", __func__, property); + if (isContinuousProperty(property)) { + mRecurrentTimer.unregisterRecurrentEvent(property); + } + return StatusCode::OK; +} + +const VehiclePropConfig* DefaultVehicleHal::getPropConfig(int32_t propId) const { + auto it = mPropConfigMap.find(propId); + return it == mPropConfigMap.end() ? nullptr : it->second; +} + +bool DefaultVehicleHal::isContinuousProperty(int32_t propId) const { + const VehiclePropConfig* config = getPropConfig(propId); + if (config == nullptr) { + ALOGW("Config not found for property: 0x%x", propId); + return false; + } + return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS; +} + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h new file mode 100644 index 0000000..98eef27 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
@@ -0,0 +1,128 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_ + +#include <map> +#include <memory> +#include <sys/socket.h> +#include <thread> +#include <unordered_set> + +#include <utils/SystemClock.h> + +#include "CommBase.h" +#include "VehicleHalProto.pb.h" + +#include <vhal_v2_0/RecurrentTimer.h> +#include <vhal_v2_0/VehicleHal.h> + +#include "DefaultConfig.h" +#include "VehicleHalProto.pb.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +class DefaultVehicleHal : public VehicleHal { +public: + DefaultVehicleHal() : mRecurrentTimer( + std::bind(&DefaultVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)) { + for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { + mPropConfigMap[kVehicleProperties->prop] = &kVehicleProperties[i]; + } + } + + ~DefaultVehicleHal() override { + // Notify thread to finish and wait for it to terminate + mExit = 1; + + // Close emulator socket if it is open + mComm->stop(); + + mThread.join(); + } + + std::vector<VehiclePropConfig> listProperties() override { + return std::vector<VehiclePropConfig>(std::begin(kVehicleProperties), + std::end(kVehicleProperties)); + } + + VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue, + StatusCode* outStatus) override; + + void onCreate() override; + + StatusCode set(const VehiclePropValue& propValue) override; + + StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override; + + StatusCode unsubscribe(int32_t property) override; + +private: + void doGetConfig(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg); + void doGetConfigAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg); + void doGetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg); + void doGetPropertyAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg); + void doSetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg); + VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId = 0); + const VehiclePropConfig* getPropConfig(int32_t propId) const; + bool isContinuousProperty(int32_t propId) const; + void parseRxProtoBuf(std::vector<uint8_t>& msg); + void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg, + const VehiclePropConfig& cfg); + void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal, + const VehiclePropValue* val); + void setDefaultValue(VehiclePropValue* prop); + void rxMsg(); + void rxThread(); + void txMsg(emulator::EmulatorMessage& txMsg); + StatusCode updateProperty(const VehiclePropValue& propValue); + + constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const { + return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz)); + } + + void onContinuousPropertyTimer(const std::vector<int32_t>& properties); + +private: + std::map< + std::pair<int32_t /*VehicleProperty*/, int32_t /*areaId*/>, + std::unique_ptr<VehiclePropValue>> mProps; + std::atomic<int> mExit; + std::unordered_set<VehicleProperty> mHvacPowerProps; + std::mutex mPropsMutex; + std::thread mThread; + std::unique_ptr<CommBase> mComm{nullptr}; + RecurrentTimer mRecurrentTimer; + std::unordered_map<int32_t, const VehiclePropConfig*> mPropConfigMap; +}; + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + +#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp new file mode 100644 index 0000000..6f219fa --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
@@ -0,0 +1,106 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "PipeComm" + +#include <android/hardware/automotive/vehicle/2.0/IVehicle.h> +#include <android/log.h> +#include <system/qemu_pipe.h> + +#include "PipeComm.h" + +#define CAR_SERVICE_NAME "pipe:qemud:car" + + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +PipeComm::PipeComm() { + // Initialize member vars + mPipeFd = -1; +} + + +int PipeComm::open() { + int fd = qemu_pipe_open(CAR_SERVICE_NAME); + + if (fd < 0) { + ALOGE("%s: Could not open connection to service: %s %d", __FUNCTION__, strerror(errno), fd); + return -errno; + } + + ALOGI("%s: OPENED PIPE, fd=%d", __FUNCTION__, fd); + mPipeFd = fd; + return 0; +} + +std::vector<uint8_t> PipeComm::read() { + static constexpr int MAX_RX_MSG_SZ = 2048; + std::vector<uint8_t> msg = std::vector<uint8_t>(MAX_RX_MSG_SZ); + int numBytes; + + numBytes = qemu_pipe_frame_recv(mPipeFd, msg.data(), msg.size()); + + if (numBytes == MAX_RX_MSG_SZ) { + ALOGE("%s: Received max size = %d", __FUNCTION__, MAX_RX_MSG_SZ); + } else if (numBytes > 0) { + msg.resize(numBytes); + return msg; + } else { + ALOGD("%s: Connection terminated on pipe %d, numBytes=%d", __FUNCTION__, mPipeFd, numBytes); + { + std::lock_guard<std::mutex> lock(mMutex); + mPipeFd = -1; + } + } + + return std::vector<uint8_t>(); +} + +int PipeComm::write(const std::vector<uint8_t>& data) { + int retVal = 0; + + { + std::lock_guard<std::mutex> lock(mMutex); + if (mPipeFd != -1) { + retVal = qemu_pipe_frame_send(mPipeFd, data.data(), data.size()); + } + } + + if (retVal < 0) { + retVal = -errno; + ALOGE("%s: send_cmd: (fd=%d): ERROR: %s", __FUNCTION__, mPipeFd, strerror(errno)); + } + + return retVal; +} + + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + +
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h new file mode 100644 index 0000000..bcd32d0 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h
@@ -0,0 +1,77 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_PipeComm_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_PipeComm_H_ + +#include <mutex> +#include <vector> +#include "CommBase.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +/** + * PipeComm uses a qemu pipe interface to connect to the Goldfish Emulator. + */ +class PipeComm : public CommBase { +public: + PipeComm(); + + /** + * Opens a pipe and begins listening. + * + * @return int Returns 0 on success. + */ + int open() override; + + /** + * Blocking call to read data from the connection. + * + * @return std::vector<uint8_t> Serialized protobuf data received from emulator. This will be + * an empty vector if the connection was closed or some other error occurred. + */ + std::vector<uint8_t> read() override; + + /** + * Transmits a string of data to the emulator. + * + * @param data Serialized protobuf data to transmit. + * + * @return int Number of bytes transmitted, or -1 if failed. + */ + int write(const std::vector<uint8_t>& data) override; + +private: + std::mutex mMutex; + int mPipeFd; +}; + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + +#endif // android_hardware_automotive_vehicle_V2_0_impl_PipeComm_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp new file mode 100644 index 0000000..a3ef4b1 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
@@ -0,0 +1,190 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "SocketComm" + +#include <android/hardware/automotive/vehicle/2.0/IVehicle.h> +#include <android/log.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#include "SocketComm.h" + +// Socket to use when communicating with Host PC +static constexpr int DEBUG_SOCKET = 33452; + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +SocketComm::SocketComm() { + // Initialize member vars + mCurSockFd = -1; + mExit = 0; + mSockFd = -1; +} + + +SocketComm::~SocketComm() { + stop(); +} + +int SocketComm::connect() { + sockaddr_in cliAddr; + socklen_t cliLen = sizeof(cliAddr); + int cSockFd = accept(mSockFd, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen); + + if (cSockFd >= 0) { + { + std::lock_guard<std::mutex> lock(mMutex); + mCurSockFd = cSockFd; + } + ALOGD("%s: Incoming connection received on socket %d", __FUNCTION__, cSockFd); + } else { + cSockFd = -1; + } + + return cSockFd; +} + +int SocketComm::open() { + int retVal; + struct sockaddr_in servAddr; + + mSockFd = socket(AF_INET, SOCK_STREAM, 0); + if (mSockFd < 0) { + ALOGE("%s: socket() failed, mSockFd=%d, errno=%d", __FUNCTION__, mSockFd, errno); + mSockFd = -1; + return -errno; + } + + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = INADDR_ANY; + servAddr.sin_port = htons(DEBUG_SOCKET); + + retVal = bind(mSockFd, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr)); + if(retVal < 0) { + ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno); + close(mSockFd); + mSockFd = -1; + return -errno; + } + + listen(mSockFd, 1); + + // Set the socket to be non-blocking so we can poll it continouously + fcntl(mSockFd, F_SETFL, O_NONBLOCK); + + return 0; +} + +std::vector<uint8_t> SocketComm::read() { + int32_t msgSize; + int numBytes = 0; + + // This is a variable length message. + // Read the number of bytes to rx over the socket + numBytes = ::read(mCurSockFd, &msgSize, sizeof(msgSize)); + msgSize = ntohl(msgSize); + + if (numBytes != sizeof(msgSize)) { + // This happens when connection is closed + ALOGD("%s: numBytes=%d, expected=4", __FUNCTION__, numBytes); + ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd); + { + std::lock_guard<std::mutex> lock(mMutex); + mCurSockFd = -1; + } + + return std::vector<uint8_t>(); + } + + std::vector<uint8_t> msg = std::vector<uint8_t>(msgSize); + + numBytes = ::read(mCurSockFd, msg.data(), msgSize); + + if ((numBytes == msgSize) && (msgSize > 0)) { + // Received a message. + return msg; + } else { + // This happens when connection is closed + ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes, msgSize); + ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd); + { + std::lock_guard<std::mutex> lock(mMutex); + mCurSockFd = -1; + } + + return std::vector<uint8_t>(); + } +} + +void SocketComm::stop() { + if (mExit == 0) { + std::lock_guard<std::mutex> lock(mMutex); + mExit = 1; + + // Close emulator socket if it is open + if (mCurSockFd != -1) { + close(mCurSockFd); + mCurSockFd = -1; + } + + if (mSockFd != -1) { + close(mSockFd); + mSockFd = -1; + } + } +} + +int SocketComm::write(const std::vector<uint8_t>& data) { + static constexpr int MSG_HEADER_LEN = 4; + int retVal = 0; + union { + uint32_t msgLen; + uint8_t msgLenBytes[MSG_HEADER_LEN]; + }; + + // Prepare header for the message + msgLen = static_cast<uint32_t>(data.size()); + msgLen = htonl(msgLen); + + std::lock_guard<std::mutex> lock(mMutex); + if (mCurSockFd != -1) { + retVal = ::write(mCurSockFd, msgLenBytes, MSG_HEADER_LEN); + + if (retVal == MSG_HEADER_LEN) { + retVal = ::write(mCurSockFd, data.data(), data.size()); + } + } + + return retVal; +} + + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android +
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h new file mode 100644 index 0000000..12cfb29 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
@@ -0,0 +1,94 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_ +#define android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_ + +#include <mutex> +#include <vector> +#include "CommBase.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +/** + * SocketComm opens a socket via adb's TCP port forwarding to enable a Host PC to connect to + * the VehicleHAL. + */ +class SocketComm : public CommBase { +public: + SocketComm(); + virtual ~SocketComm(); + + /** + * Creates a connection to the other side. + * + * @return int Returns fd or socket number if connection is successful. + * Otherwise, returns -1 if no connection is availble. + */ + int connect() override; + + /** + * Opens a socket and begins listening. + * + * @return int Returns 0 on success. + */ + int open() override; + + /** + * Blocking call to read data from the connection. + * + * @return std::vector<uint8_t> Serialized protobuf data received from emulator. This will be + * an empty vector if the connection was closed or some other error occurred. + */ + std::vector<uint8_t> read() override; + + /** + * Closes a connection if it is open. + */ + void stop() override; + + /** + * Transmits a string of data to the emulator. + * + * @param data Serialized protobuf data to transmit. + * + * @return int Number of bytes transmitted, or -1 if failed. + */ + int write(const std::vector<uint8_t>& data) override; + +private: + int mCurSockFd; + std::atomic<int> mExit; + std::mutex mMutex; + int mSockFd; +}; + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + +#endif // android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto new file mode 100644 index 0000000..86433f5 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -0,0 +1,100 @@ +/* + * Copyright (C) 2015 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"; +option optimize_for = LITE_RUNTIME; + +package emulator; + +// CMD messages are from workstation --> VHAL +// RESP messages are from VHAL --> workstation +enum MsgType { + GET_CONFIG_CMD = 0; + GET_CONFIG_RESP = 1; + GET_CONFIG_ALL_CMD = 2; + GET_CONFIG_ALL_RESP = 3; + GET_PROPERTY_CMD = 4; + GET_PROPERTY_RESP = 5; + GET_PROPERTY_ALL_CMD = 6; + GET_PROPERTY_ALL_RESP = 7; + SET_PROPERTY_CMD = 8; + SET_PROPERTY_RESP = 9; + SET_PROPERTY_ASYNC = 10; +} +enum Status { + RESULT_OK = 0; + ERROR_UNKNOWN = 1; + ERROR_UNIMPLEMENTED_CMD = 2; + ERROR_INVALID_PROPERTY = 3; + ERROR_INVALID_AREA_ID = 4; + ERROR_PROPERTY_UNINITIALIZED = 5; + ERROR_WRITE_ONLY_PROPERTY = 6; + ERROR_MEMORY_ALLOC_FAILED = 7; + ERROR_INVALID_OPERATION = 8; +} + +message VehicleAreaConfig { + required int32 area_id = 1; + optional sint32 min_int32_value = 2; + optional sint32 max_int32_value = 3; + optional sint64 min_int64_value = 4; + optional sint64 max_int64_value = 5; + optional float min_float_value = 6; + optional float max_float_value = 7; +} + +message VehiclePropConfig { + required int32 prop = 1; + optional int32 access = 2; + optional int32 change_mode = 3; + optional int32 value_type = 4; + optional int32 supported_areas = 5; + repeated VehicleAreaConfig area_configs = 6; + optional int32 config_flags = 7; + repeated int32 config_array = 8; + optional string config_string = 9; + optional float min_sample_rate = 10; + optional float max_sample_rate = 11; +}; + +message VehiclePropValue { + // common data + required int32 prop = 1; + optional int32 value_type = 2; + optional int64 timestamp = 3; // required for valid data from HAL, skipped for set + + // values + optional int32 area_id = 4; + repeated sint32 int32_values = 5; // this also covers boolean value. + repeated sint64 int64_values = 6; + repeated float float_values = 7; + optional string string_value = 8; + optional bytes bytes_value = 9; +}; + +// This structure is used to notify what values to get from the Vehicle HAL +message VehiclePropGet { + required int32 prop = 1; + optional int32 area_id = 2; +}; + +message EmulatorMessage { + required MsgType msg_type = 1; + optional Status status = 2; // Only for RESP messages + repeated VehiclePropGet prop = 3; // Provided for getConfig, getProperty commands + repeated VehiclePropConfig config = 4; + repeated VehiclePropValue value = 5; +};
diff --git a/automotive/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp b/automotive/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp new file mode 100644 index 0000000..d9611c0 --- /dev/null +++ b/automotive/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp
@@ -0,0 +1,152 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <gtest/gtest.h> +#include <memory> +#include <fstream> +#include <unordered_set> + +#include "vhal_v2_0/AccessControlConfigParser.h" +#include "vhal_v2_0/VehicleUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace { + +class AccessControlConfigParserTest : public ::testing::Test { +protected: + void SetUp() override { + std::vector<int32_t> supportedProperties { + toInt(VehicleProperty::HVAC_FAN_SPEED), + toInt(VehicleProperty::HVAC_FAN_DIRECTION), + }; + parser.reset(new AccessControlConfigParser(supportedProperties)); + } +public: + PropertyAclMap aclMap; + std::unique_ptr<AccessControlConfigParser> parser; +}; + +TEST_F(AccessControlConfigParserTest, basicParsing) { + std::stringstream file; + file << "S:0x0500 1000 RW" << std::endl; + + ASSERT_TRUE(parser->parseFromStream(&file, &aclMap)); + + ASSERT_EQ(1u, aclMap.size()); + auto it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_SPEED)); + ASSERT_NE(aclMap.end(), it); + ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access); + ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_SPEED), it->second.propId); + ASSERT_EQ(1000u, it->second.uid); +} + +TEST_F(AccessControlConfigParserTest, multipleUids) { + std::stringstream file; + file << "Set AID_AUDIO 1004" << std::endl + << "Set AID_SYSTEM 1000" << std::endl + << "S:0x0500 AID_SYSTEM RW" << std::endl + << "S:0x0500 AID_AUDIO RW" << std::endl + << "S:0x0500 0xbeef R" << std::endl; // Read-only. + + std::unordered_set<unsigned> expectedUids {1000, 1004, 0xbeef}; + + ASSERT_TRUE(parser->parseFromStream(&file, &aclMap)); + + auto range = aclMap.equal_range(toInt(VehicleProperty::HVAC_FAN_SPEED)); + for (auto it = range.first; it != range.second; ++it) { + auto& acl = it->second; + + ASSERT_EQ(1u, expectedUids.count(acl.uid)) + << " uid: " << std::hex << acl.uid; + + if (acl.uid == 0xbeef) { + ASSERT_EQ(VehiclePropertyAccess::READ, acl.access); + } else { + ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, acl.access); + } + } +} + +TEST_F(AccessControlConfigParserTest, fileContainsJunk) { + std::stringstream file; + file << "This string will be ignored with warning in the log" << std::endl + << "# However comments are quit legitimate" << std::endl + << "S:0x0500 0xbeef R # YAY" << std::endl; + + ASSERT_FALSE(parser->parseFromStream(&file, &aclMap)); + + ASSERT_EQ(1u, aclMap.size()); + auto it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_SPEED)); + ASSERT_NE(aclMap.end(), it); + ASSERT_EQ(VehiclePropertyAccess::READ, it->second.access); + ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_SPEED), it->second.propId); + ASSERT_EQ(0xBEEFu, it->second.uid); +} + +TEST_F(AccessControlConfigParserTest, badIntegerFormat) { + std::stringstream file; + file << "S:0x0500 A12 RW " << std::endl; + + ASSERT_FALSE(parser->parseFromStream(&file, &aclMap)); + ASSERT_EQ(0u, aclMap.size()); +} + +TEST_F(AccessControlConfigParserTest, ignoreNotSupportedProperties) { + std::stringstream file; + file << "S:0x0666 1000 RW " << std::endl; + + ASSERT_FALSE(parser->parseFromStream(&file, &aclMap)); + ASSERT_EQ(0u, aclMap.size()); +} + +TEST_F(AccessControlConfigParserTest, multipleCalls) { + std::stringstream configFile; + configFile << "S:0x0500 1000 RW" << std::endl; + + ASSERT_TRUE(parser->parseFromStream(&configFile, &aclMap)); + ASSERT_EQ(1u, aclMap.size()); + + std::stringstream configFile2; + configFile2 << "S:0x0501 1004 RW" << std::endl; + ASSERT_TRUE(parser->parseFromStream(&configFile2, &aclMap)); + ASSERT_EQ(2u, aclMap.size()); + + auto it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_SPEED)); + ASSERT_NE(aclMap.end(), it); + ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access); + ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_SPEED), it->second.propId); + ASSERT_EQ(1000u, it->second.uid); + + it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_DIRECTION)); + ASSERT_NE(aclMap.end(), it); + ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access); + ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_DIRECTION), it->second.propId); + ASSERT_EQ(1004u, it->second.uid); +} + + +} // namespace anonymous + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp new file mode 100644 index 0000000..9fc17c6 --- /dev/null +++ b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp
@@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <thread> + +#include <gtest/gtest.h> + +#include "vhal_v2_0/RecurrentTimer.h" + +namespace { + +using std::chrono::nanoseconds; +using std::chrono::milliseconds; + +#define ASSERT_EQ_WITH_TOLERANCE(val1, val2, tolerance) \ +ASSERT_LE(val1 - tolerance, val2); \ +ASSERT_GE(val1 + tolerance, val2); \ + + +TEST(RecurrentTimerTest, oneInterval) { + std::atomic<int64_t> counter { 0L }; + auto counterRef = std::ref(counter); + RecurrentTimer timer([&counterRef](const std::vector<int32_t>& cookies) { + ASSERT_EQ(1u, cookies.size()); + ASSERT_EQ(0xdead, cookies.front()); + counterRef.get()++; + }); + + timer.registerRecurrentEvent(milliseconds(1), 0xdead); + std::this_thread::sleep_for(milliseconds(100)); + ASSERT_EQ_WITH_TOLERANCE(100, counter.load(), 20); +} + +TEST(RecurrentTimerTest, multipleIntervals) { + std::atomic<int64_t> counter1ms { 0L }; + std::atomic<int64_t> counter5ms { 0L }; + auto counter1msRef = std::ref(counter1ms); + auto counter5msRef = std::ref(counter5ms); + RecurrentTimer timer( + [&counter1msRef, &counter5msRef](const std::vector<int32_t>& cookies) { + for (int32_t cookie : cookies) { + if (cookie == 0xdead) { + counter1msRef.get()++; + } else if (cookie == 0xbeef) { + counter5msRef.get()++; + } else { + FAIL(); + } + } + }); + + timer.registerRecurrentEvent(milliseconds(1), 0xdead); + timer.registerRecurrentEvent(milliseconds(5), 0xbeef); + + std::this_thread::sleep_for(milliseconds(100)); + ASSERT_EQ_WITH_TOLERANCE(100, counter1ms.load(), 20); + ASSERT_EQ_WITH_TOLERANCE(20, counter5ms.load(), 5); +} + +} // anonymous namespace
diff --git a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp new file mode 100644 index 0000000..7ec9b79 --- /dev/null +++ b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
@@ -0,0 +1,232 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <functional> +#include <iostream> +#include <unordered_map> + +#include <gtest/gtest.h> + +#include "vhal_v2_0/SubscriptionManager.h" + +#include "VehicleHalTestUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace { + +using namespace std::placeholders; + +class SubscriptionManagerTest : public ::testing::Test { +public: + SubscriptionManagerTest() : manager(([this](int x) { onPropertyUnsubscribed(x); })) {} + + SubscriptionManager manager; + static constexpr int32_t PROP1 = toInt(VehicleProperty::HVAC_FAN_SPEED); + static constexpr int32_t PROP2 = toInt(VehicleProperty::DISPLAY_BRIGHTNESS); + + sp<IVehicleCallback> cb1 = new MockedVehicleCallback(); + sp<IVehicleCallback> cb2 = new MockedVehicleCallback(); + sp<IVehicleCallback> cb3 = new MockedVehicleCallback(); + + void SetUp() override { + lastUnsubscribedProperty = -1; + } + + hidl_vec<SubscribeOptions> subscrToProp1 = { + SubscribeOptions { + .propId = PROP1, + .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT), + .flags = SubscribeFlags::HAL_EVENT + }, + }; + + hidl_vec<SubscribeOptions> subscrToProp2 = { + SubscribeOptions { + .propId = PROP2, + .flags = SubscribeFlags::HAL_EVENT + }, + }; + + hidl_vec<SubscribeOptions> subscrToProp1and2 = { + SubscribeOptions { + .propId = PROP1, + .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT), + .flags = SubscribeFlags::HAL_EVENT + }, + SubscribeOptions { + .propId = PROP2, + .flags = SubscribeFlags::HAL_EVENT + }, + }; + + static std::list<sp<IVehicleCallback>> extractCallbacks( + const std::list<sp<HalClient>>& clients) { + std::list<sp<IVehicleCallback>> callbacks; + for (auto c : clients) { + callbacks.push_back(c->getCallback()); + } + return callbacks; + } + + std::list<sp<HalClient>> clientsToProp1() { + return manager.getSubscribedClients(PROP1, + toInt(VehicleAreaZone::ROW_1_LEFT), + SubscribeFlags::DEFAULT); + } + + std::list<sp<HalClient>> clientsToProp2() { + return manager.getSubscribedClients(PROP2, 0, + SubscribeFlags::DEFAULT); + } + + void onPropertyUnsubscribed(int propertyId) { + // Called when there are no clients who subscribed to particular property. This can happen + // because of explict unsubscribe call or when client (IVehicleCallback) was disconnected. + lastUnsubscribedProperty = propertyId; + } + + void assertOnPropertyUnsubscribedNotCalled() { + ASSERT_EQ(-1, lastUnsubscribedProperty); + } + + void assertLastUnsubscribedProperty(int expectedPropertyId) { + ASSERT_EQ(expectedPropertyId, lastUnsubscribedProperty); + lastUnsubscribedProperty = -1; + } + +private: + int lastUnsubscribedProperty; +}; + + +TEST_F(SubscriptionManagerTest, multipleClients) { + std::list<SubscribeOptions> updatedOptions; + ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions)); + ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp1, &updatedOptions)); + + auto clients = manager.getSubscribedClients( + PROP1, + toInt(VehicleAreaZone::ROW_1_LEFT), + SubscribeFlags::HAL_EVENT); + + ASSERT_ALL_EXISTS({cb1, cb2}, extractCallbacks(clients)); +} + +TEST_F(SubscriptionManagerTest, negativeCases) { + std::list<SubscribeOptions> updatedOptions; + ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions)); + + // Wrong zone + auto clients = manager.getSubscribedClients( + PROP1, + toInt(VehicleAreaZone::ROW_2_LEFT), + SubscribeFlags::HAL_EVENT); + ASSERT_TRUE(clients.empty()); + + // Wrong prop + clients = manager.getSubscribedClients( + toInt(VehicleProperty::AP_POWER_BOOTUP_REASON), + toInt(VehicleAreaZone::ROW_1_LEFT), + SubscribeFlags::HAL_EVENT); + ASSERT_TRUE(clients.empty()); + + // Wrong flag + clients = manager.getSubscribedClients( + PROP1, + toInt(VehicleAreaZone::ROW_1_LEFT), + SubscribeFlags::SET_CALL); + ASSERT_TRUE(clients.empty()); +} + +TEST_F(SubscriptionManagerTest, mulipleSubscriptions) { + std::list<SubscribeOptions> updatedOptions; + ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions)); + + auto clients = manager.getSubscribedClients( + PROP1, + toInt(VehicleAreaZone::ROW_1_LEFT), + SubscribeFlags::DEFAULT); + ASSERT_EQ((size_t) 1, clients.size()); + ASSERT_EQ(cb1, clients.front()->getCallback()); + + // Same property, but different zone, to make sure we didn't unsubscribe + // from previous zone. + ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, { + SubscribeOptions { + .propId = PROP1, + .vehicleAreas = toInt(VehicleAreaZone::ROW_2), + .flags = SubscribeFlags::DEFAULT + } + }, &updatedOptions)); + + clients = manager.getSubscribedClients(PROP1, + toInt(VehicleAreaZone::ROW_1_LEFT), + SubscribeFlags::DEFAULT); + ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients)); + + clients = manager.getSubscribedClients(PROP1, + toInt(VehicleAreaZone::ROW_2), + SubscribeFlags::DEFAULT); + ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients)); +} + +TEST_F(SubscriptionManagerTest, unsubscribe) { + std::list<SubscribeOptions> updatedOptions; + ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions)); + ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp2, &updatedOptions)); + ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb3, subscrToProp1and2, + &updatedOptions)); + + ASSERT_ALL_EXISTS({cb1, cb3}, extractCallbacks(clientsToProp1())); + ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2())); + + manager.unsubscribe(cb1, PROP1); + assertOnPropertyUnsubscribedNotCalled(); + ASSERT_ALL_EXISTS({cb3}, extractCallbacks(clientsToProp1())); + + // Make sure nothing changed in PROP2 so far. + ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2())); + + // No one subscribed to PROP1, subscription for PROP2 is not affected. + manager.unsubscribe(cb3, PROP1); + assertLastUnsubscribedProperty(PROP1); + ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2())); + + manager.unsubscribe(cb3, PROP2); + assertOnPropertyUnsubscribedNotCalled(); + ASSERT_ALL_EXISTS({cb2}, extractCallbacks(clientsToProp2())); + + // The last client unsubscribed from this property. + manager.unsubscribe(cb2, PROP2); + assertLastUnsubscribedProperty(PROP2); + + // No one subscribed anymore + manager.unsubscribe(cb1, PROP1); + assertLastUnsubscribedProperty(PROP1); +} + +} // namespace anonymous + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp new file mode 100644 index 0000000..b5cdf5c --- /dev/null +++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
@@ -0,0 +1,478 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <unordered_map> +#include <iostream> + +#include <utils/SystemClock.h> + +#include <gtest/gtest.h> + +#include "vhal_v2_0/VehicleHalManager.h" + +#include "VehicleHalTestUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace { + +using namespace std::placeholders; + +constexpr char kCarMake[] = "Default Car"; +constexpr int kRetriablePropMockedAttempts = 3; + +class MockedVehicleHal : public VehicleHal { +public: + MockedVehicleHal() { + mConfigs.assign(std::begin(kVehicleProperties), + std::end(kVehicleProperties)); + } + + std::vector<VehiclePropConfig> listProperties() override { + return mConfigs; + } + + VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue, + StatusCode* outStatus) override { + *outStatus = StatusCode::OK; + VehiclePropValuePtr pValue; + auto property = static_cast<VehicleProperty>(requestedPropValue.prop); + int32_t areaId = requestedPropValue.areaId; + + switch (property) { + case VehicleProperty::INFO_MAKE: + pValue = getValuePool()->obtainString(kCarMake); + break; + case VehicleProperty::INFO_FUEL_CAPACITY: + if (fuelCapacityAttemptsLeft-- > 0) { + // Emulate property not ready yet. + *outStatus = StatusCode::TRY_AGAIN; + } else { + pValue = getValuePool()->obtainFloat(42.42); + } + break; + default: + if (requestedPropValue.prop == kCustomComplexProperty) { + pValue = getValuePool()->obtainComplex(); + pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 }; + pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 }; + pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 }; + pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 }; + pValue->value.stringValue = kCarMake; + break; + } + auto key = makeKey(toInt(property), areaId); + if (mValues.count(key) == 0) { + ALOGW(""); + } + pValue = getValuePool()->obtain(mValues[key]); + } + + if (*outStatus == StatusCode::OK && pValue.get() != nullptr) { + pValue->prop = toInt(property); + pValue->areaId = areaId; + pValue->timestamp = elapsedRealtimeNano(); + } + + return pValue; + } + + StatusCode set(const VehiclePropValue& propValue) override { + if (toInt(VehicleProperty::MIRROR_FOLD) == propValue.prop + && mirrorFoldAttemptsLeft-- > 0) { + return StatusCode::TRY_AGAIN; + } + + mValues[makeKey(propValue)] = propValue; + return StatusCode::OK; + } + + StatusCode subscribe(int32_t /* property */, + int32_t /* areas */, + float /* sampleRate */) override { + return StatusCode::OK; + } + + StatusCode unsubscribe(int32_t /* property */) override { + return StatusCode::OK; + } + + void sendPropEvent(recyclable_ptr<VehiclePropValue> value) { + doHalEvent(std::move(value)); + } + + void sendHalError(StatusCode error, int32_t property, int32_t areaId) { + doHalPropertySetError(error, property, areaId); + } + +public: + int fuelCapacityAttemptsLeft = kRetriablePropMockedAttempts; + int mirrorFoldAttemptsLeft = kRetriablePropMockedAttempts; + +private: + int64_t makeKey(const VehiclePropValue& v) const { + return makeKey(v.prop, v.areaId); + } + + int64_t makeKey(int32_t prop, int32_t area) const { + return (static_cast<int64_t>(prop) << 32) | area; + } + +private: + std::vector<VehiclePropConfig> mConfigs; + std::unordered_map<int64_t, VehiclePropValue> mValues; +}; + +class VehicleHalManagerTest : public ::testing::Test { +protected: + void SetUp() override { + hal.reset(new MockedVehicleHal); + manager.reset(new VehicleHalManager(hal.get())); + + objectPool = hal->getValuePool(); + } + + void TearDown() override { + manager.reset(nullptr); + hal.reset(nullptr); + } +public: + void invokeGet(int32_t property, int32_t areaId) { + VehiclePropValue requestedValue {}; + requestedValue.prop = property; + requestedValue.areaId = areaId; + + invokeGet(requestedValue); + } + + void invokeGet(const VehiclePropValue& requestedPropValue) { + actualValue = VehiclePropValue {}; // reset previous values + + StatusCode refStatus; + VehiclePropValue refValue; + bool called = false; + manager->get(requestedPropValue, [&refStatus, &refValue, &called] + (StatusCode status, const VehiclePropValue& value) { + refStatus = status; + refValue = value; + called = true; + }); + ASSERT_TRUE(called) << "callback wasn't called for prop: " + << hexString(requestedPropValue.prop); + + actualValue = refValue; + actualStatusCode = refStatus; + } + +public: + VehiclePropValue actualValue; + StatusCode actualStatusCode; + + VehiclePropValuePool* objectPool; + std::unique_ptr<MockedVehicleHal> hal; + std::unique_ptr<VehicleHalManager> manager; +}; + +TEST_F(VehicleHalManagerTest, getPropConfigs) { + hidl_vec<int32_t> properties = + { toInt(VehicleProperty::HVAC_FAN_SPEED), + toInt(VehicleProperty::INFO_MAKE) }; + bool called = false; + + manager->getPropConfigs(properties, + [&called] (StatusCode status, + const hidl_vec<VehiclePropConfig>& c) { + ASSERT_EQ(StatusCode::OK, status); + ASSERT_EQ(2u, c.size()); + called = true; + }); + + ASSERT_TRUE(called); // Verify callback received. + + called = false; + manager->getPropConfigs({ toInt(VehicleProperty::HVAC_FAN_SPEED) }, + [&called] (StatusCode status, + const hidl_vec<VehiclePropConfig>& c) { + ASSERT_EQ(StatusCode::OK, status); + ASSERT_EQ(1u, c.size()); + ASSERT_EQ(toString(kVehicleProperties[1]), toString(c[0])); + called = true; + }); + ASSERT_TRUE(called); // Verify callback received. + + // TODO(pavelm): add case case when property was not declared. +} + +TEST_F(VehicleHalManagerTest, getAllPropConfigs) { + bool called = false; + manager->getAllPropConfigs( + [&called] (const hidl_vec<VehiclePropConfig>& propConfigs) { + ASSERT_EQ(arraysize(kVehicleProperties), propConfigs.size()); + + for (size_t i = 0; i < propConfigs.size(); i++) { + ASSERT_EQ(toString(kVehicleProperties[i]), + toString(propConfigs[i])); + } + called = true; + }); + ASSERT_TRUE(called); // Verify callback received. +} + +TEST_F(VehicleHalManagerTest, halErrorEvent) { + const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS); + + sp<MockedVehicleCallback> cb = new MockedVehicleCallback(); + + hidl_vec<SubscribeOptions> options = { + SubscribeOptions { + .propId = PROP, + .flags = SubscribeFlags::DEFAULT + }, + }; + + StatusCode res = manager->subscribe(cb, options); + ASSERT_EQ(StatusCode::OK, res); + + hal->sendHalError(StatusCode::TRY_AGAIN, PROP, 0 /* area id*/); +} + +TEST_F(VehicleHalManagerTest, subscribe) { + const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS); + + sp<MockedVehicleCallback> cb = new MockedVehicleCallback(); + + hidl_vec<SubscribeOptions> options = { + SubscribeOptions { + .propId = PROP, + .flags = SubscribeFlags::DEFAULT + } + }; + + StatusCode res = manager->subscribe(cb, options); + ASSERT_EQ(StatusCode::OK, res); + + auto unsubscribedValue = objectPool->obtain(VehiclePropertyType::INT32); + unsubscribedValue->prop = toInt(VehicleProperty::HVAC_FAN_SPEED); + + hal->sendPropEvent(std::move(unsubscribedValue)); + auto& receivedEnvents = cb->getReceivedEvents(); + + ASSERT_TRUE(cb->waitForExpectedEvents(0)) << " Unexpected events received: " + << receivedEnvents.size() + << (receivedEnvents.size() > 0 + ? toString(receivedEnvents.front()[0]) : ""); + + auto subscribedValue = objectPool->obtain(VehiclePropertyType::INT32); + subscribedValue->prop = PROP; + subscribedValue->value.int32Values[0] = 42; + + cb->reset(); + VehiclePropValue actualValue(*subscribedValue.get()); + hal->sendPropEvent(std::move(subscribedValue)); + + ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: " + << receivedEnvents.size(); + + ASSERT_EQ(toString(actualValue), + toString(cb->getReceivedEvents().front()[0])); +} + +TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) { + const auto PROP = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE); + + sp<MockedVehicleCallback> cb = new MockedVehicleCallback(); + + hidl_vec<SubscribeOptions> options = { + SubscribeOptions { + .propId = PROP, + .flags = SubscribeFlags::HAL_EVENT + }, + }; + + StatusCode res = manager->subscribe(cb, options); + // Unable to subscribe on Hal Events for write-only properties. + ASSERT_EQ(StatusCode::INVALID_ARG, res); + + + options[0].flags = SubscribeFlags::SET_CALL; + + res = manager->subscribe(cb, options); + // OK to subscribe on SET method call for write-only properties. + ASSERT_EQ(StatusCode::OK, res); +} + +TEST_F(VehicleHalManagerTest, get_Complex) { + invokeGet(kCustomComplexProperty, 0); + + ASSERT_EQ(StatusCode::OK, actualStatusCode); + ASSERT_EQ(kCustomComplexProperty, actualValue.prop); + + ASSERT_EQ(3u, actualValue.value.bytes.size()); + ASSERT_EQ(1, actualValue.value.bytes[0]); + ASSERT_EQ(2, actualValue.value.bytes[1]); + ASSERT_EQ(3, actualValue.value.bytes[2]); + + ASSERT_EQ(2u, actualValue.value.int32Values.size()); + ASSERT_EQ(10, actualValue.value.int32Values[0]); + ASSERT_EQ(20, actualValue.value.int32Values[1]); + + ASSERT_EQ(2u, actualValue.value.floatValues.size()); + ASSERT_FLOAT_EQ(1.1, actualValue.value.floatValues[0]); + ASSERT_FLOAT_EQ(2.2, actualValue.value.floatValues[1]); + + ASSERT_EQ(2u, actualValue.value.int64Values.size()); + ASSERT_FLOAT_EQ(30, actualValue.value.int64Values[0]); + ASSERT_FLOAT_EQ(40, actualValue.value.int64Values[1]); + + ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str()); +} + +TEST_F(VehicleHalManagerTest, get_StaticString) { + invokeGet(toInt(VehicleProperty::INFO_MAKE), 0); + + ASSERT_EQ(StatusCode::OK, actualStatusCode); + ASSERT_EQ(toInt(VehicleProperty::INFO_MAKE), actualValue.prop); + ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str()); +} + +TEST_F(VehicleHalManagerTest, get_NegativeCases) { + // Write-only property must fail. + invokeGet(toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE), 0); + ASSERT_EQ(StatusCode::ACCESS_DENIED, actualStatusCode); + + // Unknown property must fail. + invokeGet(toInt(VehicleProperty::MIRROR_Z_MOVE), 0); + ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode); +} + +TEST_F(VehicleHalManagerTest, get_Retriable) { + actualStatusCode = StatusCode::TRY_AGAIN; + int attempts = 0; + while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) { + invokeGet(toInt(VehicleProperty::INFO_FUEL_CAPACITY), 0); + + } + ASSERT_EQ(StatusCode::OK, actualStatusCode); + ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts); + ASSERT_FLOAT_EQ(42.42, actualValue.value.floatValues[0]); +} + +TEST_F(VehicleHalManagerTest, set_Basic) { + const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS); + const auto VAL = 7; + + auto expectedValue = hal->getValuePool()->obtainInt32(VAL); + expectedValue->prop = PROP; + expectedValue->areaId = 0; + + actualStatusCode = manager->set(*expectedValue.get()); + ASSERT_EQ(StatusCode::OK, actualStatusCode); + + invokeGet(PROP, 0); + ASSERT_EQ(StatusCode::OK, actualStatusCode); + ASSERT_EQ(PROP, actualValue.prop); + ASSERT_EQ(VAL, actualValue.value.int32Values[0]); +} + +TEST_F(VehicleHalManagerTest, set_DifferentAreas) { + const auto PROP = toInt(VehicleProperty::HVAC_FAN_SPEED); + const auto VAL1 = 1; + const auto VAL2 = 2; + const auto AREA1 = toInt(VehicleAreaZone::ROW_1_LEFT); + const auto AREA2 = toInt(VehicleAreaZone::ROW_1_RIGHT); + + { + auto expectedValue1 = hal->getValuePool()->obtainInt32(VAL1); + expectedValue1->prop = PROP; + expectedValue1->areaId = AREA1; + actualStatusCode = manager->set(*expectedValue1.get()); + ASSERT_EQ(StatusCode::OK, actualStatusCode); + + auto expectedValue2 = hal->getValuePool()->obtainInt32(VAL2); + expectedValue2->prop = PROP; + expectedValue2->areaId = AREA2; + actualStatusCode = manager->set(*expectedValue2.get()); + ASSERT_EQ(StatusCode::OK, actualStatusCode); + } + + { + invokeGet(PROP, AREA1); + ASSERT_EQ(StatusCode::OK, actualStatusCode); + ASSERT_EQ(PROP, actualValue.prop); + ASSERT_EQ(AREA1, actualValue.areaId); + ASSERT_EQ(VAL1, actualValue.value.int32Values[0]); + + invokeGet(PROP, AREA2); + ASSERT_EQ(StatusCode::OK, actualStatusCode); + ASSERT_EQ(PROP, actualValue.prop); + ASSERT_EQ(AREA2, actualValue.areaId); + ASSERT_EQ(VAL2, actualValue.value.int32Values[0]); + } +} + +TEST_F(VehicleHalManagerTest, set_Retriable) { + const auto PROP = toInt(VehicleProperty::MIRROR_FOLD); + + auto v = hal->getValuePool()->obtainBoolean(true); + v->prop = PROP; + v->areaId = 0; + + actualStatusCode = StatusCode::TRY_AGAIN; + int attempts = 0; + while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) { + actualStatusCode = manager->set(*v.get()); + } + + ASSERT_EQ(StatusCode::OK, actualStatusCode); + ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts); + + invokeGet(PROP, 0); + ASSERT_EQ(StatusCode::OK, actualStatusCode); + ASSERT_TRUE(actualValue.value.int32Values[0]); +} + +TEST(HalClientVectorTest, basic) { + HalClientVector clients; + sp<IVehicleCallback> callback1 = new MockedVehicleCallback(); + + sp<HalClient> c1 = new HalClient(callback1, 10, 20); + sp<HalClient> c2 = new HalClient(callback1, 10, 20); + + clients.addOrUpdate(c1); + clients.addOrUpdate(c1); + clients.addOrUpdate(c2); + ASSERT_EQ(2u, clients.size()); + ASSERT_FALSE(clients.isEmpty()); + ASSERT_LE(0, clients.indexOf(c1)); + ASSERT_LE(0, clients.remove(c1)); + ASSERT_GT(0, clients.indexOf(c1)); // c1 was already removed + ASSERT_GT(0, clients.remove(c1)); // attempt to remove c1 again + ASSERT_LE(0, clients.remove(c2)); + + ASSERT_TRUE(clients.isEmpty()); +} + +} // namespace anonymous + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h new file mode 100644 index 0000000..28e1a5a --- /dev/null +++ b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
@@ -0,0 +1,280 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_0_VehicleDebugUtils_H_ +#define android_hardware_automotive_vehicle_V2_0_VehicleDebugUtils_H_ + +#include <android/hardware/automotive/vehicle/2.0/types.h> +#include <ios> +#include <sstream> + +#include "vhal_v2_0/VehicleUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +constexpr int32_t kCustomComplexProperty = 0xbeef + | VehiclePropertyGroup::VENDOR + | VehiclePropertyType::COMPLEX + | VehicleArea::GLOBAL; + +const VehiclePropConfig kVehicleProperties[] = { + { + .prop = toInt(VehicleProperty::INFO_MAKE), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::STATIC, + .configString = "Some=config,options=if,you=have_any", + }, + + { + .prop = toInt(VehicleProperty::HVAC_FAN_SPEED), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .supportedAreas = static_cast<int32_t>( + VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT), + .areaConfigs = { + VehicleAreaConfig { + .areaId = toInt(VehicleAreaZone::ROW_1_LEFT), + .minInt32Value = 1, + .maxInt32Value = 7}, + VehicleAreaConfig { + .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT), + .minInt32Value = 1, + .maxInt32Value = 5, + } + } + }, + + // Write-only property + { + .prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE), + .access = VehiclePropertyAccess::WRITE, + .changeMode = VehiclePropertyChangeMode::ON_SET, + .supportedAreas = static_cast<int32_t>( + VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT), + .areaConfigs = { + VehicleAreaConfig { + .areaId = toInt(VehicleAreaZone::ROW_1_LEFT), + .minInt32Value = 64, + .maxInt32Value = 80}, + VehicleAreaConfig { + .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT), + .minInt32Value = 64, + .maxInt32Value = 80, + } + } + }, + + { + .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY), + .access = VehiclePropertyAccess::READ, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = { + VehicleAreaConfig { + .minFloatValue = 0, + .maxFloatValue = 1.0 + } + } + }, + + { + .prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + .areaConfigs = { + VehicleAreaConfig { + .minInt32Value = 0, + .maxInt32Value = 10 + } + } + }, + + { + .prop = toInt(VehicleProperty::MIRROR_FOLD), + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + + }, + + // Complex data type. + { + .prop = kCustomComplexProperty, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE + } +}; + +constexpr auto kTimeout = std::chrono::milliseconds(500); + +class MockedVehicleCallback : public IVehicleCallback { +private: + using MuxGuard = std::lock_guard<std::mutex>; + using HidlVecOfValues = hidl_vec<VehiclePropValue>; +public: + // Methods from ::android::hardware::automotive::vehicle::V2_0::IVehicleCallback follow. + Return<void> onPropertyEvent( + const hidl_vec<VehiclePropValue>& values) override { + { + MuxGuard g(mLock); + mReceivedEvents.push_back(values); + } + mEventCond.notify_one(); + return Return<void>(); + } + Return<void> onPropertySet(const VehiclePropValue& /* value */) override { + return Return<void>(); + } + Return<void> onPropertySetError(StatusCode /* errorCode */, + int32_t /* propId */, + int32_t /* areaId */) override { + return Return<void>(); + } + + bool waitForExpectedEvents(size_t expectedEvents) { + std::unique_lock<std::mutex> g(mLock); + + if (expectedEvents == 0 && mReceivedEvents.size() == 0) { + // No events expected, let's sleep a little bit to make sure + // nothing will show up. + return mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout; + } + + while (expectedEvents != mReceivedEvents.size()) { + if (mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout) { + return false; + } + } + return true; + } + + void reset() { + mReceivedEvents.clear(); + } + + const std::vector<HidlVecOfValues>& getReceivedEvents() { + return mReceivedEvents; + } + +private: + std::mutex mLock; + std::condition_variable mEventCond; + std::vector<HidlVecOfValues> mReceivedEvents; +}; + +template<typename T> +inline std::string hexString(T value) { + std::stringstream ss; + ss << std::showbase << std::hex << value; + return ss.str(); +} + +template <typename T, typename Collection> +inline void assertAllExistsAnyOrder( + std::initializer_list<T> expected, + const Collection& actual, + const char* msg) { + std::set<T> expectedSet = expected; + + for (auto a: actual) { + ASSERT_EQ(1u, expectedSet.erase(a)) + << msg << "\nContains not unexpected value.\n"; + } + + ASSERT_EQ(0u, expectedSet.size()) + << msg + << "\nDoesn't contain expected value."; +} + +#define ASSERT_ALL_EXISTS(...) \ + assertAllExistsAnyOrder(__VA_ARGS__, (std::string("Called from: ") + \ + std::string(__FILE__) + std::string(":") + \ + std::to_string(__LINE__)).c_str()); \ + +template<typename T> +inline std::string enumToHexString(T value) { + return hexString(toInt(value)); +} + +template <typename T> +inline std::string vecToString(const hidl_vec<T>& vec) { + std::stringstream ss("["); + for (size_t i = 0; i < vec.size(); i++) { + if (i != 0) ss << ","; + ss << vec[i]; + } + ss << "]"; + return ss.str(); +} + +inline std::string toString(const VehiclePropValue &v) { + std::stringstream ss; + ss << "VehiclePropValue {n" + << " prop: " << hexString(v.prop) << ",\n" + << " areaId: " << hexString(v.areaId) << ",\n" + << " timestamp: " << v.timestamp << ",\n" + << " value {\n" + << " int32Values: " << vecToString(v.value.int32Values) << ",\n" + << " floatValues: " << vecToString(v.value.floatValues) << ",\n" + << " int64Values: " << vecToString(v.value.int64Values) << ",\n" + << " bytes: " << vecToString(v.value.bytes) << ",\n" + << " string: " << v.value.stringValue.c_str() << ",\n" + << " }\n" + << "}\n"; + + return ss.str(); +} + +inline std::string toString(const VehiclePropConfig &config) { + std::stringstream ss; + ss << "VehiclePropConfig {\n" + << " prop: " << hexString(config.prop) << ",\n" + << " supportedAreas: " << hexString(config.supportedAreas) << ",\n" + << " access: " << enumToHexString(config.access) << ",\n" + << " changeMode: " << enumToHexString(config.changeMode) << ",\n" + << " configFlags: " << hexString(config.configFlags) << ",\n" + << " minSampleRate: " << config.minSampleRate << ",\n" + << " maxSampleRate: " << config.maxSampleRate << ",\n" + << " configString: " << config.configString.c_str() << ",\n"; + + ss << " areaConfigs {\n"; + for (size_t i = 0; i < config.areaConfigs.size(); i++) { + const auto &area = config.areaConfigs[i]; + ss << " areaId: " << hexString(area.areaId) << ",\n" + << " minFloatValue: " << area.minFloatValue << ",\n" + << " minFloatValue: " << area.maxFloatValue << ",\n" + << " minInt32Value: " << area.minInt32Value << ",\n" + << " minInt32Value: " << area.maxInt32Value << ",\n" + << " minInt64Value: " << area.minInt64Value << ",\n" + << " minInt64Value: " << area.maxInt64Value << ",\n"; + } + ss << " }\n" + << "}\n"; + + return ss.str(); +} + + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + +#endif //android_hardware_automotive_vehicle_V2_0_VehicleDebugUtils_H_
diff --git a/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp new file mode 100644 index 0000000..a291351 --- /dev/null +++ b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
@@ -0,0 +1,131 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <thread> + +#include <gtest/gtest.h> + +#include <utils/SystemClock.h> + +#include "vhal_v2_0/VehicleObjectPool.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace { + +class VehicleObjectPoolTest : public ::testing::Test { +protected: + void SetUp() override { + stats = PoolStats::instance(); + resetStats(); + valuePool.reset(new VehiclePropValuePool); + } + + void TearDown() override { + // At the end, all created objects should be either recycled or deleted. + // Some objects could be recycled multiple times, that's why it's <= + ASSERT_EQ(stats->Obtained, stats->Recycled); + ASSERT_LE(stats->Created, stats->Recycled); + } +private: + void resetStats() { + stats->Obtained = 0; + stats->Created = 0; + stats->Recycled = 0; + } + +public: + PoolStats* stats; + std::unique_ptr<VehiclePropValuePool> valuePool; +}; + +TEST_F(VehicleObjectPoolTest, valuePoolBasicCorrectness) { + void* raw = valuePool->obtain(VehiclePropertyType::INT32).get(); + // At this point, v1 should be recycled and the only object in the pool. + ASSERT_EQ(raw, valuePool->obtain(VehiclePropertyType::INT32).get()); + // Obtaining value of another type - should return a new object + ASSERT_NE(raw, valuePool->obtain(VehiclePropertyType::FLOAT).get()); + + ASSERT_EQ(3u, stats->Obtained); + ASSERT_EQ(2u, stats->Created); +} + +TEST_F(VehicleObjectPoolTest, valuePoolStrings) { + valuePool->obtain(VehiclePropertyType::STRING); + auto vs = valuePool->obtain(VehiclePropertyType::STRING); + vs->value.stringValue = "Hello"; + void* raw = vs.get(); + vs.reset(); // delete the pointer + + auto vs2 = valuePool->obtain(VehiclePropertyType::STRING); + ASSERT_EQ(0u, vs2->value.stringValue.size()); + ASSERT_NE(raw, valuePool->obtain(VehiclePropertyType::STRING).get()); + + ASSERT_EQ(0u, stats->Obtained); +} + +TEST_F(VehicleObjectPoolTest, valuePoolMultithreadedBenchmark) { + // In this test we have T threads that concurrently in C cycles + // obtain and release O VehiclePropValue objects of FLOAT / INT32 types. + + const int T = 2; + const int C = 500; + const int O = 100; + + auto poolPtr = valuePool.get(); + + std::vector<std::thread> threads; + auto start = elapsedRealtimeNano(); + for (int i = 0; i < T; i++) { + threads.push_back(std::thread([&poolPtr] () { + for (int j = 0; j < C; j++) { + std::vector<recyclable_ptr<VehiclePropValue>> vec; + for (int k = 0; k < O; k++) { + vec.push_back( + poolPtr->obtain(k % 2 == 0 + ? VehiclePropertyType::FLOAT + : VehiclePropertyType::INT32)); + } + } + })); + } + + for (auto& t : threads) { + t.join(); + } + auto finish = elapsedRealtimeNano(); + + ASSERT_EQ(static_cast<uint32_t>(T * C * O), stats->Obtained); + ASSERT_EQ(static_cast<uint32_t>(T * C * O), stats->Recycled); + // Created less than obtained. + ASSERT_GE(static_cast<uint32_t>(T * O), stats->Created); + + auto elapsedMs = (finish - start) / 1000000; + ASSERT_GE(1000, elapsedMs); // Less a second to access 100K objects. + // Typically it takes about 0.1s on Nexus6P. +} + +} // namespace anonymous + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VehiclePropConfigIndex_test.cpp b/automotive/vehicle/2.0/default/tests/VehiclePropConfigIndex_test.cpp new file mode 100644 index 0000000..0f65820 --- /dev/null +++ b/automotive/vehicle/2.0/default/tests/VehiclePropConfigIndex_test.cpp
@@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <gtest/gtest.h> + +#include "vhal_v2_0/VehiclePropConfigIndex.h" + +#include "VehicleHalTestUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace { + +class PropConfigTest : public ::testing::Test { +protected: + void SetUp() override { + configs.assign(std::begin(kVehicleProperties), + std::end(kVehicleProperties)); + } + + void TearDown() override {} + +public: + std::vector<VehiclePropConfig> configs; +}; + +TEST_F(PropConfigTest, hasConfig) { + VehiclePropConfigIndex index(configs); + + ASSERT_TRUE(index.hasConfig(toInt(VehicleProperty::HVAC_FAN_SPEED))); + ASSERT_TRUE(index.hasConfig(toInt(VehicleProperty::INFO_MAKE))); + ASSERT_TRUE(index.hasConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY))); + + ASSERT_FALSE(index.hasConfig(toInt(VehicleProperty::INVALID))); +} + +TEST_F(PropConfigTest, getAllConfig) { + VehiclePropConfigIndex index(configs); + + std::vector<VehiclePropConfig> actualConfigs = index.getAllConfigs(); + ASSERT_EQ(configs.size(), actualConfigs.size()); + + for (size_t i = 0; i < actualConfigs.size(); i++) { + ASSERT_EQ(toString(configs[i]), toString(actualConfigs[i])); + } +} + +TEST_F(PropConfigTest, getConfigs) { + VehiclePropConfigIndex index(configs); + auto actualConfig = index.getConfig(toInt(VehicleProperty::HVAC_FAN_SPEED)); + ASSERT_EQ(toString(configs[1]), toString(actualConfig)); +} + +} // namespace anonymous + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal new file mode 100644 index 0000000..b33b6ee --- /dev/null +++ b/automotive/vehicle/2.0/types.hal
@@ -0,0 +1,2689 @@ +/* + * Copyright (C) 2016 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.automotive.vehicle@2.0; + +/* + * Enumerates supported data types for VehicleProperty. + * + * This is a bitwise flag that supposed to be used in VehicleProperty enum. + */ +enum VehiclePropertyType : int32_t { + STRING = 0x00100000, + BOOLEAN = 0x00200000, + INT32 = 0x00400000, + INT32_VEC = 0x00410000, + INT64 = 0x00500000, + FLOAT = 0x00600000, + FLOAT_VEC = 0x00610000, + BYTES = 0x00700000, + + /* + * Any combination of scalar or vector types. The exact format must be + * provided in the description of the property. + */ + COMPLEX = 0x00e00000, + + MASK = 0x00ff0000 +}; + +/* + * Some properties may be associated with particular vehicle areas. For + * example, VehicleProperty:DOOR_LOCK property must be associated with + * particular door, thus this property must be marked with + * VehicleArea:DOOR flag. + * + * Other properties may not be associated with particular vehicle area, + * these kind of properties must have VehicleArea:GLOBAL flag. + * + * This is a bitwise flag that supposed to be used in VehicleProperty enum. + */ +enum VehicleArea : int32_t { + GLOBAL = 0x01000000, + ZONE = 0x02000000, + WINDOW = 0x03000000, + MIRROR = 0x04000000, + SEAT = 0x05000000, + DOOR = 0x06000000, + + MASK = 0x0f000000, +}; + +/* + * Enumerates property groups. + * + * This is a bitwise flag that supposed to be used in VehicleProperty enum. + */ +enum VehiclePropertyGroup : int32_t { + /* + * Properties declared in AOSP must have this flag. + */ + SYSTEM = 0x10000000, + + /* + * Properties declared by vendors must have this flag. + */ + VENDOR = 0x20000000, + + MASK = 0xf0000000, +}; + +/* + * Declares all vehicle properties. VehicleProperty has a bitwise structure. + * Each property must have: + * - an unique id from range 0x0100 - 0xffff + * - associated data type using VehiclePropertyType + * - property group (VehiclePropertyGroup) + * - vehicle area (VehicleArea) + * + * Vendors are allowed to extend this enum with their own properties. In this + * case they must use VehiclePropertyGroup:VENDOR flag when property is + * declared. + */ +enum VehicleProperty: int32_t { + + /* Undefined property. */ + INVALID = 0x00000000, + + /* + * VIN of vehicle + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + */ + INFO_VIN= ( + 0x0100 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:STRING + | VehicleArea:GLOBAL), + + /* + * Maker name of vehicle + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + */ + INFO_MAKE = ( + 0x0101 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:STRING + | VehicleArea:GLOBAL), + + /* + * Model of vehicle + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + */ + INFO_MODEL = ( + 0x0102 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:STRING + | VehicleArea:GLOBAL), + + /* + * Model year of vehicle. + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:YEAR + */ + INFO_MODEL_YEAR = ( + 0x0103 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Fuel capacity of the vehicle + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:MILLILITER + */ + INFO_FUEL_CAPACITY = ( + 0x0104 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /* + * Current odometer value of the vehicle + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE | VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:KILOMETER + */ + PERF_ODOMETER = ( + 0x0204 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /* + * Speed of the vehicle + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:METER_PER_SEC + */ + PERF_VEHICLE_SPEED = ( + 0x0207 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /* + * Temperature of engine coolant + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:CELCIUS + */ + ENGINE_COOLANT_TEMP = ( + 0x0301 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /* + * Temperature of engine oil + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:CELCIUS + */ + ENGINE_OIL_TEMP = ( + 0x0304 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /* + * Engine rpm + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:RPM + */ + ENGINE_RPM = ( + 0x0305 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /* + * Currently selected gear + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * @data_enum VehicleGear + */ + GEAR_SELECTION = ( + 0x0400 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Current gear. In non-manual case, selected gear does not necessarily + * match the current gear. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * @data_enum VehicleGear + */ + CURRENT_GEAR = ( + 0x0401 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Parking brake state. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + PARKING_BRAKE_ON = ( + 0x0402 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), + + /* + * Driving status policy. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * @data_enum VehicleDrivingStatus + */ + DRIVING_STATUS = ( + 0x0404 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Warning for fuel low level. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + FUEL_LEVEL_LOW = ( + 0x0405 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), + + /* + * Night mode or not. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + NIGHT_MODE = ( + 0x0407 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), + + /* + * State of the vehicles turn signals + * + * Values from VehicleTurnSignal + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + TURN_SIGNAL_STATE = ( + 0x0408 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Represents ignition state + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + IGNITION_STATE = ( + 0x0409 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Fan speed setting + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_FAN_SPEED = ( + 0x0500 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:ZONE), + + /* + * Fan direction setting + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @data_enum VehicleHvacFanDirection + */ + HVAC_FAN_DIRECTION = ( + 0x0501 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:ZONE), + + /* + * HVAC current temperature. + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_TEMPERATURE_CURRENT = ( + 0x0502 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:ZONE), + + /* + * HVAC, target temperature set. + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_TEMPERATURE_SET = ( + 0x0503 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:ZONE), + + /* + * On/off defrost + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_DEFROSTER = ( + 0x0504 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:WINDOW), + + /* + * On/off AC + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @config_flags Supported zones + */ + HVAC_AC_ON = ( + 0x0505 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:ZONE), + + /* + * On/off max AC + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_MAX_AC_ON = ( + 0x0506 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:ZONE), + + /* + * On/off max defrost + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_MAX_DEFROST_ON = ( + 0x0507 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:ZONE), + + /* + * On/off re-circulation + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_RECIRC_ON = ( + 0x0508 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:ZONE), + + /* + * On/off dual. This must be defined per each row. + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_DUAL_ON = ( + 0x0509 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:ZONE), + + /* + * On/off automatic mode + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_AUTO_ON = ( + 0x050A + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:ZONE), + + /* + * Seat temperature + * + * Negative values indicate cooling. + * 0 indicates off. + * Positive values indicate heating. + * + * Some vehicles may have multiple levels of heating and cooling. The + * min/max range defines the allowable range and number of steps in each + * direction. + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_SEAT_TEMPERATURE = ( + 0x050B + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /** + * Side Mirror Heat + * + * Increase values denote higher heating levels for side mirrors. + * 0 indicates heating is turned off. + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_SIDE_MIRROR_HEAT = ( + 0x050C + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:MIRROR), + + /** + * Steering Wheel Temperature + * + * Sets the temperature for the steering wheel + * Positive value indicates heating. + * Negative value indicates cooling. + * 0 indicates temperature control is off. + * + * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not + * guaranteed to work if HVAC unit is off. See HVAC_POWER_ON property for + * details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + HVAC_STEERING_WHEEL_TEMP = ( + 0x050D + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /** + * Temperature units + * + * Indicates whether the temperature is in Celsius, Fahrenheit, or a + * different unit from VehicleUnit enum. + * This parameter affects all HVAC temperatures in the system. + * + * IVehicle#get is not guaranteed to work if HVAC unit is off. See + * HVAC_POWER_ON property for details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + HVAC_TEMPERATURE_UNITS = ( + 0x050E + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:ZONE), + + /** + * Actual fan speed + * + * IVehicle#get is not guaranteed to work if HVAC unit is off. See + * HVAC_POWER_ON property for details. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + HVAC_ACTUAL_FAN_SPEED_RPM = ( + 0x050F + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:ZONE), + + /** + * Fan Positions Available + * + * This is a bit mask of fan positions available for the zone. Each entry in + * vehicle_hvac_fan_direction is selected by bit position. For instance, if + * only the FAN_DIRECTION_FACE (0x1) and FAN_DIRECTION_DEFROST (0x4) are available, + * then this value shall be set to 0x12. + * + * 0x12 = (1 << 1) | (1 << 4) + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + */ + HVAC_FAN_DIRECTION_AVAILABLE = ( + 0x0511 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:ZONE), + + /* + * Represents power state for HVAC. Some HVAC properties must require + * matching power to be turned on to get out of OFF state. For non-zoned + * HVAC properties, VEHICLE_ALL_ZONE corresponds to global power state. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @config_string list of HVAC properties whose power is controlled by this + * property. Format is hexa-decimal number (0x...) separated + * by comma like "0x500,0x503". All zones defined in these + * affected properties must be available in the property. + */ + HVAC_POWER_ON = ( + 0x0510 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:ZONE), + + /* + * Outside temperature + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:CELCIUS + */ + ENV_OUTSIDE_TEMPERATURE = ( + 0x0703 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /* + * Cabin temperature + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:CELCIUS + */ + ENV_CABIN_TEMPERATURE = ( + 0x0704 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT + | VehicleArea:GLOBAL), + + /* + * Radio presets stored on the Car radio module. The data type used is int32 + * array with the following fields: + * <ul> + * <li> int32Values[0]: Preset number </li> + * <li> int32Values[1]: Band type (see #RADIO_BAND_FM in + * system/core/include/system/radio.h). + * <li> int32Values[2]: Channel number </li> + * <li> int32Values[3]: Sub channel number </li> + * </ul> + * + * NOTE: When getting a current preset config ONLY set preset number (i.e. + * int32Values[0]). For setting a preset other fields are required. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @config_flags Number of presets supported + */ + RADIO_PRESET = ( + 0x0801 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * Represents audio focus state of Android side. Note that car's audio + * module must own audio focus and grant audio focus to Android side when + * requested by Android side. The focus has both per stream characteristics + * and global characteristics. + * + * Focus request (get of this property) must take the following form: + * int32Values[0]: VehicleAudioFocusRequest type + * int32Values[1]: bit flags of streams requested by this focus request. + * There can be up to 32 streams. + * int32Values[2]: External focus state flags. For request, only flag like + * VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG or + * VehicleAudioExtFocusFlag#MUTE_MEDIA_FLAG can be + * used. + * VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG is for case + * like radio where android side app still needs to hold + * focus but playback is done outside Android. + * VehicleAudioExtFocusFlag#MUTE_MEDIA_FLAG is for + * muting media channel including radio. + * VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG can be set + * even if android side releases focus (request type + * REQUEST_RELEASE). In that case, audio module must + * maintain mute state until user's explicit action to + * play some media. + * int32Values[3]: Currently active audio contexts. Use combination of + * flags from VehicleAudioContextFlag. + * This can be used as a hint to adjust audio policy or + * other policy decision. + * Note that there can be multiple context active at the + * same time. And android can send the same focus request + * type gain due to change in audio contexts. + * Note that each focus request can request multiple streams that is + * expected to be used for the current request. But focus request itself + * is global behavior as GAIN or GAIN_TRANSIENT expects all sounds played + * by car's audio module to stop. Note that stream already allocated to + * android before this focus request must not be affected by focus + * request. + * + * Focus response (set and subscription callback for this property) must + * take the following form: + * int32Values[0]: VehicleAudioFocusState type + * int32Values[1]: bit flags of streams allowed. + * int32Values[2]: External focus state: bit flags of currently active + * audio focus in car side (outside Android). Active + * audio focus does not necessarily mean currently + * playing, but represents the state of having focus or + * waiting for focus (pause state). + * One or combination of flags from + * VehicleAudioExtFocusFlag. + * 0 means no active audio focus holder outside Android. + * The state must have following values for each + * VehicleAudioFocusState: + * GAIN: 0 or VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG + * when radio is active in Android side. + * GAIN_TRANSIENT: 0. Can be + * VehicleAudioExtFocusFlag#PERMANENT_FLAG or + * VehicleAudioExtFocusFlag#TRANSIENT_FLAG if android + * side has requested + * REQUEST_GAIN_TRANSIENT_MAY_DUCK and car side is + * ducking. + * LOSS: 0 when no focus is audio is active in car side. + * VehicleAudioExtFocusFlag#PERMANENT_FLAG when car + * side is playing something permanent. + * LOSS_TRANSIENT: always must be + * VehicleAudioExtFocusFlag#PERMANENT_FLAG + * int32Values[3]: context requested by android side when responding to + * focus request. When car side is taking focus away, + * this must be zero. + * + * A focus response must be sent per each focus request even if there is + * no change in focus state. This can happen in case like focus request + * only involving context change where android side still needs matching + * focus response to confirm that audio module has made necessary changes. + * + * If car does not support AUDIO_FOCUS, focus is assumed to be granted + * always. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + AUDIO_FOCUS = ( + 0x0900 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * A property to allow external component to control audio focus. Depending on + * H/W architecture, audio HAL may need to control audio focus while vehicle + * HAL is still interacting with upper layer. In such case, audio HAL may set + * this property and vehicle HAL may use this property value to decide + * response sent through AUDIO_FOCUS property. + * Data format is the same as AUDIO_FOCUS property. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + AUDIO_FOCUS_EXT_SYNC = ( + 0x0910 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * Property to control audio volume of each audio context. + * + * VehiclePropConfig + * configArray[0] : bit flags of all supported audio contexts from + * VehicleAudioContextFlag. If this is 0, audio volume is + * controlled per physical stream. + * configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag to + * represent audio module's capability. + * configArray[2..3] : reserved + * configArray[4..N+3] : maximum values for each audio context, where N is + * the number of audio contexts provided in + * configArray[0], minimum value is always 0 which + * indicates mute state. + * + * Data type looks like: + * int32Values[0] : stream context as defined in VehicleAudioContextFlag. + * If only physical stream is supported + * (configArray[0] == 0), this must represent physical + * stream number. + * int32Values[1] : volume level, valid range is 0 (mute) to max level + * defined in the config. + * int32Values[2] : One of VehicleAudioVolumeState. + * + * This property requires per stream based get. HAL implementation must + * check stream number in get call to return the right volume. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @config_flags all audio contexts supported. + */ + AUDIO_VOLUME = ( + 0x0901 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * Property to allow audio volume sync from external components like audio HAL. + * Some vehicle HAL implementation may get volume control from audio HAL and in such + * case, setting AUDIO_VOLUME_EXT_SYNC property may trigger event in AUDIO_VOLUME property. + * Data format for this property is the same as AUDIO_VOLUME property. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @config_flags all audio contexts supported. + */ + AUDIO_VOLUME_EXT_SYNC = ( + 0x0911 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * Property for handling volume limit set by user. This limits maximum + * volume that can be set per each context or physical stream. + * + * VehiclePropConfig + * configArray[0] : bit flags of all supported audio contexts. If this is + * 0, audio volume is controlled per physical stream. + * configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag + * to represent audio module's capability. + * + * Data type looks like: + * int32Values[0] : stream context as defined in VehicleAudioFocusFlag. + * If only physical stream is supported + * (configArray[0] == 0), this must represent physical + * stream number. + * int32Values[1] : maximum volume set to the stream. If there is no + * restriction, this value must be bigger than + * AUDIO_VOLUME's max value. + * + * If car does not support this feature, this property must not be + * populated by HAL. + * This property requires per stream based get. HAL implementation must + * check stream number in get call to return the right volume. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @config_flags all audio contexts supported. + */ + AUDIO_VOLUME_LIMIT = ( + 0x0902 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * Property to share audio routing policy of android side. This property is + * set at the beginning to pass audio policy in android side down to + * vehicle HAL and car audio module. + * This can be used as a hint to adjust audio policy or other policy + * decision. + * + * int32Values[0] : audio stream where the audio for the application + * context must be routed by default. Note that this is + * the default setting from system, but each app may + * still use different audio stream for whatever reason. + * int32Values[1] : All audio contexts that must be sent through the + * physical stream. Flag is defined in + * VehicleAudioFocusFlag. + + * Setting of this property must be done for all available physical streams + * based on audio H/W variant information acquired from AUDIO_HW_VARIANT + * property. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:WRITE + */ + AUDIO_ROUTING_POLICY = ( + 0x0903 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * Property to return audio H/W variant type used in this car. This allows + * android side to support different audio policy based on H/W variant used. + * Note that other components like CarService may need overlay update to + * support additional variants. If this property does not + * exist, default audio policy must be used. + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + * @config_flags Additional info on audio H/W. Must use + * VehicleAudioHwVariantConfigFlag for this. + */ + AUDIO_HW_VARIANT = ( + 0x0904 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Property to pass hint on external audio routing. When android side + * request focus with VehicleAudioExtFocusflag, this + * property must be set before setting AUDIO_FOCUS property as a hint for + * external audio source routing. + * Note that setting this property alone must not trigger any change. + * Audio routing must be changed only when AUDIO_FOCUS property is set. + * Note that this property allows passing custom value as long as it is + * defined in VehiclePropConfig#configString. This allows supporting + * non-standard routing options through this property. + * It is recommended to use separate name space for custom property to + * prevent conflict in future android releases. + * Enabling each external routing option is done by enabling each bit flag + * for the routing. + * This property can support up to 128 external routings. + * To give full flexibility, there is no standard definition for each bit + * flag and assigning each big flag to specific routing type is decided by + * VehiclePropConfig#configString. VehiclePropConfig#configString has + * format of each entry separated by ',' and each entry has format of + * bitFlagPositon:typeString[:physicalStreamNumber]. + * bitFlagPosition: represents which big flag will be set to enable this + * routing. 0 means + * LSB in int32Values[0]. 31 will be MSB in int32Values[0]. 127 will MSB + * in int32Values[3]. + * typeString: string representation of external routing. Some types are + * already defined in AUDIO_EXT_ROUTING_SOURCE_* and use them first + * before adding something custom. Applications will find each routing + * using this string. + * physicalStreamNumber: This part is optional and represents physical + * stream to android which will be disabled when this routing is enabled. + * If not specified, this routing must not affect physical streams to + * android. + * As an example, let's assume a system with two physical streams, 0 for + * media and 1 for nav guidance. And let's assume external routing option + * of am fm radio, external navigation guidance, satellite radio, and one + * custom. Let's assume that radio and satellite replaces physical stream 0 + * and external navigation replaces physical stream 1. And bit flag will be + * assigned in the order listed above. This configuration will look like + * this in config_string: + * "0:RADIO_AM_FM:0,1:EXT_NAV_GUIDANCE:1,2:RADIO_SATELLITE:0,3:com.test.SOMETHING_CUSTOM" + * When android requests RADIO_AM_FM, int32Values[0] will be set to 0x1. + * When android requests RADIO_SATELLITE + EXT_NAV_GUIDANCE, int32Values[0] + * will be set to 0x2|0x4. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @config_string List of all avaiable external source in the system. + */ + AUDIO_EXT_ROUTING_HINT = ( + 0x0905 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /** + * Represents state of audio stream. Audio HAL should set this when a stream is starting or + * ending. Car service can request focus for audio played without focus. If such feature + * is not required, this property does not need to be implemented. + * Car service only monitors setting of this property. It is up to each vehicle HAL + * implementation to add necessary action but default implementation will be doing nothing on + * this propery's set from audio HAL. + * Actual streaming of data should be done only after getting focus for the given stream from + * car audio module. Focus can be already granted when stream is started. Focus state can be + * monitored by monitoring AUDIO_FOCUS property. If car does not support + * AUDIO_FOCUS property, there is no need to monitor focus as focus is assumed to be + * granted always. + * Data has the following format: + * int32_array[0] : vehicle_audio_stream_state, 0: stopped, 1: started + * int32_array[1] : stream number like 0, 1, 2, ... + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + AUDIO_STREAM_STATE = ( + 0x0906 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /** + * Property to control car specific audio parameters. Each parameter is defined as string key- + * value pair. + * set and event notification can pass multiple parameters using the + * following format: + * key1=value1;key2=value2;... + * get call can request multiple parameters using the following format: + * key1;key2;... + * Response for get call has the same format as set. + * + * VehiclePropConfig + * configString: give list of all supported keys with ; as separator. For example: + * key1;key2;... + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + AUDIO_PARAMETERS = ( + 0x907 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:STRING + | VehicleArea:GLOBAL), + + /* + * Property to control power state of application processor + * + * It is assumed that AP's power state is controller by separate power + * controller. + * + * For configuration information, VehiclePropConfig.configFlags can + * have bit flag combining values in VehicleApPowerStateConfigFlag. + * + * Value format for IVehicle#get / IVehicle#subscribe: + * int32Values[0] : vehicle_ap_power_state_type + * int32Values[1] : additional parameter relevant for each state, + * 0 if not used. + * Value format for IVehicle#set: + * int32Values[0] : vehicle_ap_power_state_set_type + * int32Values[1] : additional parameter relevant for each request. should be 0 if not used. + * + * @change_mode VEHICLE_PROP_CHANGE_MODE_ON_CHANGE + * @access VEHICLE_PROP_ACCESS_READ_WRITE + */ + AP_POWER_STATE = ( + 0x0A00 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * Property to represent brightness of the display. Some cars have single + * control for the brightness of all displays and this property is to share + * change in that control. + * + * If this is writable, android side can set this value when user changes + * display brightness from Settings. If this is read only, user may still + * change display brightness from Settings, but that will not be reflected + * to other displays. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + DISPLAY_BRIGHTNESS = ( + 0x0A01 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Property to report bootup reason for the current power on. This is a + * static property that will not change for the whole duration until power + * off. For example, even if user presses power on button after automatic + * power on with door unlock, bootup reason must stay with + * VehicleApPowerBootupReason#USER_UNLOCK. + * + * int32Values[0] must be VehicleApPowerBootupReason. + * + * @change_mode VehiclePropertyChangeMode:STATIC + * @access VehiclePropertyAccess:READ + */ + AP_POWER_BOOTUP_REASON = ( + 0x0A02 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Property to feed H/W input events to android + * + * int32Values[0] : action defined by VehicleHwKeyInputAction + * int32Values[1] : key code, must use standard android key code + * int32Values[2] : target display defined in VehicleDisplay. Events not + * tied to specific display must be sent to + * VehicleDisplay#MAIN. + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + * @config_flags + */ + HW_KEY_INPUT = ( + 0x0A10 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * Property to define instrument cluster information. + * For VehicleInstrumentClusterType:EXTERNAL_DISPLAY: + * READ: + * int32Values[0] : The current screen mode index. Screen mode is defined + * as a configuration in car service and represents + * which area of screen is renderable. + * int32Values[1] : Android can render to instrument cluster (=1) or + * not(=0). When this is 0, instrument cluster may be + * rendering some information in the area allocated for + * android and android side rendering is invisible. + * WRITE from android: + * int32Values[0] : Preferred mode for android side. Depending on the app + * rendering to instrument cluster, preferred mode can + * change. Instrument cluster still needs to send + * event with new mode to trigger actual mode change. + * int32Values[1] : The current app context relevant for instrument + * cluster. Use the same flag with VehicleAudioFocusFlag + * but this context represents active apps, not + * active audio. Instrument cluster side may change mode + * depending on the currently active contexts. + * When system boots up, Android side will write {0, 0, 0, 0} when it is + * ready to render to instrument cluster. Before this message, rendering + * from android must not be visible in the cluster. + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + * @configArray 0:VehicleInstrumentClusterType 1:hw type + */ + INSTRUMENT_CLUSTER_INFO = ( + 0x0A20 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32_VEC + | VehicleArea:GLOBAL), + + /* + * Current date and time, encoded as Unix time. + * This value denotes the number of seconds that have elapsed since + * 1/1/1970. + * + * @change_mode VehiclePropertyChangeMode:ON_SET + * @access VehiclePropertyAccess:READ_WRITE + * @unit VehicleUnit:SECS + */ + UNIX_TIME = ( + 0x0A30 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT64 + | VehicleArea:GLOBAL), + + /* + * Current time only. + * Some vehicles may not keep track of date. This property only affects + * the current time, in seconds during the day. Thus, the max value for + * this parameter is 86,400 (24 * 60 * 60) + * + * @change_mode VehiclePropertyChangeMode:ON_SET + * @access VehiclePropertyAccess:READ_WRITE + * @unit VehicleUnit:SECS + */ + CURRENT_TIME_IN_SECONDS = ( + 0x0A31 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Door position + * + * This is an integer in case a door may be set to a particular position. + * Max value indicates fully open, min value (0) indicates fully closed. + * + * Some vehicles (minivans) can open the door electronically. Hence, the + * ability to write this property. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + DOOR_POS = ( + 0x0B00 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:DOOR), + + /* + * Door move + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + DOOR_MOVE = ( + 0x0B01 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:DOOR), + + /* + * Door lock + * + * 'true' indicates door is locked + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + DOOR_LOCK = ( + 0x0B02 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:DOOR), + + /* + * Mirror Z Position + * + * Positive value indicates tilt upwards, negative value is downwards + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + MIRROR_Z_POS = ( + 0x0B40 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:MIRROR), + + /* + * Mirror Z Move + * + * Positive value indicates tilt upwards, negative value is downwards + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + MIRROR_Z_MOVE = ( + 0x0B41 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:MIRROR), + + /* + * Mirror Y Position + * + * Positive value indicate tilt right, negative value is left + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + MIRROR_Y_POS = ( + 0x0B42 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:MIRROR), + + /* + * Mirror Y Move + * + * Positive value indicate tilt right, negative value is left + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + MIRROR_Y_MOVE = ( + 0x0B43 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:MIRROR), + + /* + * Mirror Lock + * + * True indicates mirror positions are locked and not changeable + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + MIRROR_LOCK = ( + 0x0B44 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), + + /* + * Mirror Fold + * + * True indicates mirrors are folded + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + MIRROR_FOLD = ( + 0x0B45 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), + + /* + * Seat memory select + * + * This parameter selects the memory preset to use to select the seat + * position. The minValue is always 0, and the maxValue determines the + * number of seat positions available. + * + * For instance, if the driver's seat has 3 memory presets, the maxValue + * will be 3. When the user wants to select a preset, the desired preset + * number (1, 2, or 3) is set. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:WRITE + */ + SEAT_MEMORY_SELECT = ( + 0x0B80 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat memory set + * + * This setting allows the user to save the current seat position settings + * into the selected preset slot. The maxValue for each seat position + * shall match the maxValue for SEAT_MEMORY_SELECT. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:WRITE + */ + SEAT_MEMORY_SET = ( + 0x0B81 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seatbelt buckled + * + * True indicates belt is buckled. + * + * Write access indicates automatic seat buckling capabilities. There are + * no known cars at this time, but you never know... + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_BELT_BUCKLED = ( + 0x0B82 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:SEAT), + + /* + * Seatbelt height position + * + * Adjusts the shoulder belt anchor point. + * Max value indicates highest position + * Min value indicates lowest position + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_BELT_HEIGHT_POS = ( + 0x0B83 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seatbelt height move + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_BELT_HEIGHT_MOVE = ( + 0x0B84 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat fore/aft position + * + * Sets the seat position forward (closer to steering wheel) and backwards. + * Max value indicates closest to wheel, min value indicates most rearward + * position. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_FORE_AFT_POS = ( + 0x0B85 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat fore/aft move + * + * Moves the seat position forward and aft. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_FORE_AFT_MOVE = ( + 0x0B86 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat backrest angle 1 position + * + * Backrest angle 1 is the actuator closest to the bottom of the seat. + * Max value indicates angling forward towards the steering wheel. + * Min value indicates full recline. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_BACKREST_ANGLE_1_POS = ( + 0x0B87 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat backrest angle 1 move + * + * Moves the backrest forward or recline. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_BACKREST_ANGLE_1_MOVE = ( + 0x0B88 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat backrest angle 2 position + * + * Backrest angle 2 is the next actuator up from the bottom of the seat. + * Max value indicates angling forward towards the steering wheel. + * Min value indicates full recline. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_BACKREST_ANGLE_2_POS = ( + 0x0B89 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat backrest angle 2 move + * + * Moves the backrest forward or recline. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_BACKREST_ANGLE_2_MOVE = ( + 0x0B8A + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat height position + * + * Sets the seat height. + * Max value indicates highest position. + * Min value indicates lowest position. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_HEIGHT_POS = ( + 0x0B8B + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat height move + * + * Moves the seat height. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_HEIGHT_MOVE = ( + 0x0B8C + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat depth position + * + * Sets the seat depth, distance from back rest to front edge of seat. + * Max value indicates longest depth position. + * Min value indicates shortest position. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_DEPTH_POS = ( + 0x0B8D + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat depth move + * + * Adjusts the seat depth. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_DEPTH_MOVE = ( + 0x0B8E + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat tilt position + * + * Sets the seat tilt. + * Max value indicates front edge of seat higher than back edge. + * Min value indicates front edge of seat lower than back edge. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_TILT_POS = ( + 0x0B8F + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Seat tilt move + * + * Tilts the seat. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_TILT_MOVE = ( + 0x0B90 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Lumber fore/aft position + * + * Pushes the lumbar support forward and backwards + * Max value indicates most forward position. + * Min value indicates most rearward position. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_LUMBAR_FORE_AFT_POS = ( + 0x0B91 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Lumbar fore/aft move + * + * Adjusts the lumbar support. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_LUMBAR_FORE_AFT_MOVE = ( + 0x0B92 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Lumbar side support position + * + * Sets the amount of lateral lumbar support. + * Max value indicates widest lumbar setting (i.e. least support) + * Min value indicates thinnest lumbar setting. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_LUMBAR_SIDE_SUPPORT_POS = ( + 0x0B93 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Lumbar side support move + * + * Adjusts the amount of lateral lumbar support. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_LUMBAR_SIDE_SUPPORT_MOVE = ( + 0x0B94 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Headrest height position + * + * Sets the headrest height. + * Max value indicates tallest setting. + * Min value indicates shortest setting. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_HEADREST_HEIGHT_POS = ( + 0x0B95 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Headrest height move + * + * Moves the headrest up and down. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_HEADREST_HEIGHT_MOVE = ( + 0x0B96 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Headrest angle position + * + * Sets the angle of the headrest. + * Max value indicates most upright angle. + * Min value indicates shallowest headrest angle. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_HEADREST_ANGLE_POS = ( + 0x0B97 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Headrest angle move + * + * Adjusts the angle of the headrest + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_HEADREST_ANGLE_MOVE = ( + 0x0B98 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Headrest fore/aft position + * + * Adjusts the headrest forwards and backwards. + * Max value indicates position closest to front of car. + * Min value indicates position closest to rear of car. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_HEADREST_FORE_AFT_POS = ( + 0x0B99 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Headrest fore/aft move + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + SEAT_HEADREST_FORE_AFT_MOVE = ( + 0x0B9A + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:SEAT), + + /* + * Window Position + * + * Max = window up / closed + * Min = window down / open + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + WINDOW_POS = ( + 0x0BC0 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Window Move + * + * Max = window up / closed + * Min = window down / open + * Magnitude denotes relative speed. I.e. +2 is faster than +1 in raising + * the window. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + WINDOW_MOVE = ( + 0x0BC1 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Window Vent Position + * + * This feature is used to control the vent feature on a sunroof. + * + * Max = vent open + * Min = vent closed + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + WINDOW_VENT_POS = ( + 0x0BC2 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Window Vent Move + * + * This feature is used to control the vent feature on a sunroof. + * + * Max = vent open + * Min = vent closed + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + WINDOW_VENT_MOVE = ( + 0x0BC3 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:INT32 + | VehicleArea:GLOBAL), + + /* + * Window Lock + * + * True indicates windows are locked and can't be moved. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + WINDOW_LOCK = ( + 0x0BC4 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:BOOLEAN + | VehicleArea:GLOBAL), +}; + +/* + * Bit flags for fan direction + */ +enum VehicleHvacFanDirection : int32_t { + FACE = 0x1, + FLOOR = 0x2, + FACE_AND_FLOOR = 0x3, + DEFROST = 0x4, + DEFROST_AND_FLOOR = 0x5, +}; + +/* + * Constants relevant to radio. + */ +enum VehicleRadioConstants : int32_t { + /* Minimum value for the radio preset */ + VEHICLE_RADIO_PRESET_MIN_VALUE = 1, +}; + +enum VehicleAudioFocusRequest : int32_t { + REQUEST_GAIN = 0x1, + REQUEST_GAIN_TRANSIENT = 0x2, + REQUEST_GAIN_TRANSIENT_MAY_DUCK = 0x3, + /* + * This is for the case where android side plays sound like UI feedback + * and car side does not need to duck existing playback as long as + * requested stream is available. + */ + REQUEST_GAIN_TRANSIENT_NO_DUCK = 0x4, + REQUEST_RELEASE = 0x5, + +}; + +enum VehicleAudioFocusState : int32_t { + /* + * Android side has permanent focus and can play allowed streams. + */ + STATE_GAIN = 0x1, + + /* + * Android side has transient focus and can play allowed streams. + */ + STATE_GAIN_TRANSIENT = 0x2, + + /* + * Car audio module is playing guidance kind of sound outside Android. + * Android side can still play through allowed streams with ducking. + */ + STATE_LOSS_TRANSIENT_CAN_DUCK = 0x3, + + /* + * Car audio module is playing transient sound outside Android. Android side + * must stop playing any sounds. + */ + STATE_LOSS_TRANSIENT = 0x4, + + /* + * Android side has lost focus and cannot play any sound. + */ + STATE_LOSS = 0x5, + + /* + * car audio module is playing safety critical sound, and Android side cannot + * request focus until the current state is finished. car audio module + * restore it to the previous state when it can allow Android to play. + */ + STATE_LOSS_TRANSIENT_EXLCUSIVE = 0x6, + +}; + +/* + * Flags to represent multiple streams by combining these. + */ +enum VehicleAudioStreamFlag : int32_t { + STREAM0_FLAG = (0x1 << 0), + STREAM1_FLAG = (0x1 << 1), + STREAM2_FLAG = (0x1 << 2), +}; + +/* + * Represents stream number (always 0 to N -1 where N is max number of streams). + * Can be used for audio related property expecting one stream. + */ +enum VehicleAudioStream : int32_t { + STREAM0 = 0, + STREAM1 = 1, +}; + +/* + * Flag to represent external focus state (outside Android). + */ +enum VehicleAudioExtFocusFlag : int32_t { + /* + * No external focus holder. + */ + NONE_FLAG = 0x0, + + /* + * Car side (outside Android) has component holding GAIN kind of focus state. + */ + PERMANENT_FLAG = 0x1, + + /* + * Car side (outside Android) has component holding GAIN_TRANSIENT kind of + * focus state. + */ + TRANSIENT_FLAG = 0x2, + + /* + * Car side is expected to play something while focus is held by Android side. + * One example can be radio attached in car side. But Android's radio app + * still must have focus, and Android side must be in GAIN state, but + * media stream will not be allocated to Android side and car side can play + * radio any time while this flag is active. + */ + PLAY_ONLY_FLAG = 0x4, + + /* + * Car side must mute any media including radio. This can be used with any + * focus request including GAIN* and RELEASE. + */ + MUTE_MEDIA_FLAG = 0x8, +}; + +/* + * Index in int32Values for VehicleProperty#AUDIO_FOCUS property. + */ +enum VehicleAudioFocusIndex : int32_t { + FOCUS = 0, + STREAMS = 1, + EXTERNAL_FOCUS_STATE = 2, + AUDIO_CONTEXTS = 3, +}; + +/* + * Flags to tell the current audio context. + */ +enum VehicleAudioContextFlag : int32_t { + /* Music playback is currently active. */ + MUSIC_FLAG = 0x1, + + /* Navigation is currently running. */ + NAVIGATION_FLAG = 0x2, + + /* Voice command session is currently running. */ + VOICE_COMMAND_FLAG = 0x4, + + /* Voice call is currently active. */ + CALL_FLAG = 0x8, + + /* + * Alarm is active. + * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY. + */ + ALARM_FLAG = 0x10, + + /* + * Notification sound is active. + * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY. + */ + NOTIFICATION_FLAG = 0x20, + + /* + * Context unknown. Only used for VehicleProperty#AUDIO_ROUTING_POLICY to + * represent default stream for unknown contents. + */ + UNKNOWN_FLAG = 0x40, + + /* Safety alert / warning is played. */ + SAFETY_ALERT_FLAG = 0x80, + + /* CD / DVD kind of audio is played */ + CD_ROM_FLAG = 0x100, + + /* Aux audio input is played */ + AUX_AUDIO_FLAG = 0x200, + + /* system sound like UI feedback */ + SYSTEM_SOUND_FLAG = 0x400, + + /* Radio is played */ + RADIO_FLAG = 0x800, + + /* Ext source is played. This is for tagging generic ext sources. */ + EXT_SOURCE_FLAG = 0x1000, +}; + +/* + * flags to represent capability of audio volume property. + * used in configArray[1] of VehiclePropConfig. + */ +enum VehicleAudioVolumeCapabilityFlag : int32_t { + /* + * External audio module or vehicle hal has persistent storage + * to keep the volume level. This must be set only when per context + * volume level is supported. When this is set, audio volume level per + * each context will be retrieved from the property when system starts up. + * And external audio module is also expected to adjust volume automatically + * whenever there is an audio context change. + * When this flag is not set, android side will assume that there is no + * persistent storage and stored value in android side will be used to + * initialize the volume level. And android side will set volume level + * of each physical streams whenever there is an audio context change. + */ + PERSISTENT_STORAGE = 0x1, + + /* + * When this flag is set, the H/W can support only single master volume for + * all streams. + * There is no way to set volume level differently per each stream or context. + */ + MASTER_VOLUME_ONLY = 0x2, +}; + +/* + * enum to represent audio volume state. + */ +enum VehicleAudioVolumeState : int32_t { + STATE_OK = 0, + + /* + * Audio volume has reached volume limit set in + * VehicleProperty#AUDIO_VOLUME_LIMIT and user's request to increase volume + * further is not allowed. + */ + LIMIT_REACHED = 1, +}; + +/* + * Index in int32Values for VehicleProperty#AUDIO_VOLUME property. + */ +enum VehicleAudioVolumeIndex : int32_t { + INDEX_STREAM = 0, + INDEX_VOLUME = 1, + INDEX_STATE = 2, +}; + +/* + * Index in int32Values for VehicleProperty#AUDIO_VOLUME_LIMIT property. + */ +enum VehicleAudioVolumeLimitIndex : int32_t { + STREAM = 0, + MAX_VOLUME = 1, +}; + +/* + * Index in int32Values for VehicleProperty#AUDIO_ROUTING_POLICY property. + */ +enum VehicleAudioRoutingPolicyIndex : int32_t { + STREAM = 0, + CONTEXTS = 1, +}; + +/* + * Flag to be used in VehiclePropConfig#configFlags for + * VehicleProperty#AUDIO_HW_VARIANT. + */ +enum VehicleAudioHwVariantConfigFlag : int32_t { + /* + * Flag to tell that radio is internal to android and radio must + * be treated like other android stream like media. + * When this flag is not set or AUDIO_HW_VARIANT does not exist, + * radio is treated as external module. This brins some delta in audio focus + * handling as well. + */ + INTERNAL_RADIO_FLAG = 0x1, +}; + +enum VehicleApPowerStateConfigFlag : int32_t /* NOTE: type is guessed */ { + /* + * AP can enter deep sleep state. If not set, AP will always shutdown from + * VehicleApPowerState#SHUTDOWN_PREPARE power state. + */ + ENABLE_DEEP_SLEEP_FLAG = 0x1, + + /* + * The power controller can power on AP from off state after timeout + * specified in VehicleApPowerSet VEHICLE_AP_POWER_SET_SHUTDOWN_READY message. + */ + CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 0x2, +}; + +enum VehicleApPowerState : int32_t /* NOTE: type is guessed */ { + /* vehicle HAL will never publish this state to AP */ + OFF = 0, + + /* vehicle HAL will never publish this state to AP */ + DEEP_SLEEP = 1, + + /* AP is on but display must be off. */ + ON_DISP_OFF = 2, + + /* AP is on with display on. This state allows full user interaction. */ + ON_FULL = 3, + + /* + * The power controller has requested AP to shutdown. AP can either enter + * sleep state or start full shutdown. AP can also request postponing + * shutdown by sending VehicleApPowerSetState#SHUTDOWN_POSTPONE message. The + * power controller must change power state to this state to shutdown + * system. + * + * int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type + */ + SHUTDOWN_PREPARE = 4, +}; + +enum VehicleApPowerStateShutdownParam : int32_t { + /* AP must shutdown immediately. Postponing is not allowed. */ + SHUTDOWN_IMMEDIATELY = 1, + + /* AP can enter deep sleep instead of shutting down completely. */ + CAN_SLEEP = 2, + + /* AP can only shutdown with postponing allowed. */ + SHUTDOWN_ONLY = 3, +}; + +enum VehicleApPowerSetState : int32_t /* NOTE: type is guessed */ { + /* + * AP has finished boot up, and can start shutdown if requested by power + * controller. + */ + BOOT_COMPLETE = 0x1, + + /* + * AP is entering deep sleep state. How this state is implemented may vary + * depending on each H/W, but AP's power must be kept in this state. + */ + DEEP_SLEEP_ENTRY = 0x2, + + /* + * AP is exiting from deep sleep state, and is in + * VehicleApPowerState#SHUTDOWN_PREPARE state. + * The power controller may change state to other ON states based on the + * current state. + */ + DEEP_SLEEP_EXIT = 0x3, + + /* + * int32Values[1]: Time to postpone shutdown in ms. Maximum value can be + * 5000 ms. + * If AP needs more time, it will send another POSTPONE + * message before the previous one expires. + */ + SHUTDOWN_POSTPONE = 0x4, + + /* + * AP is starting shutting down. When system completes shutdown, everything + * will stop in AP as kernel will stop all other contexts. It is + * responsibility of vehicle HAL or lower level to synchronize that state + * with external power controller. As an example, some kind of ping + * with timeout in power controller can be a solution. + * + * int32Values[1]: Time to turn on AP in secs. Power controller may turn on + * AP after specified time so that AP can run tasks like + * update. If it is set to 0, there is no wake up, and power + * controller may not necessarily support wake-up. If power + * controller turns on AP due to timer, it must start with + * VehicleApPowerState#ON_DISP_OFF state, and after + * receiving VehicleApPowerSetState#BOOT_COMPLETE, it shall + * do state transition to + * VehicleApPowerState#SHUTDOWN_PREPARE. + */ + SHUTDOWN_START = 0x5, + + /* + * User has requested to turn off headunit's display, which is detected in + * android side. + * The power controller may change the power state to + * VehicleApPowerState#ON_DISP_OFF. + */ + DISPLAY_OFF = 0x6, + + /* + * User has requested to turn on headunit's display, most probably from power + * key input which is attached to headunit. The power controller may change + * the power state to VehicleApPowerState#ON_FULL. + */ + DISPLAY_ON = 0x7, +}; + +/* + * Index in int32Values for VehicleProperty#AP_POWER_STATE property. + */ +enum VehicleApPowerStateIndex : int32_t { + STATE = 0, + ADDITIONAL = 1, +}; + +/* + * Enum to represent bootup reason. + */ +enum VehicleApPowerBootupReason : int32_t { + /* + * Power on due to user's pressing of power key or rotating of ignition + * switch. + */ + USER_POWER_ON = 0, + + /* + * Automatic power on triggered by door unlock or any other kind of automatic + * user detection. + */ + USER_UNLOCK = 1, + + /* + * Automatic power on triggered by timer. This only happens when AP has asked + * wake-up after + * certain time through time specified in + * VehicleApPowerSetState#SHUTDOWN_START. + */ + TIMER = 2, +}; + +enum VehicleHwKeyInputAction : int32_t { + /* Key down */ + ACTION_DOWN = 0, + + /* Key up */ + ACTION_UP = 1, +}; + +enum VehicleDisplay : int32_t { + /* center console */ + MAIN = 0, + + INSTRUMENT_CLUSTER = 1, +}; + +/* + * Represents instrument cluster type available in system + */ +enum VehicleInstrumentClusterType : int32_t { + /* Android has no access to instument cluster */ + NONE = 0, + + /* + * Instrument cluster can communicate through vehicle hal with additional + * properties to exchange meta-data + */ + HAL_INTERFACE = 1, + + /* + * Instrument cluster is external display where android can render contents + */ + EXTERNAL_DISPLAY = 2, +}; + +/* + * Units used for int or float type with no attached enum types. + */ +enum VehicleUnit : int32_t { + SHOULD_NOT_USE = 0x000, + + METER_PER_SEC = 0x01, + RPM = 0x02, + HERTZ = 0x03, + PERCENTILE = 0x10, + MILLIMETER = 0x20, + METER = 0x21, + KILOMETER = 0x23, + CELSIUS = 0x30, + FAHRENHEIT = 0x31, + KELVIN = 0x32, + MILLILITER = 0x40, + NANO_SECS = 0x50, + SECS = 0x53, + YEAR = 0x59, +}; + + /* + * This describes how value of property can change. + */ +enum VehiclePropertyChangeMode : int32_t { + /* + * Property of this type must never be changed. Subscription is not supported + * for these properties. + */ + STATIC = 0x00, + + /* + * Property of this type must be reported when there is a change. + * IVehicle#get call must return the current value. + * Set operation for this property is assumed to be asynchronous. When the + * property is read (using IVehicle#get) after IVehicle#set, it may still + * return old value until underlying H/W backing this property has actually + * changed the state. Once state is changed, the property must dispatch + * changed value as event. + */ + ON_CHANGE = 0x01, + + /* + * Property of this type change continuously and requires fixed rate of + * sampling to retrieve the data. + */ + CONTINUOUS = 0x02, + + /* + * Property of this type may be polled to get the current value. + */ + POLL = 0x03, + + /* + * This is for property where change event must be sent only when the + * value is set from external component. Normal value change must not trigger + * event. For example, clock property can send change event only when it is + * set, outside android, for case like user setting time or time getting + * update. There is no need to send it per every value change. + */ + ON_SET = 0x04, +}; + +/* + * Property config defines the capabilities of it. User of the API + * must first get the property config to understand the output from get() + * commands and also to ensure that set() or events commands are in sync with + * the expected output. + */ +enum VehiclePropertyAccess : int32_t { + NONE = 0x00, + + READ = 0x01, + WRITE = 0x02, + READ_WRITE = 0x03, +}; + +/* + * Car states. + * + * The driving states determine what features of the UI will be accessible. + */ +enum VehicleDrivingStatus : int32_t { + UNRESTRICTED = 0x00, + NO_VIDEO = 0x01, + NO_KEYBOARD_INPUT = 0x02, + NO_VOICE_INPUT = 0x04, + NO_CONFIG = 0x08, + LIMIT_MESSAGE_LEN = 0x10, +}; + +/* + * Various gears which can be selected by user and chosen in system. + */ +enum VehicleGear: int32_t { + GEAR_NEUTRAL = 0x0001, + GEAR_REVERSE = 0x0002, + GEAR_PARK = 0x0004, + GEAR_DRIVE = 0x0008, + GEAR_LOW = 0x0010, + GEAR_1 = 0x0010, + GEAR_2 = 0x0020, + GEAR_3 = 0x0040, + GEAR_4 = 0x0080, + GEAR_5 = 0x0100, + GEAR_6 = 0x0200, + GEAR_7 = 0x0400, + GEAR_8 = 0x0800, + GEAR_9 = 0x1000, +}; + +/* + * Various zones in the car. + * + * Zones are used for Air Conditioning purposes and divide the car into physical + * area zones. + */ +enum VehicleAreaZone : int32_t { + ROW_1_LEFT = 0x00000001, + ROW_1_CENTER = 0x00000002, + ROW_1_RIGHT = 0x00000004, + ROW_1 = 0x00000008, + ROW_2_LEFT = 0x00000010, + ROW_2_CENTER = 0x00000020, + ROW_2_RIGHT = 0x00000040, + ROW_2 = 0x00000080, + ROW_3_LEFT = 0x00000100, + ROW_3_CENTER = 0x00000200, + ROW_3_RIGHT = 0x00000400, + ROW_3 = 0x00000800, + ROW_4_LEFT = 0x00001000, + ROW_4_CENTER = 0x00002000, + ROW_4_RIGHT = 0x00004000, + ROW_4 = 0x00008000, + WHOLE_CABIN = 0x80000000, +}; + +/* + * Various Seats in the car. + */ +enum VehicleAreaSeat : int32_t { + ROW_1_LEFT = 0x0001, + ROW_1_CENTER = 0x0002, + ROW_1_RIGHT = 0x0004, + ROW_2_LEFT = 0x0010, + ROW_2_CENTER = 0x0020, + ROW_2_RIGHT = 0x0040, + ROW_3_LEFT = 0x0100, + ROW_3_CENTER = 0x0200, + ROW_3_RIGHT = 0x0400 +}; + +/* + * Various windshields/windows in the car. + */ +enum VehicleAreaWindow : int32_t { + FRONT_WINDSHIELD = 0x0001, + REAR_WINDSHIELD = 0x0002, + ROOF_TOP = 0x0004, + ROW_1_LEFT = 0x0010, + ROW_1_RIGHT = 0x0020, + ROW_2_LEFT = 0x0100, + ROW_2_RIGHT = 0x0200, + ROW_3_LEFT = 0x1000, + ROW_3_RIGHT = 0x2000, +}; + +enum VehicleAreaDoor : int32_t { + ROW_1_LEFT = 0x00000001, + ROW_1_RIGHT = 0x00000004, + ROW_2_LEFT = 0x00000010, + ROW_2_RIGHT = 0x00000040, + ROW_3_LEFT = 0x00000100, + ROW_3_RIGHT = 0x00000400, + HOOD = 0x10000000, + REAR = 0x20000000, +}; + +enum VehicleAreaMirror : int32_t { + DRIVER_LEFT = 0x00000001, + DRIVER_RIGHT = 0x00000002, + DRIVER_CENTER = 0x00000004, +}; + +enum VehicleTurnSignal : int32_t { + NONE = 0x00, + RIGHT = 0x01, + LEFT = 0x02, + EMERGENCY = 0x04, +}; + +struct VehicleAreaConfig { + /* + * Area id is ignored for VehiclePropertyGroup:GLOBAL properties. + */ + int32_t areaId; + + int32_t minInt32Value; + int32_t maxInt32Value; + + int64_t minInt64Value; + int64_t maxInt64Value; + + float minFloatValue; + float maxFloatValue; +}; + +struct VehiclePropConfig { + /* Property identifier */ + int32_t prop; + + /* + * Defines if the property is read or write or both. + */ + VehiclePropertyAccess access; + + /* + * Defines the change mode of the property. + */ + VehiclePropertyChangeMode changeMode; + + /* + * Some of the properties may have associated areas (for example, some hvac + * properties are associated with VehicleAreaZone), in these + * cases the config may contain an ORed value for the associated areas. + */ + int32_t supportedAreas; + + /* + * Contains per-area configuration. + */ + vec<VehicleAreaConfig> areaConfigs; + + /* + * Configuration flags for this property. + * + * For example, it may store the number of presets that are stored by the + * radio module. + */ + int32_t configFlags; + + /* Contains additional configuration parameters */ + vec<int32_t> configArray; + + /* + * Some properties may require additional information passed over this + * string. Most properties do not need to set this. + */ + string configString; + + /* + * Min sample rate in Hz. + * Must be defined for VehiclePropertyChangeMode::CONTINUOUS + */ + float minSampleRate; + + /* + * Must be defined for VehiclePropertyChangeMode::CONTINUOUS + * Max sample rate in Hz. + */ + float maxSampleRate; +}; + +/* + * Encapsulates the property name and the associated value. It + * is used across various API calls to set values, get values or to register for + * events. + */ +struct VehiclePropValue { + /* Property identifier */ + int32_t prop; + + /* Time is elapsed nanoseconds since boot */ + int64_t timestamp; + + /* + * Area type(s) for non-global property it must be one of the value from + * VehicleArea* enums or 0 for global properties. + */ + int32_t areaId; + + /* + * Contains value for a single property. Depending on property data type of + * this property (VehiclePropetyType) one field of this structure must be filled in. + */ + struct RawValue { + /* + * This is used for properties of types VehiclePropertyType#INT + * and VehiclePropertyType#INT_VEC + */ + vec<int32_t> int32Values; + + /* + * This is used for properties of types VehiclePropertyType#FLOAT + * and VehiclePropertyType#FLOAT_VEC + */ + vec<float> floatValues; + + /* This is used for properties of type VehiclePropertyType#INT64 */ + vec<int64_t> int64Values; + + /* This is used for properties of type VehiclePropertyType#BYTES */ + vec<uint8_t> bytes; + + /* This is used for properties of type VehiclePropertyType#STRING */ + string stringValue; + }; + + RawValue value; +}; + +enum VehicleIgnitionState : int32_t { + UNDEFINED = 0, + + /* Steering wheel is locked */ + LOCK = 1, + + /* + * Steering wheel is not locked, engine and all accessories are OFF. If + * car can be in LOCK and OFF state at the same time than HAL must report + * LOCK state. + */ + OFF, + + /* + * Typically in this state accessories become available (e.g. radio). + * Instrument cluster and engine are turned off + */ + ACC, + + /* + * Ignition is in state ON. Accessories and instrument cluster available, + * engine might be running or ready to be started. + */ + ON, + + /* Typically in this state engine is starting (cranking). */ + START +}; + + +/* + * Represent the operation where the current error has happened. + */ +enum VehiclePropertyOperation : int32_t { + /* + * Generic error to this property which is not tied to any operation. + */ + GENERIC = 0, + + /* + * Error happened while handling property set. + */ + SET = 1, + + /* + * Error happened while handling property get. + */ + GET = 2, + + /* + * Error happened while handling property subscription. + */ + SUBSCRIBE = 3, +}; + + +enum SubscribeFlags : int32_t { + UNDEFINED = 0x0, + + /* + * Subscribe to event that was originated in vehicle HAL + * (most likely this event came from the vehicle itself). + */ + HAL_EVENT = 0x1, + + /* + * Use this flag to subscribe on events when IVehicle#set(...) was called by + * vehicle HAL's client (e.g. Car Service). + */ + SET_CALL = 0x2, + + DEFAULT = HAL_EVENT, +}; + +/* + * Encapsulates information about subscription to vehicle property events. + */ +struct SubscribeOptions { + /* Property to subscribe */ + int32_t propId; + + /* + * Area ids - this must be a bit mask of areas to subscribe or 0 to subscribe + * to all areas. + */ + int32_t vehicleAreas; + + /* + * Sample rate in Hz. + * + * Must be provided for properties with + * VehiclePropertyChangeMode::CONTINUOUS. The value must be within + * VehiclePropConfig#minSamplingRate .. VehiclePropConfig#maxSamplingRate + * for a given property. + * This value indicates how many updates per second client wants to receive. + */ + float sampleRate; + + /* Flags that indicate what kind of events listen to. */ + SubscribeFlags flags; +}; + +/* Error codes used in vehicle HAL interface. */ +enum StatusCode : int32_t { + OK = 0, + + /* Try again. */ + TRY_AGAIN = 1, + + /* Invalid argument provided. */ + INVALID_ARG = 2, + + /* + * This code must be returned when device that associated with the vehicle + * property is not available. For example, when client tries to set HVAC + * temperature when the whole HVAC unit is turned OFF. + */ + NOT_AVAILABLE = 3, + + /* Access denied */ + ACCESS_DENIED = 4, + + /* Something unexpected has happened in Vehicle HAL */ + INTERNAL_ERROR = 5, +}; + +enum Wheel : int32_t { + UNKNOWN = 0x0, + + LEFT_FRONT = 0x1, + RIGHT_FRONT = 0x2, + LEFT_REAR = 0x4, + RIGHT_REAR = 0x8, +};
diff --git a/automotive/vehicle/2.1/Android.bp b/automotive/vehicle/2.1/Android.bp new file mode 100644 index 0000000..dcf395c --- /dev/null +++ b/automotive/vehicle/2.1/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.automotive.vehicle@2.1_hal", + srcs: [ + "types.hal", + "IVehicle.hal", + ], +} + +genrule { + name: "android.hardware.automotive.vehicle@2.1_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.1", + srcs: [ + ":android.hardware.automotive.vehicle@2.1_hal", + ], + out: [ + "android/hardware/automotive/vehicle/2.1/types.cpp", + "android/hardware/automotive/vehicle/2.1/VehicleAll.cpp", + ], +} + +genrule { + name: "android.hardware.automotive.vehicle@2.1_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.automotive.vehicle@2.1", + srcs: [ + ":android.hardware.automotive.vehicle@2.1_hal", + ], + out: [ + "android/hardware/automotive/vehicle/2.1/types.h", + "android/hardware/automotive/vehicle/2.1/IVehicle.h", + "android/hardware/automotive/vehicle/2.1/IHwVehicle.h", + "android/hardware/automotive/vehicle/2.1/BnHwVehicle.h", + "android/hardware/automotive/vehicle/2.1/BpHwVehicle.h", + "android/hardware/automotive/vehicle/2.1/BsVehicle.h", + ], +} + +cc_library_shared { + name: "android.hardware.automotive.vehicle@2.1", + generated_sources: ["android.hardware.automotive.vehicle@2.1_genc++"], + generated_headers: ["android.hardware.automotive.vehicle@2.1_genc++_headers"], + export_generated_headers: ["android.hardware.automotive.vehicle@2.1_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.automotive.vehicle@2.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.automotive.vehicle@2.0", + ], +}
diff --git a/automotive/vehicle/2.1/Android.mk b/automotive/vehicle/2.1/Android.mk new file mode 100644 index 0000000..f030af08 --- /dev/null +++ b/automotive/vehicle/2.1/Android.mk
@@ -0,0 +1,534 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.automotive.vehicle@2.1-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hardware.automotive.vehicle@2.0-java \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (CommonIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CommonIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.CommonIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CompressionIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CompressionIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.CompressionIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FuelSystemStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelSystemStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.FuelSystemStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FuelType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.FuelType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (IgnitionMonitorKind) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IgnitionMonitorKind.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.IgnitionMonitorKind + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2FloatSensorIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2FloatSensorIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.Obd2FloatSensorIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2IntegerSensorIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2IntegerSensorIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.Obd2IntegerSensorIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SecondaryAirStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SecondaryAirStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.SecondaryAirStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SparkIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SparkIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.SparkIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleProperty) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VehicleProperty.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.VehicleProperty + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.VmsMessageIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.VmsMessageType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IVehicle.hal +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IVehicle.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::IVehicle + +$(GEN): $(LOCAL_PATH)/IVehicle.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.automotive.vehicle@2.1-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hardware.automotive.vehicle@2.0-java-static \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (CommonIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CommonIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.CommonIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CompressionIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/CompressionIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.CompressionIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FuelSystemStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelSystemStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.FuelSystemStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FuelType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/FuelType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.FuelType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (IgnitionMonitorKind) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IgnitionMonitorKind.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.IgnitionMonitorKind + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2FloatSensorIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2FloatSensorIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.Obd2FloatSensorIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Obd2IntegerSensorIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/Obd2IntegerSensorIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.Obd2IntegerSensorIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SecondaryAirStatus) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SecondaryAirStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.SecondaryAirStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SparkIgnitionMonitors) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/SparkIgnitionMonitors.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.SparkIgnitionMonitors + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VehicleProperty) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VehicleProperty.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.VehicleProperty + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageIntegerValuesIndex) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageIntegerValuesIndex.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.VmsMessageIntegerValuesIndex + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VmsMessageType) +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::types.VmsMessageType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IVehicle.hal +# +GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IVehicle.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.automotive.vehicle@2.1::IVehicle + +$(GEN): $(LOCAL_PATH)/IVehicle.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/automotive/vehicle/2.1/IVehicle.hal b/automotive/vehicle/2.1/IVehicle.hal new file mode 100644 index 0000000..5b6a23f --- /dev/null +++ b/automotive/vehicle/2.1/IVehicle.hal
@@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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.automotive.vehicle@2.1; + +import android.hardware.automotive.vehicle@2.0; + +/* + * New revision of IVehicle interface that supports properties defined in + * VehicleProperty enum version 2.1. + * + * NOTE: this HAL interface is under development and shouldn't be used in + * production. + * + * TODO(pavelm): update comment when this interface is ready for prod. + */ +interface IVehicle extends @2.0::IVehicle { +};
diff --git a/automotive/vehicle/2.1/default/Android.mk b/automotive/vehicle/2.1/default/Android.mk new file mode 100644 index 0000000..3075956 --- /dev/null +++ b/automotive/vehicle/2.1/default/Android.mk
@@ -0,0 +1,122 @@ +# Copyright (C) 2016 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. + +LOCAL_PATH := $(call my-dir) + +vhal_v2_0 = android.hardware.automotive.vehicle@2.0 +vhal_v2_1 = android.hardware.automotive.vehicle@2.1 + +############################################################################### +# Vehicle reference implementation lib +############################################################################### +include $(CLEAR_VARS) +LOCAL_MODULE := $(vhal_v2_1)-manager-lib +LOCAL_SRC_FILES := \ + common/src/Obd2SensorStore.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/common/include/vhal_v2_1 \ + $(LOCAL_PATH)/../../2.0/default/common/include/vhal_v2_0 \ + +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/common/include + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + liblog \ + libutils \ + $(vhal_v2_1) \ + +include $(BUILD_STATIC_LIBRARY) + +############################################################################### +# Vehicle default VehicleHAL implementation +############################################################################### +include $(CLEAR_VARS) + +LOCAL_MODULE:= $(vhal_v2_1)-default-impl-lib +LOCAL_SRC_FILES:= \ + impl/vhal_v2_1/DefaultVehicleHal.cpp \ + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/impl/vhal_v2_1 \ + $(LOCAL_PATH)/common/include + +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/impl \ + $(LOCAL_PATH)/common/include + + +# LOCAL_WHOLE_STATIC_LIBRARIES := \ + +LOCAL_STATIC_LIBRARIES := \ + $(vhal_v2_0)-default-impl-lib \ + $(vhal_v2_0)-manager-lib \ + $(vhal_v2_1)-manager-lib \ + $(vhal_v2_0)-libproto-native + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libbinder \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + liblog \ + libutils \ + libprotobuf-cpp-lite \ + $(vhal_v2_0) \ + $(vhal_v2_1) \ + +LOCAL_CFLAGS += -Wall -Wextra -Werror + +include $(BUILD_STATIC_LIBRARY) + +############################################################################### +# Vehicle HAL service +############################################################################### +include $(CLEAR_VARS) +LOCAL_MODULE := $(vhal_v2_1)-service +LOCAL_INIT_RC := $(vhal_v2_1)-service.rc +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_SRC_FILES := \ + service.cpp + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + $(vhal_v2_0)-libproto-native \ + +LOCAL_STATIC_LIBRARIES := \ + $(vhal_v2_0)-manager-lib \ + $(vhal_v2_0)-default-impl-lib \ + $(vhal_v2_1)-default-impl-lib \ + $(vhal_v2_1)-manager-lib \ + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libbinder \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + liblog \ + libutils \ + libprotobuf-cpp-lite \ + $(vhal_v2_0) \ + $(vhal_v2_1) \ + +LOCAL_CFLAGS += -Wall -Wextra -Werror + +include $(BUILD_EXECUTABLE)
diff --git a/automotive/vehicle/2.1/default/android.hardware.automotive.vehicle@2.1-service.rc b/automotive/vehicle/2.1/default/android.hardware.automotive.vehicle@2.1-service.rc new file mode 100644 index 0000000..8929d25 --- /dev/null +++ b/automotive/vehicle/2.1/default/android.hardware.automotive.vehicle@2.1-service.rc
@@ -0,0 +1,4 @@ +service vehicle-hal-2.1 /vendor/bin/hw/android.hardware.automotive.vehicle@2.1-service + class hal + user vehicle_network + group system inet
diff --git a/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h b/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h new file mode 100644 index 0000000..945e3e0 --- /dev/null +++ b/automotive/vehicle/2.1/default/common/include/vhal_v2_1/Obd2SensorStore.h
@@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_1_Obd2SensorStore_H_ +#define android_hardware_automotive_vehicle_V2_1_Obd2SensorStore_H_ + +#include <vector> + +#include <android/hardware/automotive/vehicle/2.1/types.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_1 { + +// This class wraps all the logic required to create an OBD2 frame. +// It allows storing sensor values, setting appropriate bitmasks as needed, +// and returning appropriately laid out storage of sensor values suitable +// for being returned via a VehicleHal implementation. +class Obd2SensorStore { +public: + // Creates a sensor storage with a given number of vendor-specific sensors. + Obd2SensorStore(size_t numVendorIntegerSensors, + size_t numVendorFloatSensors); + + // Stores an integer-valued sensor. + V2_0::StatusCode setIntegerSensor(Obd2IntegerSensorIndex index, int32_t value); + // Stores an integer-valued sensor. + V2_0::StatusCode setIntegerSensor(size_t index, int32_t value); + + // Stores a float-valued sensor. + V2_0::StatusCode setFloatSensor(Obd2FloatSensorIndex index, float value); + // Stores a float-valued sensor. + V2_0::StatusCode setFloatSensor(size_t index, float value); + + // Returns a vector that contains all integer sensors stored. + const std::vector<int32_t>& getIntegerSensors() const; + // Returns a vector that contains all float sensors stored. + const std::vector<float>& getFloatSensors() const; + // Returns a vector that contains a bitmask for all stored sensors. + const std::vector<uint8_t>& getSensorsBitmask() const; + + // Given a stringValue, fill in a VehiclePropValue + void fillPropValue(V2_0::VehiclePropValue *propValue, + std::string dtc) const; + +private: + class BitmaskInVector { + public: + BitmaskInVector(size_t numBits = 0); + void resize(size_t numBits); + bool get(size_t index) const; + void set(size_t index, bool value); + + const std::vector<uint8_t>& getBitmask() const; + + private: + std::vector<uint8_t> mStorage; + }; + + std::vector<int32_t> mIntegerSensors; + std::vector<float> mFloatSensors; + BitmaskInVector mSensorsBitmask; +}; + +} // namespace V2_1 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_0_Obd2SensorStore_H_
diff --git a/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp b/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp new file mode 100644 index 0000000..b07717b --- /dev/null +++ b/automotive/vehicle/2.1/default/common/src/Obd2SensorStore.cpp
@@ -0,0 +1,117 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "Obd2SensorStore.h" + +#include <utils/SystemClock.h> +#include "VehicleUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_1 { + +Obd2SensorStore::BitmaskInVector::BitmaskInVector(size_t numBits) +{ + resize(numBits); +} + +void Obd2SensorStore::BitmaskInVector::resize(size_t numBits) { + mStorage = std::vector<uint8_t>((numBits+7)/8, 0); +} + +void Obd2SensorStore::BitmaskInVector::set(size_t index, bool value) { + const size_t byteIndex = index / 8; + const size_t bitIndex = index % 8; + const uint8_t byte = mStorage[byteIndex]; + uint8_t newValue = value ? (byte | (1 << bitIndex)) : + (byte & ~(1 << bitIndex)); + mStorage[byteIndex] = newValue; +} + +bool Obd2SensorStore::BitmaskInVector::get(size_t index) const { + const size_t byteIndex = index / 8; + const size_t bitIndex = index % 8; + const uint8_t byte = mStorage[byteIndex]; + return (byte & (1 << bitIndex)) != 0; +} + +const std::vector<uint8_t>& Obd2SensorStore::BitmaskInVector::getBitmask() const { + return mStorage; +} + +Obd2SensorStore::Obd2SensorStore(size_t numVendorIntegerSensors, + size_t numVendorFloatSensors) { + // because the last index is valid *inclusive* + const size_t numSystemIntegerSensors = V2_0::toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)+1; + const size_t numSystemFloatSensors = V2_0::toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)+1; + mIntegerSensors = std::vector<int32_t>( + numSystemIntegerSensors+numVendorIntegerSensors, 0); + mFloatSensors = std::vector<float>( + numSystemFloatSensors+numVendorFloatSensors, 0); + mSensorsBitmask.resize(mIntegerSensors.size()+mFloatSensors.size()); +} + +V2_0::StatusCode Obd2SensorStore::setIntegerSensor(Obd2IntegerSensorIndex index, + int32_t value) { + return setIntegerSensor(V2_0::toInt(index), value); +} +V2_0::StatusCode Obd2SensorStore::setFloatSensor(Obd2FloatSensorIndex index, + float value) { + return setFloatSensor(V2_0::toInt(index), value); +} + +V2_0::StatusCode Obd2SensorStore::setIntegerSensor(size_t index, int32_t value) { + mIntegerSensors[index] = value; + mSensorsBitmask.set(index, true); + return V2_0::StatusCode::OK; +} + +V2_0::StatusCode Obd2SensorStore::setFloatSensor(size_t index, float value) { + mFloatSensors[index] = value; + mSensorsBitmask.set(index + mIntegerSensors.size(), true); + return V2_0::StatusCode::OK; +} + +const std::vector<int32_t>& Obd2SensorStore::getIntegerSensors() const { + return mIntegerSensors; +} + +const std::vector<float>& Obd2SensorStore::getFloatSensors() const { + return mFloatSensors; +} + +const std::vector<uint8_t>& Obd2SensorStore::getSensorsBitmask() const { + return mSensorsBitmask.getBitmask(); +} + +void Obd2SensorStore::fillPropValue(V2_0::VehiclePropValue *propValue, + std::string dtc) const { + propValue->timestamp = elapsedRealtimeNano(); + propValue->value.int32Values = getIntegerSensors(); + propValue->value.floatValues = getFloatSensors(); + propValue->value.bytes = getSensorsBitmask(); + propValue->value.stringValue = dtc; +} + + + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h new file mode 100644 index 0000000..6bdec59 --- /dev/null +++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h
@@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_1_impl_DefaultConfig_H_ +#define android_hardware_automotive_vehicle_V2_1_impl_DefaultConfig_H_ + +#include <android/hardware/automotive/vehicle/2.1/types.h> +#include <vhal_v2_0/VehicleUtils.h> + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_1 { + +namespace impl { + +const V2_0::VehiclePropConfig kVehicleProperties[] = { + { + .prop = V2_0::toInt(V2_1::VehicleProperty::WHEEL_TICK), + .access = V2_0::VehiclePropertyAccess::READ, + .changeMode = V2_0::VehiclePropertyChangeMode::CONTINUOUS, + }, + + { + .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_LIVE_FRAME), + .access = V2_0::VehiclePropertyAccess::READ, + .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {0,0} + }, + + { + .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME), + .access = V2_0::VehiclePropertyAccess::READ, + .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE, + .configArray = {0,0} + }, + + { + .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO), + .access = V2_0::VehiclePropertyAccess::READ, + .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE + }, + + { + .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR), + .access = V2_0::VehiclePropertyAccess::WRITE, + .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE + }, + + { + .prop = V2_0::toInt(VehicleProperty::VEHICLE_MAP_SERVICE), + .access = V2_0::VehiclePropertyAccess::READ_WRITE, + .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE + } +}; + +} // impl + +} // namespace V2_1 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // android_hardware_automotive_vehicle_V2_1_impl_DefaultConfig_H_
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.cpp b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.cpp new file mode 100644 index 0000000..d4eae7f --- /dev/null +++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.cpp
@@ -0,0 +1,289 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "DefaultVehicleHal_v2_1" +#include <android/log.h> + +#include <algorithm> +#include <netinet/in.h> +#include <sys/socket.h> + +#include "DefaultVehicleHal.h" +#include "VehicleHalProto.pb.h" + +#define DEBUG_SOCKET (33452) + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_1 { + +namespace impl { + +static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame( + size_t numVendorIntegerSensors, + size_t numVendorFloatSensors) { + std::unique_ptr<Obd2SensorStore> sensorStore(new Obd2SensorStore( + numVendorIntegerSensors, numVendorFloatSensors)); + + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS, + V2_0::toInt(FuelSystemStatus::CLOSED_LOOP)); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::IGNITION_MONITORS_SUPPORTED, + V2_0::toInt(IgnitionMonitorKind::SPARK)); + sensorStore->setIntegerSensor(Obd2IntegerSensorIndex::IGNITION_SPECIFIC_MONITORS, + CommonIgnitionMonitors::COMPONENTS_AVAILABLE | + CommonIgnitionMonitors::MISFIRE_AVAILABLE | + SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE | + SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS, + V2_0::toInt(SecondaryAirStatus::FROM_OUTSIDE_OR_OFF)); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1); + sensorStore->setIntegerSensor( + Obd2IntegerSensorIndex::FUEL_TYPE, V2_0::toInt(FuelType::GASOLINE)); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::ENGINE_RPM, 1250.); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::VEHICLE_SPEED, 40.); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::TIMING_ADVANCE, 2.5); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::THROTTLE_POSITION, 19.75); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE, -0.373); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1, 190.); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094); + sensorStore->setFloatSensor( + Obd2FloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024); + + return sensorStore; +} + +void DefaultVehicleHal::initObd2LiveFrame(V2_0::VehiclePropConfig& propConfig) { + auto sensorStore = fillDefaultObd2Frame(propConfig.configArray[0], + propConfig.configArray[1]); + mLiveObd2Frame = createVehiclePropValue( + V2_0::VehiclePropertyType::COMPLEX, 0); + sensorStore->fillPropValue(mLiveObd2Frame.get(), ""); +} + +void DefaultVehicleHal::initObd2FreezeFrame(V2_0::VehiclePropConfig& propConfig) { + auto sensorStore = fillDefaultObd2Frame(propConfig.configArray[0], + propConfig.configArray[1]); + + mFreezeObd2Frames.push_back( + createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0)); + mFreezeObd2Frames.push_back( + createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0)); + mFreezeObd2Frames.push_back( + createVehiclePropValue(V2_0::VehiclePropertyType::COMPLEX,0)); + + sensorStore->fillPropValue(mFreezeObd2Frames[0].get(), "P0070"); + sensorStore->fillPropValue(mFreezeObd2Frames[1].get(), "P0102"); + sensorStore->fillPropValue(mFreezeObd2Frames[2].get(), "P0123"); +} + +V2_0::StatusCode DefaultVehicleHal::fillObd2LiveFrame(V2_0::VehiclePropValue* v) { + v->prop = V2_0::toInt(VehicleProperty::OBD2_LIVE_FRAME); + v->value.int32Values = mLiveObd2Frame->value.int32Values; + v->value.floatValues = mLiveObd2Frame->value.floatValues; + v->value.bytes = mLiveObd2Frame->value.bytes; + return V2_0::StatusCode::OK; +} + +template<typename Iterable> +typename Iterable::const_iterator findPropValueAtTimestamp( + const Iterable& frames, + int64_t timestamp) { + return std::find_if(frames.begin(), + frames.end(), + [timestamp] (const std::unique_ptr<V2_0::VehiclePropValue>& + propValue) -> bool { + return propValue->timestamp == timestamp; + }); +} + +V2_0::StatusCode DefaultVehicleHal::fillObd2FreezeFrame( + const V2_0::VehiclePropValue& requestedPropValue, + V2_0::VehiclePropValue* v) { + if (requestedPropValue.value.int64Values.size() != 1) { + ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp"); + return V2_0::StatusCode::INVALID_ARG; + } + auto timestamp = requestedPropValue.value.int64Values[0]; + auto freezeFrameIter = findPropValueAtTimestamp(mFreezeObd2Frames, + timestamp); + if(mFreezeObd2Frames.end() == freezeFrameIter) { + ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp"); + return V2_0::StatusCode::INVALID_ARG; + } + const auto& freezeFrame = *freezeFrameIter; + v->prop = V2_0::toInt(VehicleProperty::OBD2_FREEZE_FRAME); + v->value.int32Values = freezeFrame->value.int32Values; + v->value.floatValues = freezeFrame->value.floatValues; + v->value.bytes = freezeFrame->value.bytes; + v->value.stringValue = freezeFrame->value.stringValue; + v->timestamp = freezeFrame->timestamp; + return V2_0::StatusCode::OK; +} + +V2_0::StatusCode DefaultVehicleHal::clearObd2FreezeFrames( + const V2_0::VehiclePropValue& propValue) { + if (propValue.value.int64Values.size() == 0) { + mFreezeObd2Frames.clear(); + return V2_0::StatusCode::OK; + } else { + for(int64_t timestamp: propValue.value.int64Values) { + auto freezeFrameIter = findPropValueAtTimestamp(mFreezeObd2Frames, + timestamp); + if(mFreezeObd2Frames.end() == freezeFrameIter) { + ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp"); + return V2_0::StatusCode::INVALID_ARG; + } + mFreezeObd2Frames.erase(freezeFrameIter); + } + } + return V2_0::StatusCode::OK; +} + +V2_0::StatusCode DefaultVehicleHal::fillObd2DtcInfo(V2_0::VehiclePropValue* v) { + std::vector<int64_t> timestamps; + for(const auto& freezeFrame: mFreezeObd2Frames) { + timestamps.push_back(freezeFrame->timestamp); + } + v->value.int64Values = timestamps; + return V2_0::StatusCode::OK; +} + +void DefaultVehicleHal::onCreate() { + mVehicleHal20->init(getValuePool(), + std::bind(&DefaultVehicleHal::doHalEvent, this, _1), + std::bind(&DefaultVehicleHal::doHalPropertySetError, this, _1, _2, _3)); + + std::vector<V2_0::VehiclePropConfig> configs = listProperties(); + for (auto& cfg : configs) { + switch(cfg.prop) { + case V2_0::toInt(V2_1::VehicleProperty::OBD2_LIVE_FRAME): + initObd2LiveFrame(cfg); + break; + case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME): + initObd2FreezeFrame(cfg); + break; + default: + break; + } + } +} + +DefaultVehicleHal::VehiclePropValuePtr DefaultVehicleHal::get( + const V2_0::VehiclePropValue& requestedPropValue, + V2_0::StatusCode* outStatus) { + + auto propId = requestedPropValue.prop; + VehiclePropValuePtr v = nullptr; + auto& pool = *getValuePool(); + + switch (propId) { + case V2_0::toInt(V2_1::VehicleProperty::OBD2_LIVE_FRAME): + v = pool.obtainComplex(); + *outStatus = fillObd2LiveFrame(v.get()); + return v; + case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME): + v = pool.obtainComplex(); + *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get()); + return v; + case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_INFO): + v = pool.obtainComplex(); + *outStatus = fillObd2DtcInfo(v.get()); + return v; + default: + return mVehicleHal20->get(requestedPropValue, outStatus); + } +} + +V2_0::StatusCode DefaultVehicleHal::set( + const V2_0::VehiclePropValue& propValue) { + + auto propId = propValue.prop; + switch (propId) { + case V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR): + return clearObd2FreezeFrames(propValue); + break; + case V2_0::toInt(V2_1::VehicleProperty::VEHICLE_MAP_SERVICE): + // Placeholder for future implementation of VMS property in the default hal. For now, just + // returns OK; otherwise, hal clients crash with property not supported. + return V2_0::StatusCode::OK; + break; + default: + return mVehicleHal20->set(propValue); + } +} + +} // impl + +} // namespace V2_1 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.h new file mode 100644 index 0000000..ac65fc6 --- /dev/null +++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultVehicleHal.h
@@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_automotive_vehicle_V2_1_impl_DefaultVehicleHal_H_ +#define android_hardware_automotive_vehicle_V2_1_impl_DefaultVehicleHal_H_ + +#include <memory> + +#include <utils/SystemClock.h> + +#include <vhal_v2_0/VehicleHal.h> +#include <vhal_v2_0/DefaultVehicleHal.h> +#include <vhal_v2_1/Obd2SensorStore.h> + +#include "DefaultConfig.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_1 { + +namespace impl { + +using namespace std::placeholders; + +class DefaultVehicleHal : public V2_0::VehicleHal { +public: + DefaultVehicleHal(V2_0::VehicleHal* vhal20) : mVehicleHal20(vhal20) {} + + std::vector<V2_0::VehiclePropConfig> listProperties() override { + std::vector<V2_0::VehiclePropConfig> propConfigs(mVehicleHal20->listProperties()); + + // Join Vehicle Hal 2.0 and 2.1 configs. + propConfigs.insert(propConfigs.end(), + std::begin(kVehicleProperties), + std::end(kVehicleProperties)); + + return propConfigs; + } + + VehiclePropValuePtr get(const V2_0::VehiclePropValue& requestedPropValue, + V2_0::StatusCode* outStatus) override; + + V2_0::StatusCode set(const V2_0::VehiclePropValue& propValue) override; + + V2_0::StatusCode subscribe(int32_t property, + int32_t areas, + float sampleRate) override { + return mVehicleHal20->subscribe(property, areas, sampleRate); + } + + V2_0::StatusCode unsubscribe(int32_t property) override { + return mVehicleHal20->unsubscribe(property); + } + + void onCreate() override; + +private: + void initObd2LiveFrame(V2_0::VehiclePropConfig& propConfig); + void initObd2FreezeFrame(V2_0::VehiclePropConfig& propConfig); + V2_0::StatusCode fillObd2LiveFrame(V2_0::VehiclePropValue* v); + V2_0::StatusCode fillObd2FreezeFrame(const V2_0::VehiclePropValue& requestedPropValue, + V2_0::VehiclePropValue* v); + V2_0::StatusCode fillObd2DtcInfo(V2_0::VehiclePropValue *v); + V2_0::StatusCode clearObd2FreezeFrames(const V2_0::VehiclePropValue& propValue); + +private: + V2_0::VehicleHal* mVehicleHal20; + std::unique_ptr<V2_0::VehiclePropValue> mLiveObd2Frame {nullptr}; + std::vector<std::unique_ptr<V2_0::VehiclePropValue>> mFreezeObd2Frames; +}; + +} // impl + +} // namespace V2_1 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + +#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
diff --git a/automotive/vehicle/2.1/default/service.cpp b/automotive/vehicle/2.1/default/service.cpp new file mode 100644 index 0000000..0844622 --- /dev/null +++ b/automotive/vehicle/2.1/default/service.cpp
@@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "automotive.vehicle@2.1-service" +#include <android/log.h> +#include <hidl/HidlTransportSupport.h> + +#include <iostream> + +#include <android/hardware/automotive/vehicle/2.1/IVehicle.h> + +#include <vhal_v2_0/VehicleHalManager.h> +#include <vhal_v2_0/DefaultVehicleHal.h> + +#include <vhal_v2_1/DefaultVehicleHal.h> + +using namespace android; +using namespace android::hardware; + +namespace V2_1 = ::android::hardware::automotive::vehicle::V2_1; +namespace V2_0 = ::android::hardware::automotive::vehicle::V2_0; + +using StatusCode = V2_0::StatusCode; +using VehiclePropValue = V2_0::VehiclePropValue; + +/* Just wrapper that passes all calls to the provided V2_0::IVehicle object */ +struct Vehicle_V2_1 : public V2_1::IVehicle { + + Vehicle_V2_1(V2_0::IVehicle* vehicle20) : mVehicle20(vehicle20) {} + + // Methods derived from IVehicle + Return<void> getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) override { + return mVehicle20->getAllPropConfigs(_hidl_cb); + } + + Return<void> getPropConfigs(const hidl_vec<int32_t>& properties, + getPropConfigs_cb _hidl_cb) override { + return mVehicle20->getPropConfigs(properties, _hidl_cb); + } + + Return<void> get(const V2_0::VehiclePropValue& requestedPropValue, + get_cb _hidl_cb) override { + return mVehicle20->get(requestedPropValue, _hidl_cb); + } + + Return<StatusCode> set(const VehiclePropValue& value) override { + return mVehicle20->set(value); + } + + Return<StatusCode> subscribe(const sp<V2_0::IVehicleCallback>& callback, + const hidl_vec<V2_0::SubscribeOptions>& + options) override { + return mVehicle20->subscribe(callback, options); + } + + Return<StatusCode> unsubscribe(const sp<V2_0::IVehicleCallback>& callback, + int32_t propId) override { + return mVehicle20->unsubscribe(callback, propId); + } + + Return<void> debugDump(debugDump_cb _hidl_cb = nullptr) override { + return mVehicle20->debugDump(_hidl_cb); + } + +private: + V2_0::IVehicle* mVehicle20; +}; + +int main(int /* argc */, char* /* argv */ []) { + auto halImpl20 = std::make_unique<V2_0::impl::DefaultVehicleHal>(); + auto halImpl21 = std::make_unique<V2_1::impl::DefaultVehicleHal>(halImpl20.get()); + + auto vehicleManager = std::make_unique<V2_0::VehicleHalManager>(halImpl21.get()); + + Vehicle_V2_1 vehicle21(vehicleManager.get()); + + ALOGI("Registering as service..."); + vehicle21.registerAsService(); + + configureRpcThreadpool(1, true /* callerWillJoin */); + + ALOGI("Ready"); + joinRpcThreadpool(); +}
diff --git a/automotive/vehicle/2.1/default/tests/Obd2SensorStore_test.cpp b/automotive/vehicle/2.1/default/tests/Obd2SensorStore_test.cpp new file mode 100644 index 0000000..a01c0f4 --- /dev/null +++ b/automotive/vehicle/2.1/default/tests/Obd2SensorStore_test.cpp
@@ -0,0 +1,285 @@ +/* + * Copyright (C) 2017 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. + */ + + #include <gtest/gtest.h> + +#include "vhal_v2_0/Obd2SensorStore.h" +#include "vhal_v2_0/VehicleUtils.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace { + +static constexpr size_t getNumVendorIntegerSensors() { + return 5; +} +static constexpr size_t getNumVendorFloatSensors() { + return 3; +} + +// this struct holds information necessary for a test to be able to validate +// that the sensor bitmask contains the right data: +// - the index of the byte at which the bit for a given sensor lives +// - the expected value of that byte given that a certain sensor is present +class BitmaskIndexingInfo { +public: + size_t mByteIndex; + uint8_t mExpectedByteValue; + + // Returns the information required to validate the bitmask for an + // integer-valued sensor. + static BitmaskIndexingInfo getForIntegerSensor(size_t index) { + const size_t indexInBitstream = index; + return getForBitstreamIndex(indexInBitstream); + } + + // Returns the information required to validate the bitmask for a + // float-valued sensor. + static BitmaskIndexingInfo getForFloatSensor(size_t index) { + const size_t indexInBitstream = toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX) + + 1 + getNumVendorIntegerSensors() + index; + return getForBitstreamIndex(indexInBitstream); + } + +private: + static BitmaskIndexingInfo getForBitstreamIndex(size_t indexInBitstream) { + BitmaskIndexingInfo indexingInfo; + indexingInfo.mByteIndex = indexInBitstream / 8; + indexingInfo.mExpectedByteValue = 1 << (indexInBitstream % 8); + return indexingInfo; + } +}; + +static Obd2SensorStore getSensorStore() { + return Obd2SensorStore(getNumVendorIntegerSensors(), + getNumVendorFloatSensors()); +} + +// Test that one can set and retrieve a value for the first integer sensor. +TEST(Obd2SensorStoreTest, setFirstIntegerSensor) { + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setIntegerSensor( + Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS, + toInt(FuelSystemStatus::CLOSED_LOOP)); + const auto& integerSensors(sensorStore.getIntegerSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ( + toInt(FuelSystemStatus::CLOSED_LOOP), + integerSensors[toInt(Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS)]); + const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor( + toInt(Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS))); + ASSERT_EQ( + indexingInfo.mExpectedByteValue, + sensorBitmask[indexingInfo.mByteIndex]); +} + +// Test that one can set and retrieve a value for the first float sensor. +TEST(Obd2SensorStoreTest, setFirstFloatSensor) { + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setFloatSensor( + Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD, + 1.25f); + const auto& floatSensors(sensorStore.getFloatSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ( + 1.25f, + floatSensors[toInt(Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD)]); + const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor( + toInt(Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD))); + ASSERT_EQ( + indexingInfo.mExpectedByteValue, + sensorBitmask[indexingInfo.mByteIndex]); +} + +// Test that one can set and retrieve a value for an integer sensor. +TEST(Obd2SensorStoreTest, setAnyIntegerSensor) { + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setIntegerSensor( + Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, + 4000); + const auto& integerSensors(sensorStore.getIntegerSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ(4000, + integerSensors[toInt(Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE)]); + const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor( + toInt(Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE))); + ASSERT_EQ( + indexingInfo.mExpectedByteValue, + sensorBitmask[indexingInfo.mByteIndex]); +} + +// Test that one can set and retrieve a value for a float sensor. +TEST(Obd2SensorStoreTest, setAnyFloatSensor) { + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setFloatSensor( + Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE, + 2.5f); + const auto& floatSensors(sensorStore.getFloatSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ(2.5f, + floatSensors[toInt(Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE)]); + const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor( + toInt(Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE))); + ASSERT_EQ( + indexingInfo.mExpectedByteValue, + sensorBitmask[indexingInfo.mByteIndex]); +} + +// Test that one can set and retrieve a value for the last system integer sensor. +TEST(Obd2SensorStoreTest, setLastSystemIntegerSensor) { + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setIntegerSensor( + Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX, + 30); + const auto& integerSensors(sensorStore.getIntegerSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ(30, + integerSensors[toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)]); + const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor( + toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX))); + ASSERT_EQ( + indexingInfo.mExpectedByteValue, + sensorBitmask[indexingInfo.mByteIndex]); +} + +// Test that one can set and retrieve a value for the last system float sensor. +TEST(Obd2SensorStoreTest, setLastSystemFloatSensor) { + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setFloatSensor( + Obd2FloatSensorIndex::LAST_SYSTEM_INDEX, + 2.5f); + const auto& floatSensors(sensorStore.getFloatSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ(2.5f, + floatSensors[toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)]); + const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor( + toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX))); + ASSERT_EQ( + indexingInfo.mExpectedByteValue, + sensorBitmask[indexingInfo.mByteIndex]); +} + +// Test that one can set and retrieve a value for two integer sensors at once. +TEST(Obd2SensorStoreTest, setTwoIntegerSensors) { + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setIntegerSensor( + Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE, + 6); + sensorStore.setIntegerSensor( + Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED, + 1245); + const auto& integerSensors(sensorStore.getIntegerSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ(6, + integerSensors[toInt(Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE)]); + ASSERT_EQ(1245, + integerSensors[toInt(Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED)]); + const BitmaskIndexingInfo voltageIndexingInfo(BitmaskIndexingInfo::getForIntegerSensor( + toInt(Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE))); + const BitmaskIndexingInfo timeIndexingInfo(BitmaskIndexingInfo::getForIntegerSensor( + toInt(Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED))); + if (voltageIndexingInfo.mByteIndex == timeIndexingInfo.mByteIndex) { + ASSERT_EQ( + voltageIndexingInfo.mExpectedByteValue | + timeIndexingInfo.mExpectedByteValue, + sensorBitmask[timeIndexingInfo.mByteIndex]); + } + else { + ASSERT_EQ( + timeIndexingInfo.mExpectedByteValue, + sensorBitmask[timeIndexingInfo.mByteIndex]); + ASSERT_EQ( + voltageIndexingInfo.mExpectedByteValue, + sensorBitmask[voltageIndexingInfo.mByteIndex]); + } +} + +// Test that one can set and retrieve a value for two float sensors at once. +TEST(Obd2SensorStoreTest, setTwoFloatSensors) { + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setFloatSensor( + Obd2FloatSensorIndex::VEHICLE_SPEED, + 1.25f); + sensorStore.setFloatSensor( + Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE, + 2.5f); + const auto& floatSensors(sensorStore.getFloatSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ(1.25f, + floatSensors[toInt(Obd2FloatSensorIndex::VEHICLE_SPEED)]); + ASSERT_EQ(2.5f, + floatSensors[toInt(Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE)]); + const BitmaskIndexingInfo speedIndexingInfo(BitmaskIndexingInfo::getForFloatSensor( + toInt(Obd2FloatSensorIndex::VEHICLE_SPEED))); + const BitmaskIndexingInfo airflowIndexingInfo(BitmaskIndexingInfo::getForFloatSensor( + toInt(Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE))); + if (speedIndexingInfo.mByteIndex == airflowIndexingInfo.mByteIndex) { + ASSERT_EQ( + speedIndexingInfo.mExpectedByteValue | + airflowIndexingInfo.mExpectedByteValue, + sensorBitmask[airflowIndexingInfo.mByteIndex]); + } + else { + ASSERT_EQ( + speedIndexingInfo.mExpectedByteValue, + sensorBitmask[speedIndexingInfo.mByteIndex]); + ASSERT_EQ( + airflowIndexingInfo.mExpectedByteValue, + sensorBitmask[airflowIndexingInfo.mByteIndex]); + } +} + +// Test that one can set and retrieve a value for a vendor integer sensor. +TEST(Obd2SensorStoreTest, setVendorIntegerSensor) { + const size_t sensorIndex = toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX) + 2; + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setIntegerSensor(sensorIndex, 22); + const auto& integerSensors(sensorStore.getIntegerSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ(22, integerSensors[sensorIndex]); + const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor( + sensorIndex)); + ASSERT_EQ( + indexingInfo.mExpectedByteValue, + sensorBitmask[indexingInfo.mByteIndex]); +} + +// Test that one can set and retrieve a value for a vendor float sensor. +TEST(Obd2SensorStoreTest, setVendorFloatSensor) { + const size_t sensorIndex = toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX) + 2; + Obd2SensorStore sensorStore(getSensorStore()); + sensorStore.setFloatSensor(sensorIndex, 1.25f); + const auto& floatSensors(sensorStore.getFloatSensors()); + const auto& sensorBitmask(sensorStore.getSensorsBitmask()); + ASSERT_EQ(1.25f, floatSensors[sensorIndex]); + const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor( + sensorIndex)); + ASSERT_EQ( + indexingInfo.mExpectedByteValue, + sensorBitmask[indexingInfo.mByteIndex]); +} + +} // namespace anonymous + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android
diff --git a/automotive/vehicle/2.1/types.hal b/automotive/vehicle/2.1/types.hal new file mode 100644 index 0000000..9b219b2 --- /dev/null +++ b/automotive/vehicle/2.1/types.hal
@@ -0,0 +1,605 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.1 (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.1 + * + * 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.automotive.vehicle@2.1; + +import android.hardware.automotive.vehicle@2.0; + +/* + * Extension of VehicleProperty enum declared in Vehicle HAL 2.0 + */ +enum VehicleProperty: @2.0::VehicleProperty { + /* + * Reports wheel rotational distance in meters since last wheel tick + * event + * + * The value is a vector each element represents distance for individual + * wheel in the following order: left front, right front, left rear, + * right rear. VehiclePropValue.timestamp must be correctly filled in. + * + * Vendors must specify wheels that support this sensor in + * VehiclePropConfig.configFlags. The format of this field is a bitset of + * values from Wheel enum. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE |VehiclePropertyChangeMode:CONTINUOUS + * @access VehiclePropertyAccess:READ + * @unit VehicleUnit:METER + */ + WHEEL_TICK = ( + 0x0306 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:FLOAT_VEC + | VehicleArea:GLOBAL), + + /* + * OBD2 Live Sensor Data + * + * This property uses COMPLEX data to send a snapshot of the current (live) + * values of the OBD2 sensors provided by the vehicle. + * + * VehiclePropConfig + * configArray[0] : number of vendor-specific integer-valued sensors + * that can be returned in a frame. + * configArray[1] : number of vendor-specific float-valued sensors + * that can be returned in a frame. + * + * The values are to be interpreted as follows: + * the indices defined in Obd2IntegerSensorIndex are to be used to + * read from int32Values; + * the indices defined in Obd2FloatSensorIndex are to be used to + * read from floatValues. + * the elements of bytes are to be interpreted as a bitmask, such that + * the bits 0 thru the integer value of + * Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[0] + * are 1 if the corresponding index is a valid sensor index whose value can + * be read in the returned int32Values vector, 0 otherwise. + * the bits Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX+1 thru + * Obd2FloatingSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[1] + * are 1 if the corresponding index is a valid sensor index whose value + * can be read in the returned floatValues vector, 0 otherwise. + * + * For example, int32Values[0] corresponds to FUEL_SYSTEM_STATUS, and + * floatValues[0] corresponds to CALCULATED_ENGINE_LOAD, but that mapping + * is only valid if the corresponding bits in the bytes vector are set to 1. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + OBD2_LIVE_FRAME = ( + 0x0D00 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), + + /* + * OBD2 Freeze Frame Sensor Data + * + * This property uses COMPLEX data to send a snapshot of the values of the + * OBD2 sensors provided by the vehicle at the time that a diagnostic + * troubleshooting code (DTC) was recorded by the vehicle. + * + * VehiclePropConfig + * configArray[0] : number of vendor-specific integer-valued sensors + * that can be returned in a frame. + * configArray[1] : number of vendor-specific float-valued sensors + * that can be returned in a frame. + * + * A get of this property must take the following form: + * int64Values[0]: timestamp of the freeze frame to retrieve. + * Valid timestamps are given by OBD2_DTC_INFO. + * + * The values are to be interpreted as follows: + * the indices defined in Obd2IntegerSensorIndex are to be used to + * read from int32Values; + * the indices defined in Obd2FloatSensorIndex are to be used to + * read from floatValues; + * the elements of bytes are to be interpreted as a bitmask, such that + * the bits 0 thru the integer value of + * Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[0] + * are 1 if the corresponding index is a valid sensor index whose value can + * be read in the returned int32Values vector, 0 otherwise. + * the bits Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX+1 thru + * Obd2FloatingSensorIndex.LAST_SYSTEM_INDEX + the value of configArray[1] + * are 1 if the corresponding index is a valid sensor index whose value + * can be read in the returned floatValues vector, 0 otherwise. + * stringValue is the DTC that caused this freeze frame to be recorded. + * + * For example, int32Values[0] corresponds to FUEL_SYSTEM_STATUS, and + * floatValues[0] corresponds to CALCULATED_ENGINE_LOAD, but that mapping + * is only valid if the corresponding bits in the bytes vector are set to 1, + * and a possible valid stringValue is "P0176" to indicate a malfunction + * of the fuel composition sensor circuit. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + OBD2_FREEZE_FRAME = ( + 0x0D01 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), + + /* + * OBD2 Freeze Frame Information + * + * This property describes the current freeze frames stored in vehicle + * memory and available for retrieval via OBD2_FREEZE_FRAME. + * + * The values are to be interpreted as follows: + * each element of int64Values is the timestamp at which a a fault code + * has been detected and the corresponding freeze frame stored, and each + * such element can be used as the key to OBD2_FREEZE_FRAME to retrieve + * the corresponding freeze frame. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ + */ + OBD2_FREEZE_FRAME_INFO = ( + 0x0D02 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), + + /* + * OBD2 Freeze Frame Clear + * + * This property allows deletion of any of the freeze frames stored in + * vehicle memory, as described by OBD2_DTC_INFO. + * + * A set of this property is to be interpreted as follows: + * if int64Values contains no elements, then all DTCs stored will be cleared; + * if int64Values contains one or more elements, then DTCs at the timestamps + * stored in int64Values will be cleared, and the others not cleared, except + * the memory will be compacted so that all remaining DTCs are stored + * contiguously. + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:WRITE + */ + OBD2_FREEZE_FRAME_CLEAR = ( + 0x0D03 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), + + /* + * Vehicle Maps Service (VMS) message + * + * This property uses COMPLEX data to communicate vms messages. + * + * Its contents are to be interpreted as follows: + * the indices defined in VmsMessageIntegerValuesIndex are to be used to + * read from int32Values; + * bytes is a serialized VMS message as defined in the vms protocol + * which is opaque to the framework; + * + * @change_mode VehiclePropertyChangeMode:ON_CHANGE + * @access VehiclePropertyAccess:READ_WRITE + */ + VEHICLE_MAP_SERVICE = ( + 0x0C00 + | VehiclePropertyGroup:SYSTEM + | VehiclePropertyType:COMPLEX + | VehicleArea:GLOBAL), +}; + +/* The status of a fuel system as described by the OBD2 specification. */ +enum FuelSystemStatus : int32_t { + OPEN_INSUFFICIENT_ENGINE_TEMPERATURE = 1, + + CLOSED_LOOP = 2, + + OPEN_ENGINE_LOAD_OR_DECELERATION = 4, + + OPEN_SYSTEM_FAILURE = 8, + + CLOSED_LOOP_BUT_FEEDBACK_FAULT = 16, +}; + +/* Defines which ignition monitors are available to be read. */ +enum IgnitionMonitorKind : int32_t { + SPARK = 0, + + COMPRESSION = 1, +}; + +/* These ignition monitors are common to both SPARK and COMPRESSION. */ +enum CommonIgnitionMonitors : int32_t { + COMPONENTS_AVAILABLE = 0x1 << 0, + COMPONENTS_INCOMPLETE = 0x1 << 1, + + FUEL_SYSTEM_AVAILABLE = 0x1 << 2, + FUEL_SYSTEM_INCOMPLETE = 0x1 << 3, + + MISFIRE_AVAILABLE = 0x1 << 4, + MISFIRE_INCOMPLETE = 0x1 << 5, +}; + +/* Ignition monitors available for SPARK vehicles. */ +enum SparkIgnitionMonitors : CommonIgnitionMonitors { + EGR_AVAILABLE = 0x1 << 6, + EGR_INCOMPLETE = 0x1 << 7, + + OXYGEN_SENSOR_HEATER_AVAILABLE = 0x1 << 8, + OXYGEN_SENSOR_HEATER_INCOMPLETE = 0x1 << 9, + + OXYGEN_SENSOR_AVAILABLE = 0x1 << 10, + OXYGEN_SENSOR_INCOMPLETE = 0x1 << 11, + + AC_REFRIGERANT_AVAILABLE = 0x1 << 12, + AC_REFRIGERANT_INCOMPLETE = 0x1 << 13, + + SECONDARY_AIR_SYSTEM_AVAILABLE = 0x1 << 14, + SECONDARY_AIR_SYSTEM_INCOMPLETE = 0x1 << 15, + + EVAPORATIVE_SYSTEM_AVAILABLE = 0x1 << 16, + EVAPORATIVE_SYSTEM_INCOMPLETE = 0x1 << 17, + + HEATED_CATALYST_AVAILABLE = 0x1 << 18, + HEATED_CATALYST_INCOMPLETE = 0x1 << 19, + + CATALYST_AVAILABLE = 0x1 << 20, + CATALYST_INCOMPLETE = 0x1 << 21, +}; + +/* Ignition monitors only available for COMPRESSION vehicles. */ +enum CompressionIgnitionMonitors : CommonIgnitionMonitors { + EGR_OR_VVT_AVAILABLE = 0x1 << 6, + EGR_OR_VVT_INCOMPLETE = 0x1 << 7, + + PM_FILTER_AVAILABLE = 0x1 << 8, + PM_FILTER_INCOMPLETE = 0x1 << 9, + + EXHAUST_GAS_SENSOR_AVAILABLE = 0x1 << 10, + EXHAUST_GAS_SENSOR_INCOMPLETE = 0x1 << 11, + + BOOST_PRESSURE_AVAILABLE = 0x1 << 12, + BOOST_PRESSURE_INCOMPLETE = 0x1 << 13, + + NOx_SCR__AVAILABLE = 0x1 << 14, + NOx_SCR_INCOMPLETE = 0x1 << 15, + + NMHC_CATALYST_AVAILABLE = 0x1 << 16, + NMHC_CATALYST_INCOMPLETE = 0x1 << 17, +}; + +enum SecondaryAirStatus : int32_t { + UPSTREAM = 1, + + DOWNSTREAM_OF_CATALYCIC_CONVERTER = 2, + + FROM_OUTSIDE_OR_OFF = 4, + + PUMP_ON_FOR_DIAGNOSTICS = 8, +}; + +enum FuelType : int32_t { + NOT_AVAILABLE = 0, + + GASOLINE = 1, + + METHANOL = 2, + + ETHANOL = 3, + + DIESEL = 4, + + LPG = 5, + + CNG = 6, + + PROPANE = 7, + + ELECTRIC = 8, + + BIFUEL_RUNNING_GASOLINE = 9, + + BIFUEL_RUNNING_METHANOL = 10, + + BIFUEL_RUNNING_ETHANOL = 11, + + BIFUEL_RUNNING_LPG = 12, + + BIFUEL_RUNNING_CNG = 13, + + BIFUEL_RUNNING_PROPANE = 14, + + BIFUEL_RUNNING_ELECTRIC = 15, + + BIFUEL_RUNNING_ELECTRIC_AND_COMBUSTION = 16, + + HYBRID_GASOLINE = 17, + + HYBRID_ETHANOL = 18, + + HYBRID_DIESEL = 19, + + HYBRID_ELECTRIC = 20, + + HYBRID_RUNNING_ELECTRIC_AND_COMBUSTION = 21, + + HYBRID_REGENERATIVE = 22, + + BIFUEL_RUNNING_DIESEL = 23, +}; + +/* + * This enum provides the canonical mapping for sensor properties that have an integer value. + * The ordering of the values is taken from the OBD2 specification. + * Some of the properties are represented as an integer mapping to another enum. In those cases + * expect a comment by the property definition describing the enum to look at for the mapping. + * Any value greater than the last reserved index is available to vendors to map their extensions. + */ +enum Obd2IntegerSensorIndex : int32_t { + /* refer to FuelSystemStatus for a description of this value. */ + FUEL_SYSTEM_STATUS = 0, + + MALFUNCTION_INDICATOR_LIGHT_ON = 1, + + /* refer to IgnitionMonitorKind for a description of this value. */ + IGNITION_MONITORS_SUPPORTED = 2, + + /* + * The value of this sensor is a bitmask that specifies whether ignition-specific + * tests are available and whether they are complete. The semantics of the individual + * bits in this value are given by, respectively, SparkIgnitionMonitors and + * CompressionIgnitionMonitors depending on the value of IGNITION_MONITORS_SUPPORTED. + */ + IGNITION_SPECIFIC_MONITORS = 3, + + INTAKE_AIR_TEMPERATURE = 4, + + /* refer to SecondaryAirStatus for a description of this value. */ + COMMANDED_SECONDARY_AIR_STATUS = 5, + + NUM_OXYGEN_SENSORS_PRESENT = 6, + + RUNTIME_SINCE_ENGINE_START = 7, + + DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON = 8, + + WARMUPS_SINCE_CODES_CLEARED = 9, + + DISTANCE_TRAVELED_SINCE_CODES_CLEARED = 10, + + ABSOLUTE_BAROMETRIC_PRESSURE = 11, + + CONTROL_MODULE_VOLTAGE = 12, + + AMBIENT_AIR_TEMPERATURE = 13, + + TIME_WITH_MALFUNCTION_LIGHT_ON = 14, + + TIME_SINCE_TROUBLE_CODES_CLEARED = 15, + + MAX_FUEL_AIR_EQUIVALENCE_RATIO = 16, + + MAX_OXYGEN_SENSOR_VOLTAGE = 17, + + MAX_OXYGEN_SENSOR_CURRENT = 18, + + MAX_INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 19, + + MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR = 20, + + /* refer to FuelType for a description of this value. */ + FUEL_TYPE = 21, + + FUEL_RAIL_ABSOLUTE_PRESSURE = 22, + + ENGINE_OIL_TEMPERATURE = 23, + + DRIVER_DEMAND_PERCENT_TORQUE = 24, + + ENGINE_ACTUAL_PERCENT_TORQUE = 25, + + ENGINE_REFERENCE_PERCENT_TORQUE = 26, + + ENGINE_PERCENT_TORQUE_DATA_IDLE = 27, + + ENGINE_PERCENT_TORQUE_DATA_POINT1 = 28, + + ENGINE_PERCENT_TORQUE_DATA_POINT2 = 29, + + ENGINE_PERCENT_TORQUE_DATA_POINT3 = 30, + + ENGINE_PERCENT_TORQUE_DATA_POINT4 = 31, + + LAST_SYSTEM_INDEX = ENGINE_PERCENT_TORQUE_DATA_POINT4, +}; + +/* + * This enum provides the canonical mapping for sensor properties that have a floating-point value. + * The ordering of the values is taken from the OBD2 specification. + * Any value greater than the last reserved index is available to vendors to map their extensions. + */ +enum Obd2FloatSensorIndex : int32_t { + CALCULATED_ENGINE_LOAD = 0, + + ENGINE_COOLANT_TEMPERATURE = 1, + + SHORT_TERM_FUEL_TRIM_BANK1 = 2, + + LONG_TERM_FUEL_TRIM_BANK1 = 3, + + SHORT_TERM_FUEL_TRIM_BANK2 = 4, + + LONG_TERM_FUEL_TRIM_BANK2 = 5, + + FUEL_PRESSURE = 6, + + INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 7, + + ENGINE_RPM = 8, + + VEHICLE_SPEED = 9, + + TIMING_ADVANCE = 10, + + MAF_AIR_FLOW_RATE = 11, + + THROTTLE_POSITION = 12, + + OXYGEN_SENSOR1_VOLTAGE = 13, + + OXYGEN_SENSOR1_SHORT_TERM_FUEL_TRIM = 14, + + OXYGEN_SENSOR1_FUEL_AIR_EQUIVALENCE_RATIO = 15, + + OXYGEN_SENSOR2_VOLTAGE = 16, + + OXYGEN_SENSOR2_SHORT_TERM_FUEL_TRIM = 17, + + OXYGEN_SENSOR2_FUEL_AIR_EQUIVALENCE_RATIO = 18, + + OXYGEN_SENSOR3_VOLTAGE = 19, + + OXYGEN_SENSOR3_SHORT_TERM_FUEL_TRIM = 20, + + OXYGEN_SENSOR3_FUEL_AIR_EQUIVALENCE_RATIO = 21, + + OXYGEN_SENSOR4_VOLTAGE = 22, + + OXYGEN_SENSOR4_SHORT_TERM_FUEL_TRIM = 23, + + OXYGEN_SENSOR4_FUEL_AIR_EQUIVALENCE_RATIO = 24, + + OXYGEN_SENSOR5_VOLTAGE = 25, + + OXYGEN_SENSOR5_SHORT_TERM_FUEL_TRIM = 26, + + OXYGEN_SENSOR5_FUEL_AIR_EQUIVALENCE_RATIO = 27, + + OXYGEN_SENSOR6_VOLTAGE = 28, + + OXYGEN_SENSOR6_SHORT_TERM_FUEL_TRIM = 29, + + OXYGEN_SENSOR6_FUEL_AIR_EQUIVALENCE_RATIO = 30, + + OXYGEN_SENSOR7_VOLTAGE = 31, + + OXYGEN_SENSOR7_SHORT_TERM_FUEL_TRIM = 32, + + OXYGEN_SENSOR7_FUEL_AIR_EQUIVALENCE_RATIO = 33, + + OXYGEN_SENSOR8_VOLTAGE = 34, + + OXYGEN_SENSOR8_SHORT_TERM_FUEL_TRIM = 35, + + OXYGEN_SENSOR8_FUEL_AIR_EQUIVALENCE_RATIO = 36, + + FUEL_RAIL_PRESSURE = 37, + + FUEL_RAIL_GAUGE_PRESSURE = 38, + + COMMANDED_EXHAUST_GAS_RECIRCULATION = 39, + + EXHAUST_GAS_RECIRCULATION_ERROR = 40, + + COMMANDED_EVAPORATIVE_PURGE = 41, + + FUEL_TANK_LEVEL_INPUT = 42, + + EVAPORATION_SYSTEM_VAPOR_PRESSURE = 43, + + CATALYST_TEMPERATURE_BANK1_SENSOR1 = 44, + + CATALYST_TEMPERATURE_BANK2_SENSOR1 = 45, + + CATALYST_TEMPERATURE_BANK1_SENSOR2 = 46, + + CATALYST_TEMPERATURE_BANK2_SENSOR2 = 47, + + ABSOLUTE_LOAD_VALUE = 48, + + FUEL_AIR_COMMANDED_EQUIVALENCE_RATIO = 49, + + RELATIVE_THROTTLE_POSITION = 50, + + ABSOLUTE_THROTTLE_POSITION_B = 51, + + ABSOLUTE_THROTTLE_POSITION_C = 52, + + ACCELERATOR_PEDAL_POSITION_D = 53, + + ACCELERATOR_PEDAL_POSITION_E = 54, + + ACCELERATOR_PEDAL_POSITION_F = 55, + + COMMANDED_THROTTLE_ACTUATOR = 56, + + ETHANOL_FUEL_PERCENTAGE = 57, + + ABSOLUTE_EVAPORATION_SYSTEM_VAPOR_PRESSURE = 58, + + SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 59, + + SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 60, + + SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 61, + + SHORT_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 62, + + LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK1 = 63, + + LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK2 = 64, + + LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK3 = 65, + + LONG_TERM_SECONDARY_OXYGEN_SENSOR_TRIM_BANK4 = 66, + + RELATIVE_ACCELERATOR_PEDAL_POSITION = 67, + + HYBRID_BATTERY_PACK_REMAINING_LIFE = 68, + + FUEL_INJECTION_TIMING = 69, + + ENGINE_FUEL_RATE = 70, + + LAST_SYSTEM_INDEX = ENGINE_FUEL_RATE, +}; + +/* + * This enum lists the types of supported VMS messages. + */ +enum VmsMessageType : int32_t { + /* A client subscribes to a layer. */ + SUBSCRIBE = 1, + + /* A client unsubscribes from a layer. */ + UNSUBSCRIBE = 2, + + /* A client publishes a data packet. */ + DATA = 3, +}; + +/* + * This enum provides the canonical mapping for VMS properties that have an + * integer value. + */ +enum VmsMessageIntegerValuesIndex : int32_t { + /* The message type as enumerated by VmsMessageType enum. */ + VMS_MESSAGE_TYPE = 0, + + /* The layer ID as defined in the vms protocol. */ + VMS_LAYER_ID = 1, + + /* The version of the VMS layer. */ + VMS_LAYER_VERSION = 2, + + /* The number of bytes in the payload */ + VMS_PAYLOAD_SIZE_BYTES = 3, +};
diff --git a/biometrics/Android.bp b/biometrics/Android.bp new file mode 100644 index 0000000..c87e3af --- /dev/null +++ b/biometrics/Android.bp
@@ -0,0 +1,5 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "fingerprint/2.1", + "fingerprint/2.1/vts/functional", +]
diff --git a/biometrics/fingerprint/2.1/Android.bp b/biometrics/fingerprint/2.1/Android.bp new file mode 100644 index 0000000..586e1b3 --- /dev/null +++ b/biometrics/fingerprint/2.1/Android.bp
@@ -0,0 +1,69 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.biometrics.fingerprint@2.1_hal", + srcs: [ + "types.hal", + "IBiometricsFingerprint.hal", + "IBiometricsFingerprintClientCallback.hal", + ], +} + +genrule { + name: "android.hardware.biometrics.fingerprint@2.1_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.biometrics.fingerprint@2.1", + srcs: [ + ":android.hardware.biometrics.fingerprint@2.1_hal", + ], + out: [ + "android/hardware/biometrics/fingerprint/2.1/types.cpp", + "android/hardware/biometrics/fingerprint/2.1/BiometricsFingerprintAll.cpp", + "android/hardware/biometrics/fingerprint/2.1/BiometricsFingerprintClientCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.biometrics.fingerprint@2.1_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.biometrics.fingerprint@2.1", + srcs: [ + ":android.hardware.biometrics.fingerprint@2.1_hal", + ], + out: [ + "android/hardware/biometrics/fingerprint/2.1/types.h", + "android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h", + "android/hardware/biometrics/fingerprint/2.1/IHwBiometricsFingerprint.h", + "android/hardware/biometrics/fingerprint/2.1/BnHwBiometricsFingerprint.h", + "android/hardware/biometrics/fingerprint/2.1/BpHwBiometricsFingerprint.h", + "android/hardware/biometrics/fingerprint/2.1/BsBiometricsFingerprint.h", + "android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h", + "android/hardware/biometrics/fingerprint/2.1/IHwBiometricsFingerprintClientCallback.h", + "android/hardware/biometrics/fingerprint/2.1/BnHwBiometricsFingerprintClientCallback.h", + "android/hardware/biometrics/fingerprint/2.1/BpHwBiometricsFingerprintClientCallback.h", + "android/hardware/biometrics/fingerprint/2.1/BsBiometricsFingerprintClientCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.biometrics.fingerprint@2.1", + generated_sources: ["android.hardware.biometrics.fingerprint@2.1_genc++"], + generated_headers: ["android.hardware.biometrics.fingerprint@2.1_genc++_headers"], + export_generated_headers: ["android.hardware.biometrics.fingerprint@2.1_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/biometrics/fingerprint/2.1/Android.mk b/biometrics/fingerprint/2.1/Android.mk new file mode 100644 index 0000000..567b38a --- /dev/null +++ b/biometrics/fingerprint/2.1/Android.mk
@@ -0,0 +1,468 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.biometrics.fingerprint@2.1-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (FingerprintAcquired) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAcquired.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintAcquired + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintAcquiredInfo) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAcquiredInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintAcquiredInfo + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintAuthenticated) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAuthenticated.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintAuthenticated + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintEnroll) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintEnroll.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintEnroll + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintError) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintError.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintError + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintFingerId) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintFingerId.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintFingerId + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintIterator) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintIterator.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintIterator + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintMsgType) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintMsgType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintMsgType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (RequestStatus) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/RequestStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.RequestStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IBiometricsFingerprint.hal +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/IBiometricsFingerprint.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IBiometricsFingerprint.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal +$(GEN): $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint + +$(GEN): $(LOCAL_PATH)/IBiometricsFingerprint.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IBiometricsFingerprintClientCallback.hal +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/IBiometricsFingerprintClientCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprintClientCallback + +$(GEN): $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.biometrics.fingerprint@2.1-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (FingerprintAcquired) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAcquired.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintAcquired + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintAcquiredInfo) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAcquiredInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintAcquiredInfo + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintAuthenticated) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAuthenticated.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintAuthenticated + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintEnroll) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintEnroll.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintEnroll + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintError) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintError.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintError + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintFingerId) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintFingerId.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintFingerId + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintIterator) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintIterator.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintIterator + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (FingerprintMsgType) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintMsgType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.FingerprintMsgType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (RequestStatus) +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/RequestStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::types.RequestStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IBiometricsFingerprint.hal +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/IBiometricsFingerprint.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IBiometricsFingerprint.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal +$(GEN): $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint + +$(GEN): $(LOCAL_PATH)/IBiometricsFingerprint.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IBiometricsFingerprintClientCallback.hal +# +GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/IBiometricsFingerprintClientCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprintClientCallback + +$(GEN): $(LOCAL_PATH)/IBiometricsFingerprintClientCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/biometrics/fingerprint/2.1/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.1/IBiometricsFingerprint.hal new file mode 100644 index 0000000..0b92848 --- /dev/null +++ b/biometrics/fingerprint/2.1/IBiometricsFingerprint.hal
@@ -0,0 +1,164 @@ +/* + * Copyright (C) 2017 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.biometrics.fingerprint@2.1; + +import IBiometricsFingerprintClientCallback; + +interface IBiometricsFingerprint { + /* + * Set notification callback: + * Registers a user function that must receive notifications from the HAL + * This call must block if the HAL state machine is in busy state until HAL + * leaves the busy state. + * + * @return deviceId is a unique handle for this fingerprint device + */ + @callflow(next={"setActiveGroup"}) + @entry + setNotify(IBiometricsFingerprintClientCallback clientCallback) + generates (uint64_t deviceId); + + /* + * Fingerprint pre-enroll enroll request: + * Generates a unique token to upper layers to indicate the start of + * an enrollment transaction. pre-enroll and post-enroll specify + * a pin/password cleared time window where enrollment is allowed. + * Pre-enroll only generates a challenge, a full hardwareAuthToken is + * generated by trustzone after verifying a pin/password/swipe. This is to + * ensure adding a new fingerprint template was preceded by some kind of + * credential confirmation (e.g. device password). + * + * @return 0 if function failed, a uint64_t of challenge otherwise. + */ + @callflow(next={"enroll", "postEnroll"}) + preEnroll() generates (uint64_t authChallenge); + + /* + * Fingerprint enroll request: + * Switches the HAL state machine to collect and store a new fingerprint + * template. Switches back as soon as enroll is complete, signalled by + * (fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENROLLING && + * fingerprintMsg.data.enroll.samplesRemaining == 0) + * or after timeoutSec seconds. + * The fingerprint template must be assigned to the group gid. + * + * @param hat a valid Hardware Authentication Token (HAT), generated + * as a result of a preEnroll() call. + * @param gid a framework defined fingerprint set (group) id. + * @param timeoutSec a timeout in seconds. + * + * @return debugErrno is a value the framework logs in case it is not 0. + * + * A notify() function may be called with a more detailed error structure. + */ + @callflow(next={"cancel", "enroll", "postEnroll", "remove"}) + enroll(uint8_t[69] hat, uint32_t gid, uint32_t timeoutSec) + generates (RequestStatus debugErrno); + + /* + * Finishes the enroll operation and invalidates the preEnroll() generated + * challenge. This must be called at the end of a multi-finger enrollment + * session to indicate that no more fingers may be added. + * + * @return debugErrno is a value the framework logs in case it is not 0. + */ + @callflow(next={"authenticate", "setActiveGroup", "enumerate", "remove"}) + postEnroll() generates (RequestStatus debugErrno); + + /* + * getAuthenticatorId: + * Returns a token associated with the current fingerprint set. This value + * must change whenever a new fingerprint is enrolled, thus creating a new + * fingerprint set. + * + * @return getAuthenticatorIdRet current authenticator id, 0 if function + * failed. + */ + @callflow(next={"authenticate"}) + getAuthenticatorId() generates (uint64_t AuthenticatorId); + + /* + * Cancel pending enroll or authenticate, sending FINGERPRINT_ERROR_CANCELED + * to all running clients. Switches the HAL state machine back to the idle + * state. Unlike enrollDone() doesn't invalidate the preEnroll() challenge. + * + * @return debugErrno is a value the framework logs in case it is not 0. + */ + @callflow(next={"authenticate", "enroll", "enumerate", "remove", + "setActiveGroup"}) + cancel() generates (RequestStatus debugErrno); + + /* + * Enumerate all the fingerprint templates found in the directory set by + * setActiveGroup(): + * For each template found a notify() must be called with: + * fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENUMERATED + * fingerprintMsg.data.enumerated.finger indicating a template id + * fingerprintMsg.data.enumerated.remainingTemplates indicating how many more + * enumeration messages to expect. + * + * @return debugErrno is a value the framework logs in case it is not 0. + */ + @callflow(next={"remove", "enroll", "authenticate", "setActiveGroup"}) + enumerate() generates (RequestStatus debugErrno); + + /* + * Fingerprint remove request: + * Deletes fingerprint template(s). + * Works only within the path set by setActiveGroup(). + * For each template found a notify() must be called with: + * fingerprintMsg.type == FINGERPRINT_TEMPLATE_REMOVED + * fingerprintMsg.data.removed.finger indicating the template id deleted + * fingerprintMsg.data.removed.remainingTemplates indicating how many more + * templates must be deleted by this operation. + * + * @param gid group id must match the last group set by setActiveGroup(). + * @param fid template id to delete or 0 to delete all templates within the + * current group. + * + * @return debugErrno is a value the framework logs in case it is not 0. + */ + @callflow(next={"enumerate", "authenticate", "cancel", "getAuthenticatorId", + "setActiveGroup"}) + remove(uint32_t gid, uint32_t fid) generates (RequestStatus debugErrno); + + /* + * Restricts the HAL operation to a set of fingerprints belonging to a group + * provided. The caller must provide a path to a storage location within the + * user's data directory. + * + * @param gid the fingerprint group (set) id. + * @param storePath filesystem path to the template storage directory. + * + * @return debugErrno is a value the framework logs in case it is not 0. + */ + @callflow(next={"authenticate", "preEnroll", "enumerate", "remove"}) + setActiveGroup(uint32_t gid, string storePath) + generates (RequestStatus debugErrno); + + /* + * Authenticates an operation identified by operationId + * + * @param operationId operation id. + * @param gid fingerprint group id. + * + * @return debugErrno is a value the framework logs in case it is not 0. + */ + @callflow(next={"cancel", "preEnroll", "remove"}) + authenticate(uint64_t operationId, uint32_t gid) + generates (RequestStatus debugErrno); +};
diff --git a/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.hal b/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.hal new file mode 100644 index 0000000..d913cf1 --- /dev/null +++ b/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.hal
@@ -0,0 +1,76 @@ +/* + * Copyright (C) 2017 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.biometrics.fingerprint@2.1; + +/* This HAL interface communicates asynchronous results from the + fingerprint driver in response to user actions on the fingerprint sensor +*/ +interface IBiometricsFingerprintClientCallback { + /** + * Sent when one enrollment step is complete. + * @param deviceId the instance of this fingerprint device + * @param fingerId the fingerprint templetate being enrolled + * @param groupId the groupid for the template being enrolled + * @param remaining the number of remaining steps before enrolllment is complete + */ + oneway onEnrollResult(uint64_t deviceId, uint32_t fingerId, uint32_t groupId, uint32_t remaining); + + /** + * Sent when a fingerprint image is acquired by the sensor + * @param deviceId the instance of this fingerprint device + * @param acquiredInfo a message about the quality of the acquired image + * @param vendorCode a vendor-specific message about the quality of the image. Only + * valid when acquiredInfo == ACQUIRED_VENDOR + */ + oneway onAcquired(uint64_t deviceId, FingerprintAcquiredInfo acquiredInfo, int32_t vendorCode); + + /** + * Sent when a fingerprint is authenticated + * @param deviceId the instance of this fingerprint device + * @param fingerId the fingerprint templetate that was authenticated + * @param groupId the groupid for the template that was authenticated + * @param token the hardware authentication token to pass to Keystore.addAuthToken() + */ + oneway onAuthenticated(uint64_t deviceId, uint32_t fingerId, uint32_t groupId, vec<uint8_t> token); + + /** + * Sent when a fingerprint error occurs + * @param deviceId the instance of this fingerprint device + * @param error a message about the error that occurred + * @param vendorCode a vendor-speicifc error message. Only valid + * when error == ERROR_VENDOR + */ + oneway onError(uint64_t deviceId, FingerprintError error, int32_t vendorCode); + + /** + * Sent when one template is removed + * @param deviceId the instance of this fingerprint device + * @param fingerId the fingerprint templetate being removed + * @param groupId the groupid for the template being removed + * @param remaining the number of remaining templates that will be removed. + */ + oneway onRemoved(uint64_t deviceId, uint32_t fingerId, uint32_t groupId, uint32_t remaining); + + /** + * Sent when one fingerprint template is enumerated + * @param deviceId the instance of this fingerprint device + * @param fingerId the fingerprint for this templetate + * @param groupId the groupid for this template + * @param remaining the number of remaining steps before enumeration is complete + */ + oneway onEnumerate(uint64_t deviceId, uint32_t fingerId, uint32_t groupId, uint32_t remaining); +};
diff --git a/biometrics/fingerprint/2.1/default/Android.mk b/biometrics/fingerprint/2.1/default/Android.mk new file mode 100644 index 0000000..3d06397 --- /dev/null +++ b/biometrics/fingerprint/2.1/default/Android.mk
@@ -0,0 +1,22 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.biometrics.fingerprint@2.1-service +LOCAL_INIT_RC := android.hardware.biometrics.fingerprint@2.1-service.rc +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + BiometricsFingerprint.cpp \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + liblog \ + libhidlbase \ + libhidltransport \ + libhardware \ + libkeystore_binder \ + libutils \ + android.hardware.biometrics.fingerprint@2.1 \ + +include $(BUILD_EXECUTABLE)
diff --git a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp new file mode 100644 index 0000000..b106481 --- /dev/null +++ b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
@@ -0,0 +1,321 @@ +/* + * Copyright (C) 2017 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. + */ +#define LOG_TAG "android.hardware.biometrics.fingerprint@2.1-service" +#define LOG_VERBOSE "android.hardware.biometrics.fingerprint@2.1-service" + +// For communication with Keystore binder interface +#include <keystore/keystore.h> // for error codes +#include <hardware/hw_auth_token.h> + +#include <hardware/hardware.h> +#include <hardware/fingerprint.h> +#include "BiometricsFingerprint.h" + +#include <inttypes.h> + +namespace android { +namespace hardware { +namespace biometrics { +namespace fingerprint { +namespace V2_1 { +namespace implementation { + +// Supported fingerprint HAL version +static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 1); + +using RequestStatus = + android::hardware::biometrics::fingerprint::V2_1::RequestStatus; + +BiometricsFingerprint *BiometricsFingerprint::sInstance = nullptr; + +BiometricsFingerprint::BiometricsFingerprint() : mClientCallback(nullptr), mDevice(nullptr) { + sInstance = this; // keep track of the most recent instance + mDevice = openHal(); + if (!mDevice) { + ALOGE("Can't open HAL module"); + } +} + +BiometricsFingerprint::~BiometricsFingerprint() { + ALOGV("~BiometricsFingerprint()"); + if (mDevice == nullptr) { + ALOGE("No valid device"); + return; + } + int err; + if (0 != (err = mDevice->common.close( + reinterpret_cast<hw_device_t*>(mDevice)))) { + ALOGE("Can't close fingerprint module, error: %d", err); + return; + } + mDevice = nullptr; +} + +Return<RequestStatus> BiometricsFingerprint::ErrorFilter(int32_t error) { + switch(error) { + case 0: return RequestStatus::SYS_OK; + case -2: return RequestStatus::SYS_ENOENT; + case -4: return RequestStatus::SYS_EINTR; + case -5: return RequestStatus::SYS_EIO; + case -11: return RequestStatus::SYS_EAGAIN; + case -12: return RequestStatus::SYS_ENOMEM; + case -13: return RequestStatus::SYS_EACCES; + case -14: return RequestStatus::SYS_EFAULT; + case -16: return RequestStatus::SYS_EBUSY; + case -22: return RequestStatus::SYS_EINVAL; + case -28: return RequestStatus::SYS_ENOSPC; + case -110: return RequestStatus::SYS_ETIMEDOUT; + default: + ALOGE("An unknown error returned from fingerprint vendor library"); + return RequestStatus::SYS_UNKNOWN; + } +} + +// Translate from errors returned by traditional HAL (see fingerprint.h) to +// HIDL-compliant FingerprintError. +FingerprintError BiometricsFingerprint::VendorErrorFilter(int32_t error, + int32_t* vendorCode) { + *vendorCode = 0; + switch(error) { + case FINGERPRINT_ERROR_HW_UNAVAILABLE: + return FingerprintError::ERROR_HW_UNAVAILABLE; + case FINGERPRINT_ERROR_UNABLE_TO_PROCESS: + return FingerprintError::ERROR_UNABLE_TO_PROCESS; + case FINGERPRINT_ERROR_TIMEOUT: + return FingerprintError::ERROR_TIMEOUT; + case FINGERPRINT_ERROR_NO_SPACE: + return FingerprintError::ERROR_NO_SPACE; + case FINGERPRINT_ERROR_CANCELED: + return FingerprintError::ERROR_CANCELED; + case FINGERPRINT_ERROR_UNABLE_TO_REMOVE: + return FingerprintError::ERROR_UNABLE_TO_REMOVE; + case FINGERPRINT_ERROR_LOCKOUT: + return FingerprintError::ERROR_LOCKOUT; + default: + if (error >= FINGERPRINT_ERROR_VENDOR_BASE) { + // vendor specific code. + *vendorCode = error - FINGERPRINT_ERROR_VENDOR_BASE; + return FingerprintError::ERROR_VENDOR; + } + } + ALOGE("Unknown error from fingerprint vendor library: %d", error); + return FingerprintError::ERROR_UNABLE_TO_PROCESS; +} + +// Translate acquired messages returned by traditional HAL (see fingerprint.h) +// to HIDL-compliant FingerprintAcquiredInfo. +FingerprintAcquiredInfo BiometricsFingerprint::VendorAcquiredFilter( + int32_t info, int32_t* vendorCode) { + *vendorCode = 0; + switch(info) { + case FINGERPRINT_ACQUIRED_GOOD: + return FingerprintAcquiredInfo::ACQUIRED_GOOD; + case FINGERPRINT_ACQUIRED_PARTIAL: + return FingerprintAcquiredInfo::ACQUIRED_PARTIAL; + case FINGERPRINT_ACQUIRED_INSUFFICIENT: + return FingerprintAcquiredInfo::ACQUIRED_INSUFFICIENT; + case FINGERPRINT_ACQUIRED_IMAGER_DIRTY: + return FingerprintAcquiredInfo::ACQUIRED_IMAGER_DIRTY; + case FINGERPRINT_ACQUIRED_TOO_SLOW: + return FingerprintAcquiredInfo::ACQUIRED_TOO_SLOW; + case FINGERPRINT_ACQUIRED_TOO_FAST: + return FingerprintAcquiredInfo::ACQUIRED_TOO_FAST; + default: + if (info >= FINGERPRINT_ACQUIRED_VENDOR_BASE) { + // vendor specific code. + *vendorCode = info - FINGERPRINT_ACQUIRED_VENDOR_BASE; + return FingerprintAcquiredInfo::ACQUIRED_VENDOR; + } + } + ALOGE("Unknown acquiredmsg from fingerprint vendor library: %d", info); + return FingerprintAcquiredInfo::ACQUIRED_INSUFFICIENT; +} + +Return<uint64_t> BiometricsFingerprint::setNotify( + const sp<IBiometricsFingerprintClientCallback>& clientCallback) { + mClientCallback = clientCallback; + // This is here because HAL 2.1 doesn't have a way to propagate a + // unique token for its driver. Subsequent versions should send a unique + // token for each call to setNotify(). This is fine as long as there's only + // one fingerprint device on the platform. + return reinterpret_cast<uint64_t>(mDevice); +} + +Return<uint64_t> BiometricsFingerprint::preEnroll() { + return mDevice->pre_enroll(mDevice); +} + +Return<RequestStatus> BiometricsFingerprint::enroll(const hidl_array<uint8_t, 69>& hat, + uint32_t gid, uint32_t timeoutSec) { + const hw_auth_token_t* authToken = + reinterpret_cast<const hw_auth_token_t*>(hat.data()); + return ErrorFilter(mDevice->enroll(mDevice, authToken, gid, timeoutSec)); +} + +Return<RequestStatus> BiometricsFingerprint::postEnroll() { + return ErrorFilter(mDevice->post_enroll(mDevice)); +} + +Return<uint64_t> BiometricsFingerprint::getAuthenticatorId() { + return mDevice->get_authenticator_id(mDevice); +} + +Return<RequestStatus> BiometricsFingerprint::cancel() { + return ErrorFilter(mDevice->cancel(mDevice)); +} + +Return<RequestStatus> BiometricsFingerprint::enumerate() { + return ErrorFilter(mDevice->enumerate(mDevice)); +} + +Return<RequestStatus> BiometricsFingerprint::remove(uint32_t gid, uint32_t fid) { + return ErrorFilter(mDevice->remove(mDevice, gid, fid)); +} + +Return<RequestStatus> BiometricsFingerprint::setActiveGroup(uint32_t gid, + const hidl_string& storePath) { + if (storePath.size() >= PATH_MAX || storePath.size() <= 0) { + ALOGE("Bad path length: %zd", storePath.size()); + } + return ErrorFilter(mDevice->set_active_group(mDevice, gid, + storePath.c_str())); +} + +Return<RequestStatus> BiometricsFingerprint::authenticate(uint64_t operationId, + uint32_t gid) { + return ErrorFilter(mDevice->authenticate(mDevice, operationId, gid)); +} + +IBiometricsFingerprint* BiometricsFingerprint::getInstance() { + if (!sInstance) { + sInstance = new BiometricsFingerprint(); + } + return sInstance; +} + +fingerprint_device_t* BiometricsFingerprint::openHal() { + int err; + const hw_module_t *hw_mdl = nullptr; + ALOGD("Opening fingerprint hal library..."); + if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_mdl))) { + ALOGE("Can't open fingerprint HW Module, error: %d", err); + return nullptr; + } + + if (hw_mdl == nullptr) { + ALOGE("No valid fingerprint module"); + return nullptr; + } + + fingerprint_module_t const *module = + reinterpret_cast<const fingerprint_module_t*>(hw_mdl); + if (module->common.methods->open == nullptr) { + ALOGE("No valid open method"); + return nullptr; + } + + hw_device_t *device = nullptr; + + if (0 != (err = module->common.methods->open(hw_mdl, nullptr, &device))) { + ALOGE("Can't open fingerprint methods, error: %d", err); + return nullptr; + } + + if (kVersion != device->version) { + // enforce version on new devices because of HIDL@2.1 translation layer + ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version); + return nullptr; + } + + fingerprint_device_t* fp_device = + reinterpret_cast<fingerprint_device_t*>(device); + + if (0 != (err = + fp_device->set_notify(fp_device, BiometricsFingerprint::notify))) { + ALOGE("Can't register fingerprint module callback, error: %d", err); + return nullptr; + } + + return fp_device; +} + +void BiometricsFingerprint::notify(const fingerprint_msg_t *msg) { + BiometricsFingerprint* thisPtr = static_cast<BiometricsFingerprint*>( + BiometricsFingerprint::getInstance()); + if (thisPtr == nullptr || thisPtr->mClientCallback == nullptr) { + ALOGE("Receiving callbacks before the client callback is registered."); + return; + } + const uint64_t devId = reinterpret_cast<uint64_t>(thisPtr->mDevice); + switch (msg->type) { + case FINGERPRINT_ERROR: { + int32_t vendorCode = 0; + FingerprintError result = VendorErrorFilter(msg->data.error, &vendorCode); + thisPtr->mClientCallback->onError(devId, result, vendorCode); + } + break; + case FINGERPRINT_ACQUIRED: { + int32_t vendorCode = 0; + FingerprintAcquiredInfo result = + VendorAcquiredFilter(msg->data.acquired.acquired_info, &vendorCode); + thisPtr->mClientCallback->onAcquired(devId, result, vendorCode); + } + break; + case FINGERPRINT_TEMPLATE_ENROLLING: + thisPtr->mClientCallback->onEnrollResult(devId, + msg->data.enroll.finger.fid, + msg->data.enroll.finger.gid, + msg->data.enroll.samples_remaining); + break; + case FINGERPRINT_TEMPLATE_REMOVED: + thisPtr->mClientCallback->onRemoved(devId, + msg->data.removed.finger.fid, + msg->data.removed.finger.gid, + msg->data.removed.remaining_templates); + break; + case FINGERPRINT_AUTHENTICATED: + if (msg->data.authenticated.finger.fid != 0) { + const uint8_t* hat = + reinterpret_cast<const uint8_t *>(&msg->data.authenticated.hat); + const hidl_vec<uint8_t> token( + std::vector<uint8_t>(hat, hat + sizeof(msg->data.authenticated.hat))); + thisPtr->mClientCallback->onAuthenticated(devId, + msg->data.authenticated.finger.fid, + msg->data.authenticated.finger.gid, + token); + } else { + // Not a recognized fingerprint + thisPtr->mClientCallback->onAuthenticated(devId, + msg->data.authenticated.finger.fid, + msg->data.authenticated.finger.gid, + hidl_vec<uint8_t>()); + } + break; + case FINGERPRINT_TEMPLATE_ENUMERATING: + thisPtr->mClientCallback->onEnumerate(devId, + msg->data.enumerated.finger.fid, + msg->data.enumerated.finger.gid, + msg->data.enumerated.remaining_templates); + break; + } +} + +} // namespace implementation +} // namespace V2_1 +} // namespace fingerprint +} // namespace biometrics +} // namespace hardware +} // namespace android
diff --git a/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h new file mode 100644 index 0000000..5923c84 --- /dev/null +++ b/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h
@@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_1_BIOMETRICSFINGERPRINT_H +#define ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_1_BIOMETRICSFINGERPRINT_H + +#include <log/log.h> +#include <android/log.h> +#include <hardware/hardware.h> +#include <hardware/fingerprint.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h> + +namespace android { +namespace hardware { +namespace biometrics { +namespace fingerprint { +namespace V2_1 { +namespace implementation { + +using ::android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint; +using ::android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback; +using ::android::hardware::biometrics::fingerprint::V2_1::RequestStatus; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct BiometricsFingerprint : public IBiometricsFingerprint { +public: + BiometricsFingerprint(); + ~BiometricsFingerprint(); + + // Method to wrap legacy HAL with BiometricsFingerprint class + static IBiometricsFingerprint* getInstance(); + + // Methods from ::android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint follow. + Return<uint64_t> setNotify(const sp<IBiometricsFingerprintClientCallback>& clientCallback) override; + Return<uint64_t> preEnroll() override; + Return<RequestStatus> enroll(const hidl_array<uint8_t, 69>& hat, uint32_t gid, uint32_t timeoutSec) override; + Return<RequestStatus> postEnroll() override; + Return<uint64_t> getAuthenticatorId() override; + Return<RequestStatus> cancel() override; + Return<RequestStatus> enumerate() override; + Return<RequestStatus> remove(uint32_t gid, uint32_t fid) override; + Return<RequestStatus> setActiveGroup(uint32_t gid, const hidl_string& storePath) override; + Return<RequestStatus> authenticate(uint64_t operationId, uint32_t gid) override; + +private: + static fingerprint_device_t* openHal(); + static void notify(const fingerprint_msg_t *msg); /* Static callback for legacy HAL implementation */ + static Return<RequestStatus> ErrorFilter(int32_t error); + static FingerprintError VendorErrorFilter(int32_t error, int32_t* vendorCode); + static FingerprintAcquiredInfo VendorAcquiredFilter(int32_t error, int32_t* vendorCode); + static BiometricsFingerprint* sInstance; + + sp<IBiometricsFingerprintClientCallback> mClientCallback; + fingerprint_device_t *mDevice; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace fingerprint +} // namespace biometrics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_1_BIOMETRICSFINGERPRINT_H
diff --git a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc new file mode 100644 index 0000000..aa767a6 --- /dev/null +++ b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
@@ -0,0 +1,7 @@ +service fps_hal /vendor/bin/hw/android.hardware.biometrics.fingerprint@2.1-service + # "class hal" causes a race condition on some devices due to files created + # in /data. As a workaround, postpone startup until later in boot once + # /data is mounted. + class late_start + user system + group system input
diff --git a/biometrics/fingerprint/2.1/default/service.cpp b/biometrics/fingerprint/2.1/default/service.cpp new file mode 100644 index 0000000..d6b91c6 --- /dev/null +++ b/biometrics/fingerprint/2.1/default/service.cpp
@@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "android.hardware.biometrics.fingerprint@2.1-service" + +#include <android/log.h> +#include <hidl/HidlSupport.h> +#include <hidl/HidlTransportSupport.h> +#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h> +#include <android/hardware/biometrics/fingerprint/2.1/types.h> +#include "BiometricsFingerprint.h" + +using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint; +using android::hardware::biometrics::fingerprint::V2_1::implementation::BiometricsFingerprint; +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::sp; + +int main() { + android::sp<IBiometricsFingerprint> bio = BiometricsFingerprint::getInstance(); + + configureRpcThreadpool(1, true /*callerWillJoin*/); + + if (bio != nullptr) { + bio->registerAsService("fingerprint_hal"); + } else { + ALOGE("Can't create instance of BiometricsFingerprint, nullptr"); + } + + joinRpcThreadpool(); + + return 0; // should never get here +}
diff --git a/biometrics/fingerprint/2.1/types.hal b/biometrics/fingerprint/2.1/types.hal new file mode 100644 index 0000000..e389773 --- /dev/null +++ b/biometrics/fingerprint/2.1/types.hal
@@ -0,0 +1,145 @@ +/* + * Copyright (C) 2017 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.biometrics.fingerprint@2.1; + +/* + * Request status indicates whether the request is accepted by the vendor + * implementation or not. These values are taken from the errno set, + * except for the SYS_UNKNOWN + */ +enum RequestStatus : int32_t { + SYS_UNKNOWN = 1, + SYS_OK = 0, + SYS_ENOENT = -2, + SYS_EINTR = -4, + SYS_EIO = -5, + SYS_EAGAIN = -11, + SYS_ENOMEM = -12, + SYS_EACCES = -13, + SYS_EFAULT = -14, + SYS_EBUSY = -16, + SYS_EINVAL = -22, + SYS_ENOSPC = -28, + SYS_ETIMEDOUT = -110, +}; + +/* + * Fingerprint errors are meant to tell the framework to terminate the current + * operation and ask for the user to correct the situation. These will almost + * always result in messaging and user interaction to correct the problem. + * + * For example, ERROR_CANCELED should follow any acquisition message that + * results in a situation where the current operation can't continue without + * user interaction. For example, if the sensor is dirty during enrollment and + * no further enrollment progress can be made, send ACQUIRED_IMAGER_DIRTY + * followed by ERROR_CANCELED. + */ +enum FingerprintError : int32_t { + /* Used for testing, no error returned */ + ERROR_NO_ERROR = 0, + /* The hardware has an error that can't be resolved. */ + ERROR_HW_UNAVAILABLE = 1, + /* Bad data; operation can't continue */ + ERROR_UNABLE_TO_PROCESS = 2, + /* The operation has timed out waiting for user input. */ + ERROR_TIMEOUT = 3, + /* No space available to store a template */ + ERROR_NO_SPACE = 4, + /* The current operation has been canceled */ + ERROR_CANCELED = 5, + /* Unable to remove a template */ + ERROR_UNABLE_TO_REMOVE = 6, + /* The hardware is in lockout due to too many attempts */ + ERROR_LOCKOUT = 7, + /* Vendor-specific error message */ + ERROR_VENDOR = 8 +}; + +/* + * Fingerprint acquisition info is meant as feedback for the current operation. + * Anything but ACQUIRED_GOOD must be shown to the user as feedback on how to + * take action on the current operation. For example, ACQUIRED_IMAGER_DIRTY may + * be used to tell the user to clean the sensor if it is detected to be dirty. + * If this causes the current operation to fail, an additional ERROR_CANCELED + * must be sent to stop the operation in progress (e.g. enrollment). + * In general, these messages will result in a "Try again" message. + */ +enum FingerprintAcquiredInfo : int32_t { + ACQUIRED_GOOD = 0, + /* sensor needs more data, i.e. longer swipe. */ + ACQUIRED_PARTIAL = 1, + /* image doesn't contain enough detail for recognition*/ + ACQUIRED_INSUFFICIENT = 2, + /* sensor needs to be cleaned */ + ACQUIRED_IMAGER_DIRTY = 3, + /* mostly swipe-type sensors; not enough data collected */ + ACQUIRED_TOO_SLOW = 4, + /* vendor-specific acquisition messages start here */ + ACQUIRED_TOO_FAST = 5, + /* vendor-specific acquisition messages */ + ACQUIRED_VENDOR = 6 +}; + +struct FingerprintFingerId { + /* Group ID */ + uint32_t gid; + /* Fingerprint template ID */ + uint32_t fid; +}; + +struct FingerprintEnroll { + /* Template ID */ + FingerprintFingerId finger; + /* samplesRemaining goes from N (no data collected, but N scans needed) + * to 0 (no more data is needed to build a template). */ + uint32_t samplesRemaining; + /* Vendor specific message. Used for user guidance */ + uint64_t msg; +}; + +struct FingerprintIterator { + /* Template ID */ + FingerprintFingerId finger; + /* How many templates remain to iterate through */ + uint32_t remainingTemplates; +}; + +typedef FingerprintIterator FingerprintEnumerated; +typedef FingerprintIterator FingerprintRemoved; + +struct FingerprintAcquired { + /* information about the image */ + FingerprintAcquiredInfo acquiredInfo; +}; + +struct FingerprintAuthenticated { + /* Matched template ID */ + FingerprintFingerId finger; + /* Authentication result from the keymaster */ + uint8_t[69] hat; +}; + +/* Run time type identification for the notify() call payload. */ +enum FingerprintMsgType : int32_t { + ERROR = -1, + ACQUIRED = 1, + TEMPLATE_ENROLLING = 3, + TEMPLATE_REMOVED = 4, + AUTHENTICATED = 5, + TEMPLATE_ENUMERATING = 6, +}; +
diff --git a/biometrics/fingerprint/2.1/vts/functional/Android.bp b/biometrics/fingerprint/2.1/vts/functional/Android.bp new file mode 100644 index 0000000..27b7157 --- /dev/null +++ b/biometrics/fingerprint/2.1/vts/functional/Android.bp
@@ -0,0 +1,36 @@ +// +// Copyright (C) 2017 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. +// + +cc_test { + name: "VtsHalBiometricsFingerprintV2_1TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalBiometricsFingerprintV2_1TargetTest.cpp"], + shared_libs: [ + "libbase", + "libhidltransport", + "libhardware", + "libhidlbase", + "liblog", + "libutils", + "android.hardware.biometrics.fingerprint@2.1", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ] +} +
diff --git a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp new file mode 100644 index 0000000..c07c3e3 --- /dev/null +++ b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp
@@ -0,0 +1,190 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "fingerprint_hidl_hal_test" +#define SERVICE_NAME "fingerprint_hal" + +#include <android-base/logging.h> +#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h> +#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h> +#include <hidl/HidlSupport.h> +#include <hidl/HidlTransportSupport.h> +#include <VtsHalHidlTargetTestBase.h> + +using android::Condition; +using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint; +using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback; +using android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo; +using android::hardware::biometrics::fingerprint::V2_1::FingerprintError; +using android::hardware::biometrics::fingerprint::V2_1::RequestStatus; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::Mutex; +using android::sp; + +class FingerprintHidlTest : public ::testing::VtsHalHidlTargetTestBase { + +protected: + class MyCallback : public IBiometricsFingerprintClientCallback { + + // implement methods of IBiometricsFingerprintClientCallback + virtual Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t, + uint32_t) override { + callBackCalled(); + return Return<void>(); + } + + virtual Return<void> onAcquired(uint64_t, FingerprintAcquiredInfo, + int32_t) override { + callBackCalled(); + return Return<void>(); + } + + virtual Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t, + const hidl_vec<uint8_t>&) override { + callBackCalled(); + return Return<void>(); + } + + virtual Return<void> onError(uint64_t, FingerprintError error, int32_t) + override { + mTestCase->mErr = error; + callBackCalled(); + return Return<void>(); + } + + virtual Return<void> onRemoved(uint64_t, uint32_t, uint32_t, uint32_t) + override { + callBackCalled(); + return Return<void>(); + } + + virtual Return<void> onEnumerate(uint64_t, uint32_t, uint32_t, + uint32_t) override { + callBackCalled(); + return Return<void>(); + } + + void callBackCalled () { + mTestCase->mCallbackCalled = true; + mTestCase->mCallbackCond.broadcast(); + } + + FingerprintHidlTest* mTestCase; + public: + MyCallback(FingerprintHidlTest* aTest) : mTestCase(aTest) {} + }; + + sp<MyCallback> mCallback; + bool mCallbackCalled; + Condition mCallbackCond; + FingerprintError mErr; + Mutex mLock; + sp<IBiometricsFingerprint> mService; + static const unsigned int kThresholdInSeconds = 3; + + void clearErr () { + mErr = FingerprintError::ERROR_NO_ERROR; + } + + // Timed callback mechanism. Will block up to kThresholdInSeconds, + // returning true if callback was invoked in that time frame. + bool waitForCallback(const unsigned int seconds = kThresholdInSeconds) { + nsecs_t reltime = seconds_to_nanoseconds(seconds); + Mutex::Autolock _l(mLock); + nsecs_t endTime = systemTime() + reltime; + while (!mCallbackCalled) { + if (reltime == 0) { + mCallbackCond.wait(mLock); + } else { + nsecs_t now = systemTime(); + if (now > endTime) { + return false; + } + mCallbackCond.waitRelative(mLock, endTime - now); + } + } + return true; + } +public: + FingerprintHidlTest (): mCallbackCalled(false) {} + + virtual void SetUp() override { + mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFingerprint>(SERVICE_NAME); + + ASSERT_NE(mService, nullptr); + clearErr(); + + mCallback = new MyCallback(this); + // TODO: instantly fail any test that receives a death notification + } + + virtual void TearDown() override {} +}; + +class FingerprintHidlEnvironment : public ::testing::Environment { +public: + virtual void SetUp() {} + virtual void TearDown() {} +}; + +// The service should be reachable. +TEST_F(FingerprintHidlTest, ConnectTest) { + Return<uint64_t> rc = mService->setNotify(mCallback); + EXPECT_NE(rc, 0UL); +} + +// Cancel should always return ERROR_CANCELED from any starting state including +// the IDLE state. +TEST_F(FingerprintHidlTest, CancelTest) { + Return<uint64_t> rc = mService->setNotify(mCallback); + EXPECT_NE(rc, 0UL); + + Return<RequestStatus> res = mService->cancel(); + // make sure callback was invoked within kThresholdInSeconds + EXPECT_EQ(true, waitForCallback()); + // check that we were able to make an IPC request successfully + EXPECT_EQ(RequestStatus::SYS_OK, res); + // check error should be ERROR_CANCELED + EXPECT_EQ(FingerprintError::ERROR_CANCELED, mErr); +} + +// A call to cancel should after any other method call should set the error +// state to canceled. +TEST_F(FingerprintHidlTest, AuthTest) { + Return<uint64_t> rc = mService->setNotify(mCallback); + EXPECT_NE(rc, 0UL); + + Return<RequestStatus> res = mService->authenticate(0, 0); + // check that we were able to make an IPC request successfully + EXPECT_EQ(RequestStatus::SYS_OK, res); + + res = mService->cancel(); + // make sure callback was invoked within kThresholdInSeconds + EXPECT_EQ(true, waitForCallback()); + // check that we were able to make an IPC request successfully + EXPECT_EQ(RequestStatus::SYS_OK, res); + // check error should be ERROR_CANCELED + EXPECT_EQ(FingerprintError::ERROR_CANCELED, mErr); +} + +int main(int argc, char **argv) { + ::testing::AddGlobalTestEnvironment(new FingerprintHidlEnvironment); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +}
diff --git a/boot/1.0/default/BootControl.cpp b/boot/1.0/default/BootControl.cpp index 83ee1d2..9a90076 100644 --- a/boot/1.0/default/BootControl.cpp +++ b/boot/1.0/default/BootControl.cpp
@@ -1,3 +1,18 @@ +/* + * Copyright (C) 2016 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. + */ #define LOG_TAG "android.hardware.boot@1.0-impl" #include <log/log.h>
diff --git a/boot/1.0/default/BootControl.h b/boot/1.0/default/BootControl.h index be8a814..3d668dc 100644 --- a/boot/1.0/default/BootControl.h +++ b/boot/1.0/default/BootControl.h
@@ -1,3 +1,18 @@ +/* + * Copyright (C) 2016 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. + */ #ifndef ANDROID_HARDWARE_BOOT_V1_0_BOOTCONTROL_H #define ANDROID_HARDWARE_BOOT_V1_0_BOOTCONTROL_H
diff --git a/boot/1.0/default/service.cpp b/boot/1.0/default/service.cpp index 247e40e..f3996ef 100644 --- a/boot/1.0/default/service.cpp +++ b/boot/1.0/default/service.cpp
@@ -1,3 +1,18 @@ +/* + * Copyright (C) 2016 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. + */ #define LOG_TAG "android.hardware.boot@1.0-service" #include <android/hardware/boot/1.0/IBootControl.h>
diff --git a/boot/1.0/vts/Android.bp b/boot/1.0/vts/Android.bp new file mode 100644 index 0000000..7aef46b --- /dev/null +++ b/boot/1.0/vts/Android.bp
@@ -0,0 +1,3 @@ +subdirs = [ + "*" +]
diff --git a/radio/1.0/vts/Android.mk b/boot/1.0/vts/Android.mk similarity index 100% rename from radio/1.0/vts/Android.mk rename to boot/1.0/vts/Android.mk
diff --git a/boot/1.0/vts/functional/Android.bp b/boot/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..5b14f54 --- /dev/null +++ b/boot/1.0/vts/functional/Android.bp
@@ -0,0 +1,35 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalBootV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalBootV1_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libnativehelper", + "libutils", + "android.hardware.boot@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ] +}
diff --git a/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp b/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp new file mode 100644 index 0000000..9789ee6 --- /dev/null +++ b/boot/1.0/vts/functional/VtsHalBootV1_0TargetTest.cpp
@@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "boot_hidl_hal_test" +#include <android-base/logging.h> + +#include <cutils/properties.h> + +#include <android/hardware/boot/1.0/IBootControl.h> + +#include <VtsHalHidlTargetTestBase.h> + +using ::android::hardware::boot::V1_0::IBootControl; +using ::android::hardware::boot::V1_0::CommandResult; +using ::android::hardware::boot::V1_0::BoolResult; +using ::android::hardware::boot::V1_0::Slot; +using ::android::hardware::hidl_string; +using ::android::hardware::Return; +using ::android::sp; + +// The main test class for the Boot HIDL HAL. +class BootHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + boot = ::testing::VtsHalHidlTargetTestBase::getService<IBootControl>(); + ASSERT_NE(boot, nullptr); + } + + virtual void TearDown() override {} + + sp<IBootControl> boot; +}; + +auto generate_callback(CommandResult *dest) { + return [=](CommandResult cr) { *dest = cr; }; +} + +// Sanity check Boot::getNumberSlots(). +TEST_F(BootHidlTest, GetNumberSlots) { + uint32_t slots = boot->getNumberSlots(); + EXPECT_LE((uint32_t)2, slots); +} + +// Sanity check Boot::getCurrentSlot(). +TEST_F(BootHidlTest, GetCurrentSlot) { + Slot curSlot = boot->getCurrentSlot(); + uint32_t slots = boot->getNumberSlots(); + EXPECT_LT(curSlot, slots); +} + +// Sanity check Boot::markBootSuccessful(). +TEST_F(BootHidlTest, MarkBootSuccessful) { + CommandResult cr; + Return<void> result = boot->markBootSuccessful(generate_callback(&cr)); + ASSERT_TRUE(result.isOk()); + if (cr.success) { + Slot curSlot = boot->getCurrentSlot(); + BoolResult ret = boot->isSlotMarkedSuccessful(curSlot); + EXPECT_EQ(BoolResult::TRUE, ret); + } +} + +// Sanity check Boot::setActiveBootSlot() on good and bad inputs. +TEST_F(BootHidlTest, SetActiveBootSlot) { + for (Slot s = 0; s < 2; s++) { + CommandResult cr; + Return<void> result = boot->setActiveBootSlot(s, generate_callback(&cr)); + EXPECT_TRUE(result.isOk()); + } + { + // Restore original flags to avoid problems on reboot + CommandResult cr; + Return <void> result = boot->markBootSuccessful(generate_callback(&cr)); + EXPECT_TRUE(result.isOk()); + EXPECT_TRUE(cr.success); + } + { + CommandResult cr; + uint32_t slots = boot->getNumberSlots(); + Return<void> result = + boot->setActiveBootSlot(slots, generate_callback(&cr)); + ASSERT_TRUE(result.isOk()); + EXPECT_EQ(false, cr.success); + } +} + +// Sanity check Boot::setSlotAsUnbootable() on good and bad inputs. +TEST_F(BootHidlTest, SetSlotAsUnbootable) { + { + CommandResult cr; + Slot curSlot = boot->getCurrentSlot(); + Slot otherSlot = curSlot ? 0 : 1; + Return<void> result = + boot->setSlotAsUnbootable(otherSlot, generate_callback(&cr)); + EXPECT_TRUE(result.isOk()); + if (cr.success) { + EXPECT_EQ(BoolResult::FALSE, boot->isSlotBootable(otherSlot)); + + // Restore original flags to avoid problems on reboot + result = boot->setActiveBootSlot(otherSlot, generate_callback(&cr)); + EXPECT_TRUE(result.isOk()); + EXPECT_TRUE(cr.success); + result = boot->setActiveBootSlot(curSlot, generate_callback(&cr)); + EXPECT_TRUE(result.isOk()); + EXPECT_TRUE(cr.success); + result = boot->markBootSuccessful(generate_callback(&cr)); + EXPECT_TRUE(result.isOk()); + EXPECT_TRUE(cr.success); + } + } + { + CommandResult cr; + uint32_t slots = boot->getNumberSlots(); + Return<void> result = + boot->setSlotAsUnbootable(slots, generate_callback(&cr)); + EXPECT_TRUE(result.isOk()); + EXPECT_EQ(false, cr.success); + } +} + +// Sanity check Boot::isSlotBootable() on good and bad inputs. +TEST_F(BootHidlTest, IsSlotBootable) { + for (Slot s = 0; s < 2; s++) { + EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotBootable(s)); + } + uint32_t slots = boot->getNumberSlots(); + EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotBootable(slots)); +} + +// Sanity check Boot::isSlotMarkedSuccessful() on good and bad inputs. +TEST_F(BootHidlTest, IsSlotMarkedSuccessful) { + for (Slot s = 0; s < 2; s++) { + EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(s)); + } + uint32_t slots = boot->getNumberSlots(); + EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(slots)); +} + +// Sanity check Boot::getSuffix() on good and bad inputs. +TEST_F(BootHidlTest, GetSuffix) { + const char *suffixPtr; + auto cb = [&](hidl_string suffix) { suffixPtr = suffix.c_str(); }; + for (Slot i = 0; i < 2; i++) { + CommandResult cr; + Return<void> result = boot->getSuffix(i, cb); + EXPECT_TRUE(result.isOk()); + char correctSuffix[3]; + snprintf(correctSuffix, sizeof(correctSuffix), "_%c", 'a' + i); + ASSERT_EQ(0, strcmp(suffixPtr, correctSuffix)); + } + { + char emptySuffix[] = ""; + Return<void> result = boot->getSuffix(boot->getNumberSlots(), cb); + EXPECT_TRUE(result.isOk()); + ASSERT_EQ(0, strcmp(emptySuffix, suffixPtr)); + } +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +}
diff --git a/boot/Android.bp b/boot/Android.bp index bbb3e4b..67af5bb 100644 --- a/boot/Android.bp +++ b/boot/Android.bp
@@ -1,4 +1,6 @@ // This is an autogenerated file, do not edit. subdirs = [ "1.0", + "1.0/vts", + "1.0/vts/functional", ]
diff --git a/broadcastradio/1.0/Android.bp b/broadcastradio/1.0/Android.bp new file mode 100644 index 0000000..3c3a015 --- /dev/null +++ b/broadcastradio/1.0/Android.bp
@@ -0,0 +1,83 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.broadcastradio@1.0_hal", + srcs: [ + "types.hal", + "IBroadcastRadio.hal", + "IBroadcastRadioFactory.hal", + "ITuner.hal", + "ITunerCallback.hal", + ], +} + +genrule { + name: "android.hardware.broadcastradio@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.broadcastradio@1.0", + srcs: [ + ":android.hardware.broadcastradio@1.0_hal", + ], + out: [ + "android/hardware/broadcastradio/1.0/types.cpp", + "android/hardware/broadcastradio/1.0/BroadcastRadioAll.cpp", + "android/hardware/broadcastradio/1.0/BroadcastRadioFactoryAll.cpp", + "android/hardware/broadcastradio/1.0/TunerAll.cpp", + "android/hardware/broadcastradio/1.0/TunerCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.broadcastradio@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.broadcastradio@1.0", + srcs: [ + ":android.hardware.broadcastradio@1.0_hal", + ], + out: [ + "android/hardware/broadcastradio/1.0/types.h", + "android/hardware/broadcastradio/1.0/IBroadcastRadio.h", + "android/hardware/broadcastradio/1.0/IHwBroadcastRadio.h", + "android/hardware/broadcastradio/1.0/BnHwBroadcastRadio.h", + "android/hardware/broadcastradio/1.0/BpHwBroadcastRadio.h", + "android/hardware/broadcastradio/1.0/BsBroadcastRadio.h", + "android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.0/IHwBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.0/BnHwBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.0/BpHwBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.0/BsBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.0/ITuner.h", + "android/hardware/broadcastradio/1.0/IHwTuner.h", + "android/hardware/broadcastradio/1.0/BnHwTuner.h", + "android/hardware/broadcastradio/1.0/BpHwTuner.h", + "android/hardware/broadcastradio/1.0/BsTuner.h", + "android/hardware/broadcastradio/1.0/ITunerCallback.h", + "android/hardware/broadcastradio/1.0/IHwTunerCallback.h", + "android/hardware/broadcastradio/1.0/BnHwTunerCallback.h", + "android/hardware/broadcastradio/1.0/BpHwTunerCallback.h", + "android/hardware/broadcastradio/1.0/BsTunerCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.broadcastradio@1.0", + generated_sources: ["android.hardware.broadcastradio@1.0_genc++"], + generated_headers: ["android.hardware.broadcastradio@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.broadcastradio@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/broadcastradio/1.0/Android.mk b/broadcastradio/1.0/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/broadcastradio/1.0/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/broadcastradio/1.0/IBroadcastRadio.hal b/broadcastradio/1.0/IBroadcastRadio.hal new file mode 100644 index 0000000..c7fe62d --- /dev/null +++ b/broadcastradio/1.0/IBroadcastRadio.hal
@@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 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.broadcastradio@1.0; + +import ITunerCallback; +import ITuner; + +interface IBroadcastRadio { + + /* + * Retrieve implementation properties. + * @return result Operation completion status: OK in case of success, + * NOT_INITIALIZED in case of initialization error. + * @return properties A Properties structure containing implementation + * description and capabilities. + */ + getProperties() generates (Result result, Properties properties); + + /* + * Open a tuner interface for the requested configuration. + * If no other tuner is opened, this will power on the radio hardware. + * The hardware must be powered down when all tuner interface are released. + * @param config A BandConfig struct containing the band configuration to apply + * @param audio True if this tuner must be used for live radio listening and + * should be connected to the radio audio source. + * @param callback the callback interface + * @return result Operation completion status: OK in case of success, + * INVALID_ARGUMENTS if configuration requested is invalid, + * INVALID_STATE if called out of sequence + * @return tuner The interface to control the tuner + * + * Callback ITunerCallback.ConfigChanged MUST be called once the + * configuration is applied or a failure occurs or after a time out. + */ + openTuner(BandConfig config, bool audio, ITunerCallback callback) + generates (Result result, ITuner tuner); +};
diff --git a/broadcastradio/1.0/IBroadcastRadioFactory.hal b/broadcastradio/1.0/IBroadcastRadioFactory.hal new file mode 100644 index 0000000..82a97c4 --- /dev/null +++ b/broadcastradio/1.0/IBroadcastRadioFactory.hal
@@ -0,0 +1,36 @@ +/* + * Copyright (C) 2016 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.broadcastradio@1.0; + +import IBroadcastRadio; + +interface IBroadcastRadioFactory { + + /* + * Connects to a broadcast radio HAL module for a given class + * (AM/FM, Satellite, DAB). + * + * @param classId Class of the module to connect to . + * @return retval operation completion status. Returns INVALID_ARGUMENTS + * if there is no corresponding hardware module found, + * NOT_INITIALIZED if an error occurred while opening the hardware + * module. + * @return result the interface for the created module. + */ + connectModule(Class classId) + generates (Result retval, IBroadcastRadio result); +};
diff --git a/broadcastradio/1.0/ITuner.hal b/broadcastradio/1.0/ITuner.hal new file mode 100644 index 0000000..ae4b284 --- /dev/null +++ b/broadcastradio/1.0/ITuner.hal
@@ -0,0 +1,111 @@ +/* + * Copyright (C) 2015 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.broadcastradio@1.0; + +import ITunerCallback; + +interface ITuner { + + /* + * Apply current radio band configuration (band, range, channel spacing...). + * Automatically cancels pending scan, step or tune. + * ITunerCallback.configChange() method MUST be called once the + * configuration is applied or a failure occurs or after a time out. + * @param config The band configuration to apply. + * @return result OK if configuration could be applied + * NOT_INITIALIZED in case of initialization error. + * INVALID_ARGUMENTS if configuration requested is invalid + * + */ + setConfiguration(BandConfig config) generates(Result result); + + /* + * Retrieve current radio band configuration. + * @return result OK if valid configuration is returned, + * NOT_INITIALIZED in case of initialization error. + * @param config Current band configuration + */ + getConfiguration() generates(Result result, BandConfig config); + + /* + * Start scanning up to next valid station. + * Shall be called only when a valid configuration has been applied. + * Automatically cancels pending scan, step or tune. + * ITunerCallback.tuneComplete() MUST be called once locked on a station + * or after a time out or full band scan if no station found. + * The status should indicate if a valid station is tuned or not. + * @param direction UP or DOWN. + * @param skipSubChannel valid for HD radio or digital radios only: + * ignore sub channels (e.g SPS for HD radio). + * @return result OK if scan successfully started + * INVALID_STATE if called out of sequence + * NOT_INITIALIZED if another error occurs + */ + scan(Direction direction, bool skipSubChannel) generates(Result result); + + /* + * Move one channel spacing up or down. + * Must be called when a valid configuration has been applied. + * Automatically cancels pending scan, step or tune. + * ITunerCallback.tuneComplete() MUST be called once locked on a station + * or after a time out or full band scan if no station found. + * The status should indicate if a valid station is tuned or not. + * @param direction UP or DOWN. + * @param skipSubChannel valid for HD radio or digital radios only: + * ignore sub channels (e.g SPS for HD radio). + * @return result OK if scan successfully started + * INVALID_STATE if called out of sequence + * NOT_INITIALIZED if another error occurs + */ + step(Direction direction, bool skipSubChannel) generates(Result result); + + /* + * Tune to specified channel. + * Must be called when a valid configuration has been applied. + * Automatically cancels pending scan, step or tune. + * ITunerCallback.tuneComplete() MUST be called once locked on a station + * or after a time out or full band scan if no station found. + * The status should indicate if a valid station is tuned or not. + * @param channel Channel to tune to. A frequency in kHz for AM/FM/HD Radio + * bands. + * @param subChannel Valid for HD radio or digital radios only + * (e.g SPS number for HD radio).. + * @return result OK if scan successfully started + * INVALID_ARGUMENTS if invalid arguments are passed + * INVALID_STATE if called out of sequence + * NOT_INITIALIZED if another error occurs + */ + tune(uint32_t channel, uint32_t subChannel) generates(Result result); + + /* + * Cancel a scan, step or tune operation. + * Shall be called only while a scan, step or tune operation is pending. + * ITunerCallback.tuneComplete() MUST NOT be sent by the HAL. + * @return result OK if scan successfully started + * INVALID_STATE if called out of sequence + * NOT_INITIALIZED if another error occurs + */ + cancel() generates(Result result); + + /* + * Retrieve current station information. + * @return result OK if scan successfully started + * NOT_INITIALIZED if another error occurs + * @return info Current program information. + */ + getProgramInformation() generates(Result result, ProgramInfo info); +};
diff --git a/broadcastradio/1.0/ITunerCallback.hal b/broadcastradio/1.0/ITunerCallback.hal new file mode 100644 index 0000000..a7e1260 --- /dev/null +++ b/broadcastradio/1.0/ITunerCallback.hal
@@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 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.broadcastradio@1.0; + + +interface ITunerCallback { + + /* + * Method called by the HAL when a HW failure occurs. + * The framework MUST close the ITuner interface and open a new one. + */ + oneway hardwareFailure(); + + /* + * Method called by the HAL when a new configuration is applied + * in response to IDevice.openTuner() or ITuner.setConfiguration(). + * @param result OK if the configuration has been applied, + * INVALID_ARGUMENTS if not or TIMEOUT in case of time out. + * @param config A BandConfig structure describing the new configuration + * applied. + */ + oneway configChange(Result result, BandConfig config); + + /* + * Method called by the HAL when a tuning operation completes + * following a step(), scan() or tune() command. + * @param result OK if tune succeeded or TIMEOUT in case of time out. + * @param info A ProgramInfo structure describing the tuned station. + */ + oneway tuneComplete(Result result, ProgramInfo info); + + /* + * Method called by the HAL when a frequency switch occurs. + * @param info A ProgramInfo structure describing the new tuned station. + */ + oneway afSwitch(ProgramInfo info); + + /* + * Method called by the HAL when the antenna connection state changes. + * @param connected True if the antenna is connected, false otherwise. + */ + oneway antennaStateChange(bool connected); + + /* + * Method called by the HAL when a traffic announcement starts or + * stops. + * @param active True if the announcement starts, false if it stops. + */ + oneway trafficAnnouncement(bool active); + + /* + * Method called by the HAL when an emergency announcement starts + * or stops. + * @param active True if the announcement starts, false if it stops. + */ + oneway emergencyAnnouncement(bool active); + + /* + * Method called by the HAL when metadata for current station + * are updated. + * @param channel The channel the metadata is associated with. + * @param subChannel The sub channel the metadata is associated with. + * @param metadata A list of all updated metada. + */ + oneway newMetadata(uint32_t channel, uint32_t subChannel, vec<MetaData> metadata); +}; \ No newline at end of file
diff --git a/broadcastradio/1.0/default/Android.mk b/broadcastradio/1.0/default/Android.mk new file mode 100644 index 0000000..bb32595 --- /dev/null +++ b/broadcastradio/1.0/default/Android.mk
@@ -0,0 +1,28 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.broadcastradio@1.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + BroadcastRadio.cpp \ + BroadcastRadioFactory.cpp \ + Tuner.cpp \ + Utils.cpp + +LOCAL_SHARED_LIBRARIES := \ + libhidlbase \ + libhidltransport \ + libutils \ + liblog \ + libhardware \ + android.hardware.broadcastradio@1.0 \ + libradio_metadata + +ifeq ($(strip $(AUDIOSERVER_MULTILIB)),) +LOCAL_MULTILIB := 32 +else +LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) +endif + +include $(BUILD_SHARED_LIBRARY)
diff --git a/broadcastradio/1.0/default/BroadcastRadio.cpp b/broadcastradio/1.0/default/BroadcastRadio.cpp new file mode 100644 index 0000000..45ffdb2 --- /dev/null +++ b/broadcastradio/1.0/default/BroadcastRadio.cpp
@@ -0,0 +1,142 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "BroadcastRadio" +//#define LOG_NDEBUG 0 + +#include <log/log.h> + +#include <hardware/radio.h> + +#include "BroadcastRadio.h" +#include "Tuner.h" +#include "Utils.h" + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_0 { +namespace implementation { + +BroadcastRadio::BroadcastRadio(Class classId) + : mStatus(Result::NOT_INITIALIZED), mClassId(classId), mHwDevice(NULL) +{ +} + +BroadcastRadio::~BroadcastRadio() +{ + if (mHwDevice != NULL) { + radio_hw_device_close(mHwDevice); + } +} + +void BroadcastRadio::onFirstRef() +{ + const hw_module_t *mod; + int rc; + ALOGI("%s mClassId %d", __FUNCTION__, mClassId); + + mHwDevice = NULL; + const char *classString = Utils::getClassString(mClassId); + if (classString == NULL) { + ALOGE("invalid class ID %d", mClassId); + mStatus = Result::INVALID_ARGUMENTS; + return; + } + + ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s", + __FUNCTION__, RADIO_HARDWARE_MODULE_ID, classString); + + rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, classString, &mod); + if (rc != 0) { + ALOGE("couldn't load radio module %s.%s (%s)", + RADIO_HARDWARE_MODULE_ID, classString, strerror(-rc)); + return; + } + rc = radio_hw_device_open(mod, &mHwDevice); + if (rc != 0) { + ALOGE("couldn't open radio hw device in %s.%s (%s)", + RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc)); + mHwDevice = NULL; + return; + } + if (mHwDevice->common.version != RADIO_DEVICE_API_VERSION_CURRENT) { + ALOGE("wrong radio hw device version %04x", mHwDevice->common.version); + radio_hw_device_close(mHwDevice); + mHwDevice = NULL; + } else { + mStatus = Result::OK; + } +} + +int BroadcastRadio::closeHalTuner(const struct radio_tuner *halTuner) +{ + ALOGV("%s", __FUNCTION__); + if (mHwDevice == NULL) { + return -ENODEV; + } + if (halTuner == 0) { + return -EINVAL; + } + return mHwDevice->close_tuner(mHwDevice, halTuner); +} + + +// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow. +Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) +{ + int rc; + radio_hal_properties_t halProperties; + Properties properties; + + if (mHwDevice == NULL) { + rc = -ENODEV; + goto exit; + } + rc = mHwDevice->get_properties(mHwDevice, &halProperties); + if (rc == 0) { + Utils::convertPropertiesFromHal(&properties, &halProperties); + } + +exit: + _hidl_cb(Utils::convertHalResult(rc), properties); + return Void(); +} + +Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio, + const sp<ITunerCallback>& callback, openTuner_cb _hidl_cb) +{ + sp<Tuner> tunerImpl = new Tuner(callback, this); + + radio_hal_band_config_t halConfig; + const struct radio_tuner *halTuner; + Utils::convertBandConfigToHal(&halConfig, &config); + int rc = mHwDevice->open_tuner(mHwDevice, &halConfig, audio, + Tuner::callback, tunerImpl.get(), + &halTuner); + if (rc == 0) { + tunerImpl->setHalTuner(halTuner); + } + + _hidl_cb(Utils::convertHalResult(rc), tunerImpl); + return Void(); +} + + +} // namespace implementation +} // namespace V1_0 +} // namespace broadcastradio +} // namespace hardware +} // namespace android
diff --git a/broadcastradio/1.0/default/BroadcastRadio.h b/broadcastradio/1.0/default/BroadcastRadio.h new file mode 100644 index 0000000..6764d82 --- /dev/null +++ b/broadcastradio/1.0/default/BroadcastRadio.h
@@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIO_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIO_H + +#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h> +#include <hidl/Status.h> +#include <hardware/radio.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_0 { +namespace implementation { + +struct BroadcastRadio : public IBroadcastRadio { + + BroadcastRadio(Class classId); + + // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow. + Return<void> getProperties(getProperties_cb _hidl_cb) override; + Return<void> openTuner(const BandConfig& config, bool audio, + const sp<ITunerCallback>& callback, + openTuner_cb _hidl_cb) override; + + + // RefBase + virtual void onFirstRef(); + + Result initCheck() { return mStatus; } + int closeHalTuner(const struct radio_tuner *halTuner); + +private: + virtual ~BroadcastRadio(); + + static const char * sClassModuleNames[]; + + Result convertHalResult(int rc); + void convertBandConfigFromHal(BandConfig *config, + const radio_hal_band_config_t *halConfig); + void convertPropertiesFromHal(Properties *properties, + const radio_hal_properties_t *halProperties); + void convertBandConfigToHal(radio_hal_band_config_t *halConfig, + const BandConfig *config); + + Result mStatus; + Class mClassId; + struct radio_hw_device *mHwDevice; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIO_H
diff --git a/broadcastradio/1.0/default/BroadcastRadioFactory.cpp b/broadcastradio/1.0/default/BroadcastRadioFactory.cpp new file mode 100644 index 0000000..d5d214c --- /dev/null +++ b/broadcastradio/1.0/default/BroadcastRadioFactory.cpp
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 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. + */ +#include "BroadcastRadioFactory.h" +#include "BroadcastRadio.h" + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_0 { +namespace implementation { + +// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow. +Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) { + sp<BroadcastRadio> impl = new BroadcastRadio(classId); + Result retval = Result::NOT_INITIALIZED; + if (impl != 0) { + retval = impl->initCheck(); + } + _hidl_cb(retval, impl); + return Void(); +} + + +IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* /* name */) { + return new BroadcastRadioFactory(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace broadcastradio +} // namespace hardware +} // namespace android
diff --git a/broadcastradio/1.0/default/BroadcastRadioFactory.h b/broadcastradio/1.0/default/BroadcastRadioFactory.h new file mode 100644 index 0000000..97f7f55 --- /dev/null +++ b/broadcastradio/1.0/default/BroadcastRadioFactory.h
@@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIOFACTORY_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIOFACTORY_H + +#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_0 { +namespace implementation { + +struct BroadcastRadioFactory : public IBroadcastRadioFactory { + // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow. + Return<void> connectModule(Class classId, connectModule_cb _hidl_cb) override; + +}; + +extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_0_BROADCASTRADIOFACTORY_H
diff --git a/broadcastradio/1.0/default/Tuner.cpp b/broadcastradio/1.0/default/Tuner.cpp new file mode 100644 index 0000000..ff643b8 --- /dev/null +++ b/broadcastradio/1.0/default/Tuner.cpp
@@ -0,0 +1,193 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "Tuner" +//#define LOG_NDEBUG 0 + +#include <log/log.h> + +#include "BroadcastRadio.h" +#include "Tuner.h" +#include "Utils.h" +#include <system/RadioMetadataWrapper.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_0 { +namespace implementation { + +void Tuner::onCallback(radio_hal_event_t *halEvent) +{ + BandConfig config; + ProgramInfo info; + hidl_vec<MetaData> metadata; + + if (mCallback != 0) { + switch(halEvent->type) { + case RADIO_EVENT_CONFIG: + Utils::convertBandConfigFromHal(&config, &halEvent->config); + mCallback->configChange(Utils::convertHalResult(halEvent->status), config); + break; + case RADIO_EVENT_ANTENNA: + mCallback->antennaStateChange(halEvent->on); + break; + case RADIO_EVENT_TUNED: + Utils::convertProgramInfoFromHal(&info, &halEvent->info); + mCallback->tuneComplete(Utils::convertHalResult(halEvent->status), info); + break; + case RADIO_EVENT_METADATA: { + uint32_t channel; + uint32_t sub_channel; + if (radio_metadata_get_channel(halEvent->metadata, &channel, &sub_channel) == 0) { + Utils::convertMetaDataFromHal(metadata, halEvent->metadata); + mCallback->newMetadata(channel, sub_channel, metadata); + } + } break; + case RADIO_EVENT_TA: + mCallback->trafficAnnouncement(halEvent->on); + break; + case RADIO_EVENT_AF_SWITCH: + Utils::convertProgramInfoFromHal(&info, &halEvent->info); + mCallback->afSwitch(info); + break; + case RADIO_EVENT_EA: + mCallback->emergencyAnnouncement(halEvent->on); + break; + case RADIO_EVENT_HW_FAILURE: + default: + mCallback->hardwareFailure(); + break; + } + } +} + +//static +void Tuner::callback(radio_hal_event_t *halEvent, void *cookie) +{ + wp<Tuner> weak(reinterpret_cast<Tuner*>(cookie)); + sp<Tuner> tuner = weak.promote(); + if (tuner == 0) return; + tuner->onCallback(halEvent); +} + +Tuner::Tuner(const sp<ITunerCallback>& callback, const wp<BroadcastRadio>& parentDevice) + : mHalTuner(NULL), mCallback(callback), mParentDevice(parentDevice) +{ + ALOGV("%s", __FUNCTION__); +} + + +Tuner::~Tuner() +{ + ALOGV("%s", __FUNCTION__); + const sp<BroadcastRadio> parentDevice = mParentDevice.promote(); + if (parentDevice != 0) { + parentDevice->closeHalTuner(mHalTuner); + } +} + +// Methods from ::android::hardware::broadcastradio::V1_0::ITuner follow. +Return<Result> Tuner::setConfiguration(const BandConfig& config) { + ALOGV("%s", __FUNCTION__); + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + radio_hal_band_config_t halConfig; + Utils::convertBandConfigToHal(&halConfig, &config); + int rc = mHalTuner->set_configuration(mHalTuner, &halConfig); + return Utils::convertHalResult(rc); +} + +Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) { + int rc; + radio_hal_band_config_t halConfig; + BandConfig config; + + ALOGV("%s", __FUNCTION__); + if (mHalTuner == NULL) { + rc = -ENODEV; + goto exit; + } + rc = mHalTuner->get_configuration(mHalTuner, &halConfig); + if (rc == 0) { + Utils::convertBandConfigFromHal(&config, &halConfig); + } + +exit: + _hidl_cb(Utils::convertHalResult(rc), config); + return Void(); +} + +Return<Result> Tuner::scan(Direction direction, bool skipSubChannel) { + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + int rc = mHalTuner->scan(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel); + return Utils::convertHalResult(rc); +} + +Return<Result> Tuner::step(Direction direction, bool skipSubChannel) { + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + int rc = mHalTuner->step(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel); + return Utils::convertHalResult(rc); +} + +Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) { + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + int rc = mHalTuner->tune(mHalTuner, channel, subChannel); + return Utils::convertHalResult(rc); +} + +Return<Result> Tuner::cancel() { + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + int rc = mHalTuner->cancel(mHalTuner); + return Utils::convertHalResult(rc); +} + +Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) { + int rc; + radio_program_info_t halInfo; + RadioMetadataWrapper metadataWrapper(&halInfo.metadata); + ProgramInfo info; + + ALOGV("%s", __FUNCTION__); + if (mHalTuner == NULL) { + rc = -ENODEV; + goto exit; + } + + rc = mHalTuner->get_program_information(mHalTuner, &halInfo); + if (rc == 0) { + Utils::convertProgramInfoFromHal(&info, &halInfo); + } + +exit: + _hidl_cb(Utils::convertHalResult(rc), info); + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace broadcastradio +} // namespace hardware +} // namespace android
diff --git a/broadcastradio/1.0/default/Tuner.h b/broadcastradio/1.0/default/Tuner.h new file mode 100644 index 0000000..bfdd4f4 --- /dev/null +++ b/broadcastradio/1.0/default/Tuner.h
@@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_0_TUNER_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_0_TUNER_H + +#include <android/hardware/broadcastradio/1.0/ITuner.h> +#include <android/hardware/broadcastradio/1.0/ITunerCallback.h> +#include <hidl/Status.h> +#include <hardware/radio.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_0 { +namespace implementation { + +struct BroadcastRadio; + +struct Tuner : public ITuner { + + Tuner(const sp<ITunerCallback>& callback, const wp<BroadcastRadio>& mParentDevice); + + // Methods from ::android::hardware::broadcastradio::V1_0::ITuner follow. + Return<Result> setConfiguration(const BandConfig& config) override; + Return<void> getConfiguration(getConfiguration_cb _hidl_cb) override; + Return<Result> scan(Direction direction, bool skipSubChannel) override; + Return<Result> step(Direction direction, bool skipSubChannel) override; + Return<Result> tune(uint32_t channel, uint32_t subChannel) override; + Return<Result> cancel() override; + Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override; + + static void callback(radio_hal_event_t *halEvent, void *cookie); + void onCallback(radio_hal_event_t *halEvent); + + void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; } + const struct radio_tuner *getHalTuner() { return mHalTuner; } + + private: + ~Tuner(); + + const struct radio_tuner *mHalTuner; + const sp<ITunerCallback> mCallback; + const wp<BroadcastRadio> mParentDevice; +}; + + +} // namespace implementation +} // namespace V1_0 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_0_TUNER_H
diff --git a/broadcastradio/1.0/default/Utils.cpp b/broadcastradio/1.0/default/Utils.cpp new file mode 100644 index 0000000..8776222 --- /dev/null +++ b/broadcastradio/1.0/default/Utils.cpp
@@ -0,0 +1,295 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "BroadcastRadioHalUtils" +//#define LOG_NDEBUG 0 + +#include <log/log.h> +#include <utils/misc.h> +#include <system/radio_metadata.h> + +#include "Utils.h" + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_0 { +namespace implementation { + +const char *Utils::sClassModuleNames[] = { + RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */ + RADIO_HARDWARE_MODULE_ID_SAT, /* corresponds to RADIO_CLASS_SAT */ + RADIO_HARDWARE_MODULE_ID_DT, /* corresponds to RADIO_CLASS_DT */ +}; + +// make sure HIDL enum values are aligned with legacy values +static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM), + "AM/FM class mismatch with legacy"); +static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT), + "SAT class mismatch with legacy"); +static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT), + "DT class mismatch with legacy"); + +static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM), + "AM band mismatch with legacy"); +static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM), + "FM band mismatch with legacy"); +static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD), + "AM HD band mismatch with legacy"); +static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD), + "FM HD band mismatch with legacy"); + +static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE), + "RDS NONE mismatch with legacy"); +static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD), + "RDS WORLD mismatch with legacy"); +static_assert(RADIO_RDS_US == static_cast<int>(Rds::US), + "RDS US mismatch with legacy"); + +static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50), + "De-emphasis 50 mismatch with legacy"); +static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75), + "De-emphasis 75 mismatch with legacy"); + +static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP), + "Direction Up mismatch with legacy"); +static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN), + "Direction Up mismatch with legacy"); + +static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID), + "Metadata type INVALID mismatch with legacy"); +static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT), + "Metadata type INT mismatch with legacy"); +static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT), + "Metadata type TEXT mismatch with legacy"); +static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW), + "Metadata type RAW mismatch with legacy"); +static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK), + "Metadata type CLOCK mismatch with legacy"); + +static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID), + "Metadata key INVALID mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI), + "Metadata key RDS_PI mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS), + "Metadata key RDS_PS mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY), + "Metadata key RDS_PTY mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY), + "Metadata key RBDS_PTY mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT), + "Metadata key RDS_RT mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE), + "Metadata key TITLE mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST), + "Metadata key ARTIST mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM), + "Metadata key ALBUM mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE), + "Metadata key GENRE mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON), + "Metadata key ICON mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART), + "Metadata key ART mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK), + "Metadata key CLOCK mismatch with legacy"); + + +//static +const char * Utils::getClassString(Class ClassId) +{ + int id = static_cast<int>(ClassId); + + if ((id < 0) || + (id >= NELEM(sClassModuleNames))) { + ALOGE("invalid class ID %d", id); + return NULL; + } + return sClassModuleNames[id]; +} + +//static +Result Utils::convertHalResult(int rc) +{ + switch (rc) { + case 0: + return Result::OK; + case -EINVAL: + return Result::INVALID_ARGUMENTS; + case -ENOSYS: + return Result::INVALID_STATE; + case -ETIMEDOUT: + return Result::TIMEOUT; + case -ENODEV: + default: + return Result::NOT_INITIALIZED; + } +} + +//static +void Utils::convertBandConfigFromHal( + BandConfig *config, + const radio_hal_band_config_t *halConfig) +{ + + config->type = static_cast<Band>(halConfig->type); + config->antennaConnected = halConfig->antenna_connected; + config->lowerLimit = halConfig->lower_limit; + config->upperLimit = halConfig->upper_limit; + config->spacings.setToExternal(const_cast<unsigned int *>(&halConfig->spacings[0]), + halConfig->num_spacings * sizeof(uint32_t)); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + config->spacings.resize(halConfig->num_spacings); + + if (config->type == Band::FM) { + config->ext.fm.deemphasis = static_cast<Deemphasis>(halConfig->fm.deemphasis); + config->ext.fm.stereo = halConfig->fm.stereo; + config->ext.fm.rds = static_cast<Rds>(halConfig->fm.rds); + config->ext.fm.ta = halConfig->fm.ta; + config->ext.fm.af = halConfig->fm.af; + config->ext.fm.ea = halConfig->fm.ea; + } else { + config->ext.am.stereo = halConfig->am.stereo; + } +} + +//static +void Utils::convertPropertiesFromHal( + Properties *properties, + const radio_hal_properties_t *halProperties) +{ + properties->classId = static_cast<Class>(halProperties->class_id); + properties->implementor.setToExternal(halProperties->implementor, strlen(halProperties->implementor)); + properties->product.setToExternal(halProperties->product, strlen(halProperties->product)); + properties->version.setToExternal(halProperties->version, strlen(halProperties->version)); + properties->serial.setToExternal(halProperties->serial, strlen(halProperties->serial)); + properties->numTuners = halProperties->num_tuners; + properties->numAudioSources = halProperties->num_audio_sources; + properties->supportsCapture = halProperties->supports_capture; + + BandConfig *bands = + new BandConfig[halProperties->num_bands]; + for (size_t i = 0; i < halProperties->num_bands; i++) { + convertBandConfigFromHal(&bands[i], &halProperties->bands[i]); + } + properties->bands.setToExternal(bands, halProperties->num_bands); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + properties->bands.resize(halProperties->num_bands); + delete[] bands; +} + +//static +void Utils::convertBandConfigToHal( + radio_hal_band_config_t *halConfig, + const BandConfig *config) +{ + + halConfig->type = static_cast<radio_band_t>(config->type); + halConfig->antenna_connected = config->antennaConnected; + halConfig->lower_limit = config->lowerLimit; + halConfig->upper_limit = config->upperLimit; + halConfig->num_spacings = config->spacings.size(); + if (halConfig->num_spacings > RADIO_NUM_SPACINGS_MAX) { + halConfig->num_spacings = RADIO_NUM_SPACINGS_MAX; + } + memcpy(halConfig->spacings, config->spacings.data(), + sizeof(uint32_t) * halConfig->num_spacings); + + if (config->type == Band::FM) { + halConfig->fm.deemphasis = static_cast<radio_deemphasis_t>(config->ext.fm.deemphasis); + halConfig->fm.stereo = config->ext.fm.stereo; + halConfig->fm.rds = static_cast<radio_rds_t>(config->ext.fm.rds); + halConfig->fm.ta = config->ext.fm.ta; + halConfig->fm.af = config->ext.fm.af; + halConfig->fm.ea = config->ext.fm.ea; + } else { + halConfig->am.stereo = config->ext.am.stereo; + } +} + + +//static +void Utils::convertProgramInfoFromHal(ProgramInfo *info, + radio_program_info_t *halInfo) +{ + info->channel = halInfo->channel; + info->subChannel = halInfo->sub_channel; + info->tuned = halInfo->tuned; + info->stereo = halInfo->stereo; + info->digital = halInfo->digital; + info->signalStrength = halInfo->signal_strength; + convertMetaDataFromHal(info->metadata, halInfo->metadata); +} + +//static +int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata, + radio_metadata_t *halMetadata) +{ + if (halMetadata == NULL) { + ALOGE("Invalid argument: halMetadata is NULL"); + return 0; + } + + int count = radio_metadata_get_count(halMetadata); + if (count <= 0) { + return count; + } + MetaData *newMetadata = + new MetaData[count]; + int outCount = 0; + for (int i = 0; i < count; i++) { + radio_metadata_key_t key; + radio_metadata_type_t type; + void *value; + size_t size; + if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 || + size == 0) { + continue; + } + switch (type) { + case RADIO_METADATA_TYPE_INT: { + newMetadata[outCount].intValue = *(static_cast<int32_t *>(value)); + } break; + case RADIO_METADATA_TYPE_TEXT: { + newMetadata[outCount].stringValue = static_cast<char *>(value); + } break; + case RADIO_METADATA_TYPE_RAW: { + newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + newMetadata[outCount].rawValue.resize(size); + } break; + case RADIO_METADATA_TYPE_CLOCK: { + radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value); + newMetadata[outCount].clockValue.utcSecondsSinceEpoch = + clock->utc_seconds_since_epoch; + newMetadata[outCount].clockValue.timezoneOffsetInMinutes = + clock->timezone_offset_in_minutes; + } break; + } + newMetadata[outCount].type = static_cast<MetadataType>(type); + newMetadata[outCount].key = static_cast<MetadataKey>(key); + outCount++; + } + metadata.setToExternal(newMetadata, outCount); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + metadata.resize(outCount); + return outCount; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace broadcastradio +} // namespace hardware +} // namespace android
diff --git a/broadcastradio/1.0/default/Utils.h b/broadcastradio/1.0/default/Utils.h new file mode 100644 index 0000000..4ef22a5 --- /dev/null +++ b/broadcastradio/1.0/default/Utils.h
@@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_0_UTILS_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_0_UTILS_H + +#include <android/hardware/broadcastradio/1.0/types.h> +#include <hardware/radio.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_0 { +namespace implementation { + +class Utils { +public: + static const char * getClassString(Class ClassId); + static Result convertHalResult(int rc); + static void convertBandConfigFromHal(BandConfig *config, + const radio_hal_band_config_t *halConfig); + static void convertPropertiesFromHal(Properties *properties, + const radio_hal_properties_t *halProperties); + static void convertBandConfigToHal(radio_hal_band_config_t *halConfig, + const BandConfig *config); + static void convertProgramInfoFromHal(ProgramInfo *info, + radio_program_info_t *halInfo); + static int convertMetaDataFromHal(hidl_vec<MetaData>& metadata, + radio_metadata_t *halMetadata); +private: + static const char * sClassModuleNames[]; + +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_0_UTILS_H
diff --git a/broadcastradio/1.0/types.hal b/broadcastradio/1.0/types.hal new file mode 100644 index 0000000..d8b2da3 --- /dev/null +++ b/broadcastradio/1.0/types.hal
@@ -0,0 +1,216 @@ +/* + * Copyright 2016 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.broadcastradio@1.0; + +enum Result : int32_t { + OK, + NOT_INITIALIZED, + INVALID_ARGUMENTS, + INVALID_STATE, + TIMEOUT, +}; + +/* + * Radio hardware module class. A given radio hardware module HAL is of one + * class only. The platform can not have more than one hardware module of + * each class. Current version of the framework only supports RADIO_CLASS_AM_FM. + */ +enum Class : uint32_t { + /* FM (including HD radio) and AM */ + AM_FM = 0, + /* Satellite Radio */ + SAT = 1, + /* Digital Radio (DAB) */ + DT = 2, +}; + +/* value for field "type" of radio band described in struct radio_hal_band_config */ +enum Band : uint32_t { + /* Amplitude Modulation band: LW, MW, SW */ + AM = 0, + /* Frequency Modulation band: FM */ + FM = 1, + /* FM HD Radio / DRM (IBOC) */ + FM_HD = 2, + /* AM HD Radio / DRM (IBOC) */ + AM_HD = 3, +}; + +/* RDS variant implemented. A struct FmBandConfig can list none or several. */ +enum Rds : uint32_t { + NONE = 0, + WORLD = (1<<0), + US = (1<<1), +}; + + +/* FM deemphasis variant implemented. + * A struct FmBandConfig can list one or more. */ +enum Deemphasis : uint32_t { + D50 = (1<<0), + D75 = (1<<1), +}; + +/* Scanning direction for scan() and step() tuner APIs */ +enum Direction : uint32_t { + UP, + DOWN +}; + +/* Unique handle allocated to a radio module */ +typedef uint32_t Handle; + + +/* Additional attributes for an FM band configuration */ +struct FmBandConfig { + /* deemphasis variant */ + Deemphasis deemphasis; + /* stereo supported */ + bool stereo; + /* RDS variants supported */ + Rds rds; + /* Traffic Announcement supported */ + bool ta; + /* Alternate Frequency supported */ + bool af; + /* Emergency announcements supported */ + bool ea; +}; + +/* Additional attributes for an AM band configuration */ +struct AmBandConfig { + /* Stereo supported */ + bool stereo; +}; + +/* Radio band configuration. Describes a given band supported by the radio + * module. The HAL can expose only one band per type with the the maximum range + * supported and all options. The framework will derive the actual regions were + * this module can operate and expose separate band configurations for + * applications to chose from. */ +struct BandConfig { + Band type; + bool antennaConnected; + uint32_t lowerLimit; + uint32_t upperLimit; + vec<uint32_t> spacings; + union Ext { + FmBandConfig fm; + AmBandConfig am; + } ext; +}; + +/* Exposes properties of a given hardware radio module. + * NOTE: current framework implementation supports only one audio source + * (num_audio_sources = 1). The source corresponds to AUDIO_DEVICE_IN_FM_TUNER. + * If more than one tuner is supported (num_tuners > 1), only one can be + * connected to the audio source. */ +struct Properties { + /* Class of this module. E.g AM_FM */ + Class classId; + /* implementor name */ + string implementor; + /* product name */ + string product; + /* product version */ + string version; + /* serial number (for subscription services) */ + string serial; + /* number of tuners controllable independently */ + uint32_t numTuners; + /* number of audio sources driven simultaneously */ + uint32_t numAudioSources; + /* the hardware supports capture of audio source from audio HAL */ + bool supportsCapture; + vec<BandConfig> bands; /* band descriptors */ +}; + +enum MetadataType : int32_t { + INVALID = -1, + /* Signed 32 bit integer */ + INT = 0, + /* String */ + TEXT = 1, + /* Raw binary data (icon or art) + This data must be transparent to the android framework */ + RAW = 2, + /* clock data, see MetaDataClock */ + CLOCK = 3, +}; + +enum MetadataKey : int32_t { + INVALID = -1, + /* RDS PI - string */ + RDS_PI = 0, + /* RDS PS - string */ + RDS_PS = 1, + /* RDS PTY - int32_t */ + RDS_PTY = 2, + /* RBDS PTY - int32_t */ + RBDS_PTY = 3, + /* RDS RT - string */ + RDS_RT = 4, + /* Song title - string */ + TITLE = 5, + /* Artist name - string */ + ARTIST = 6, + /* Album name - string */ + ALBUM = 7, + /* Musical genre - string */ + GENRE = 8, + /* Station icon - raw */ + ICON = 9, + /* Album art - raw */ + ART = 10, + /* Clock - MetaDataClock */ + CLOCK = 11, +}; + +struct MetaDataClock { + /* Seconds since epoch at GMT + 0. */ + uint64_t utcSecondsSinceEpoch; + /* Minutes offset from the GMT. */ + int32_t timezoneOffsetInMinutes; +}; + +struct MetaData { + MetadataType type; + MetadataKey key; + /* Value used for type MetadataType.INT */ + int32_t intValue; + /* Value used for type MetadataType.CLOCK */ + MetaDataClock clockValue; + /* Value used for type MetadataType.TEXT */ + string stringValue; + /* Value used for type MetadataType.RAW */ + vec<uint8_t> rawValue; +}; + + +/* Radio program information. Returned by the HAL with event RADIO_EVENT_TUNED. + * Contains information on currently tuned channel. + */ +struct ProgramInfo { + uint32_t channel; /* current channel. (e.g kHz for band type AM_FM) */ + uint32_t subChannel; /* current sub channel. (FM_HD) */ + bool tuned; /* tuned to a program or not */ + bool stereo; /* program is stereo or not */ + bool digital; /* digital program or not (e.g HD Radio program) */ + uint32_t signalStrength; /* signal strength from 0 to 100 */ + vec<MetaData> metadata; /* non empty if meta data are present (e.g PTY, song title ...) */ +}; +
diff --git a/broadcastradio/1.0/vts/Android.mk b/broadcastradio/1.0/vts/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/broadcastradio/1.0/vts/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/broadcastradio/1.0/vts/functional/Android.bp b/broadcastradio/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..cf52f49 --- /dev/null +++ b/broadcastradio/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalBroadcastradioV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalBroadcastradioV1_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.broadcastradio@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +}
diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp new file mode 100644 index 0000000..74911f0 --- /dev/null +++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
@@ -0,0 +1,604 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "BroadcastRadioHidlHalTest" +#include <VtsHalHidlTargetTestBase.h> +#include <android-base/logging.h> +#include <cutils/native_handle.h> +#include <cutils/properties.h> +#include <hidl/HidlTransportSupport.h> +#include <utils/threads.h> + +#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h> +#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h> +#include <android/hardware/broadcastradio/1.0/ITuner.h> +#include <android/hardware/broadcastradio/1.0/ITunerCallback.h> +#include <android/hardware/broadcastradio/1.0/types.h> + + +using ::android::sp; +using ::android::Mutex; +using ::android::Condition; +using ::android::hardware::Return; +using ::android::hardware::Status; +using ::android::hardware::Void; +using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory; +using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio; +using ::android::hardware::broadcastradio::V1_0::ITuner; +using ::android::hardware::broadcastradio::V1_0::ITunerCallback; +using ::android::hardware::broadcastradio::V1_0::Result; +using ::android::hardware::broadcastradio::V1_0::Class; +using ::android::hardware::broadcastradio::V1_0::Properties; +using ::android::hardware::broadcastradio::V1_0::Band; +using ::android::hardware::broadcastradio::V1_0::BandConfig; +using ::android::hardware::broadcastradio::V1_0::Direction; +using ::android::hardware::broadcastradio::V1_0::ProgramInfo; +using ::android::hardware::broadcastradio::V1_0::MetaData; + + +// The main test class for Broadcast Radio HIDL HAL. + +class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + virtual void SetUp() override { + sp<IBroadcastRadioFactory> factory = + ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>(); + if (factory != 0) { + factory->connectModule(Class::AM_FM, + [&](Result retval, const ::android::sp<IBroadcastRadio>& result) { + if (retval == Result::OK) { + mRadio = result; + } + }); + } + mTunerCallback = new MyCallback(this); + ASSERT_NE(nullptr, mRadio.get()); + ASSERT_NE(nullptr, mTunerCallback.get()); + } + + virtual void TearDown() override { + mTuner.clear(); + mRadio.clear(); + } + + class MyCallback : public ITunerCallback { + public: + + // ITunerCallback methods (see doc in ITunerCallback.hal) + virtual Return<void> hardwareFailure() { + ALOGI("%s", __FUNCTION__); + mParentTest->onHwFailureCallback(); + return Void(); + } + + virtual Return<void> configChange(Result result, const BandConfig& config) { + ALOGI("%s result %d", __FUNCTION__, result); + mParentTest->onConfigChangeCallback(result, config); + return Void(); + } + + virtual Return<void> tuneComplete(Result result, const ProgramInfo& info) { + ALOGI("%s result %d", __FUNCTION__, result); + mParentTest->onTuneCompleteCallback(result, info); + return Void(); + } + + virtual Return<void> afSwitch(const ProgramInfo& info __unused) { + return Void(); + } + + virtual Return<void> antennaStateChange(bool connected) { + ALOGI("%s connected %d", __FUNCTION__, connected); + return Void(); + } + + virtual Return<void> trafficAnnouncement(bool active) { + ALOGI("%s active %d", __FUNCTION__, active); + return Void(); + } + + virtual Return<void> emergencyAnnouncement(bool active) { + ALOGI("%s active %d", __FUNCTION__, active); + return Void(); + } + + virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused, + const ::android::hardware::hidl_vec<MetaData>& metadata __unused) { + ALOGI("%s", __FUNCTION__); + return Void(); + } + + MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {} + + private: + // BroadcastRadioHidlTest instance to which callbacks will be notified. + BroadcastRadioHidlTest *mParentTest; + }; + + + /** + * Method called by MyCallback when a callback with no status or boolean value is received + */ + void onCallback() { + Mutex::Autolock _l(mLock); + onCallback_l(); + } + + /** + * Method called by MyCallback when hardwareFailure() callback is received + */ + void onHwFailureCallback() { + Mutex::Autolock _l(mLock); + mHwFailure = true; + onCallback_l(); + } + + /** + * Method called by MyCallback when configChange() callback is received. + */ + void onConfigChangeCallback(Result result, const BandConfig& config) { + Mutex::Autolock _l(mLock); + mResultCallbackData = result; + mBandConfigCallbackData = config; + onCallback_l(); + } + + /** + * Method called by MyCallback when tuneComplete() callback is received. + */ + void onTuneCompleteCallback(Result result, const ProgramInfo& info) { + Mutex::Autolock _l(mLock); + mResultCallbackData = result; + mProgramInfoCallbackData = info; + onCallback_l(); + } + + /** + * Method called by MyCallback when a boolean indication is received + */ + void onBoolCallback(bool result) { + Mutex::Autolock _l(mLock); + mBoolCallbackData = result; + onCallback_l(); + } + + + BroadcastRadioHidlTest() : + mCallbackCalled(false), mBoolCallbackData(false), + mResultCallbackData(Result::OK), mHwFailure(false) {} + + void onCallback_l() { + if (!mCallbackCalled) { + mCallbackCalled = true; + mCallbackCond.broadcast(); + } + } + + + bool waitForCallback(nsecs_t reltime = 0) { + Mutex::Autolock _l(mLock); + nsecs_t endTime = systemTime() + reltime; + while (!mCallbackCalled) { + if (reltime == 0) { + mCallbackCond.wait(mLock); + } else { + nsecs_t now = systemTime(); + if (now > endTime) { + return false; + } + mCallbackCond.waitRelative(mLock, endTime - now); + } + } + return true; + } + + bool getProperties(); + bool openTuner(); + bool checkAntenna(); + + static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10); + static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30); + + sp<IBroadcastRadio> mRadio; + Properties mHalProperties; + sp<ITuner> mTuner; + sp<MyCallback> mTunerCallback; + Mutex mLock; + Condition mCallbackCond; + bool mCallbackCalled; + bool mBoolCallbackData; + Result mResultCallbackData; + ProgramInfo mProgramInfoCallbackData; + BandConfig mBandConfigCallbackData; + bool mHwFailure; +}; + +// A class for test environment setup (kept since this file is a template). +class BroadcastRadioHidlEnvironment : public ::testing::Environment { + public: + virtual void SetUp() {} + virtual void TearDown() {} +}; + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_0 { + +/** + * Compares two BandConfig objects for testing purposes. + */ +static bool operator==(const BandConfig& l, const BandConfig& r) { + if (l.type != r.type) return false; + if (l.antennaConnected != r.antennaConnected) return false; + if (l.lowerLimit != r.lowerLimit) return false; + if (l.upperLimit != r.upperLimit) return false; + if (l.spacings != r.spacings) return false; + if (l.type == Band::AM || l.type == Band::AM_HD) { + return l.ext.am == r.ext.am; + } else if (l.type == Band::FM || l.type == Band::FM_HD) { + return l.ext.fm == r.ext.fm; + } else { + // unsupported type + return false; + } +} + +} // V1_0 +} // broadcastradio +} // hardware +} // android + +bool BroadcastRadioHidlTest::getProperties() +{ + if (mHalProperties.bands.size() == 0) { + Result halResult = Result::NOT_INITIALIZED; + Return<void> hidlReturn = + mRadio->getProperties([&](Result result, const Properties& properties) { + halResult = result; + if (result == Result::OK) { + mHalProperties = properties; + } + }); + + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(Result::OK, halResult); + EXPECT_EQ(Class::AM_FM, mHalProperties.classId); + EXPECT_GT(mHalProperties.numTuners, 0u); + EXPECT_GT(mHalProperties.bands.size(), 0u); + } + return mHalProperties.bands.size() > 0; +} + +bool BroadcastRadioHidlTest::openTuner() +{ + if (!getProperties()) { + return false; + } + if (mTuner.get() == nullptr) { + Result halResult = Result::NOT_INITIALIZED; + Return<void> hidlReturn = + mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback, + [&](Result result, const sp<ITuner>& tuner) { + halResult = result; + if (result == Result::OK) { + mTuner = tuner; + } + }); + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(Result::OK, halResult); + EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs)); + } + EXPECT_NE(nullptr, mTuner.get()); + return nullptr != mTuner.get(); +} + +bool BroadcastRadioHidlTest::checkAntenna() +{ + BandConfig halConfig; + Result halResult = Result::NOT_INITIALIZED; + Return<void> hidlReturn = + mTuner->getConfiguration([&](Result result, const BandConfig& config) { + halResult = result; + if (result == Result::OK) { + halConfig = config; + } + }); + + return ((halResult == Result::OK) && (halConfig.antennaConnected == true)); +} + + +/** + * Test IBroadcastRadio::getProperties() method + * + * Verifies that: + * - the HAL implements the method + * - the method returns 0 (no error) + * - the implementation class is AM_FM + * - the implementation supports at least one tuner + * - the implementation supports at one band + */ +TEST_F(BroadcastRadioHidlTest, GetProperties) { + EXPECT_EQ(true, getProperties()); +} + +/** + * Test IBroadcastRadio::openTuner() method + * + * Verifies that: + * - the HAL implements the method + * - the method returns 0 (no error) and a valid ITuner interface + */ +TEST_F(BroadcastRadioHidlTest, OpenTuner) { + EXPECT_EQ(true, openTuner()); +} + +/** + * Test IBroadcastRadio::openTuner() after ITuner disposal. + * + * Verifies that: + * - ITuner destruction gets propagated through HAL + * - the openTuner method works well when called for the second time + */ +TEST_F(BroadcastRadioHidlTest, ReopenTuner) { + EXPECT_TRUE(openTuner()); + mTuner.clear(); + EXPECT_TRUE(openTuner()); +} + +/** + * Test IBroadcastRadio::openTuner() method called twice. + * + * Verifies that: + * - the openTuner method fails when called for the second time without deleting previous + * ITuner instance + */ +TEST_F(BroadcastRadioHidlTest, OpenTunerTwice) { + EXPECT_TRUE(openTuner()); + + Result halResult = Result::NOT_INITIALIZED; + Return<void> hidlReturn = + mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback, + [&](Result result, const sp<ITuner>&) { + halResult = result; + }); + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(Result::INVALID_STATE, halResult); + EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); +} + +/** + * Test ITuner::setConfiguration() and getConfiguration methods + * + * Verifies that: + * - the HAL implements both methods + * - the methods return 0 (no error) + * - the configuration callback is received within kConfigCallbacktimeoutNs ns + * - the configuration read back from HAl has the same class Id + */ +TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) { + ASSERT_EQ(true, openTuner()); + // test setConfiguration + mCallbackCalled = false; + Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[1]); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs)); + EXPECT_EQ(Result::OK, mResultCallbackData); + EXPECT_EQ(mHalProperties.bands[1], mBandConfigCallbackData); + + // test getConfiguration + BandConfig halConfig; + Result halResult; + Return<void> hidlReturn = + mTuner->getConfiguration([&](Result result, const BandConfig& config) { + halResult = result; + if (result == Result::OK) { + halConfig = config; + } + }); + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(Result::OK, halResult); + EXPECT_EQ(mHalProperties.bands[1], halConfig); +} + +/** + * Test ITuner::setConfiguration() with invalid arguments. + * + * Verifies that: + * - the methods returns INVALID_ARGUMENTS on invalid arguments + * - the method recovers and succeeds after passing correct arguments + */ +TEST_F(BroadcastRadioHidlTest, SetConfigurationFails) { + ASSERT_EQ(true, openTuner()); + + // Let's define a config that's bad for sure. + BandConfig badConfig = {}; + badConfig.type = Band::FM; + badConfig.lowerLimit = 0xFFFFFFFF; + badConfig.upperLimit = 0; + badConfig.spacings = (std::vector<uint32_t>){ 0 }; + + // Test setConfiguration failing on bad data. + mCallbackCalled = false; + auto setResult = mTuner->setConfiguration(badConfig); + EXPECT_TRUE(setResult.isOk()); + EXPECT_EQ(Result::INVALID_ARGUMENTS, setResult); + + // Test setConfiguration recovering after passing good data. + mCallbackCalled = false; + setResult = mTuner->setConfiguration(mHalProperties.bands[0]); + EXPECT_TRUE(setResult.isOk()); + EXPECT_EQ(Result::OK, setResult); + EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs)); + EXPECT_EQ(Result::OK, mResultCallbackData); +} + +/** + * Test ITuner::scan + * + * Verifies that: + * - the HAL implements the method + * - the method returns 0 (no error) + * - the tuned callback is received within kTuneCallbacktimeoutNs ns + */ +TEST_F(BroadcastRadioHidlTest, Scan) { + ASSERT_EQ(true, openTuner()); + ASSERT_TRUE(checkAntenna()); + // test scan UP + mCallbackCalled = false; + Return<Result> hidlResult = mTuner->scan(Direction::UP, true); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); + + // test scan DOWN + mCallbackCalled = false; + hidlResult = mTuner->scan(Direction::DOWN, true); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); +} + +/** + * Test ITuner::step + * + * Verifies that: + * - the HAL implements the method + * - the method returns 0 (no error) + * - the tuned callback is received within kTuneCallbacktimeoutNs ns + */ +TEST_F(BroadcastRadioHidlTest, Step) { + ASSERT_EQ(true, openTuner()); + ASSERT_TRUE(checkAntenna()); + // test step UP + mCallbackCalled = false; + Return<Result> hidlResult = mTuner->step(Direction::UP, true); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); + + // test step DOWN + mCallbackCalled = false; + hidlResult = mTuner->step(Direction::DOWN, true); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); +} + +/** + * Test ITuner::tune, getProgramInformation and cancel methods + * + * Verifies that: + * - the HAL implements the methods + * - the methods return 0 (no error) + * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune() + */ +TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) { + ASSERT_EQ(true, openTuner()); + ASSERT_TRUE(checkAntenna()); + + // test tune + ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u); + ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit); + + // test scan UP + uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit; + uint32_t upperLimit = mHalProperties.bands[0].upperLimit; + uint32_t spacing = mHalProperties.bands[0].spacings[0]; + + uint32_t channel = + lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing; + mCallbackCalled = false; + mResultCallbackData = Result::NOT_INITIALIZED; + Return<Result> hidlResult = mTuner->tune(channel, 0); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); + EXPECT_EQ(channel, mProgramInfoCallbackData.channel); + + // test getProgramInformation + ProgramInfo halInfo; + Result halResult = Result::NOT_INITIALIZED; + Return<void> hidlReturn = mTuner->getProgramInformation( + [&](Result result, const ProgramInfo& info) { + halResult = result; + if (result == Result::OK) { + halInfo = info; + } + }); + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(Result::OK, halResult); + if (mResultCallbackData == Result::OK) { + EXPECT_EQ(true, halInfo.tuned); + EXPECT_LE(halInfo.channel, upperLimit); + EXPECT_GE(halInfo.channel, lowerLimit); + } else { + EXPECT_EQ(false, halInfo.tuned); + } + + // test cancel + mTuner->tune(lowerLimit, 0); + hidlResult = mTuner->cancel(); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); +} + +/** + * Test ITuner::tune failing when channel out of the range is provided. + * + * Verifies that: + * - the method returns INVALID_ARGUMENTS when applicable + * - the method recovers and succeeds after passing correct arguments + */ +TEST_F(BroadcastRadioHidlTest, TuneFailsOutOfBounds) { + ASSERT_TRUE(openTuner()); + ASSERT_TRUE(checkAntenna()); + + // get current channel bounds + BandConfig halConfig; + Result halResult; + auto configResult = mTuner->getConfiguration([&](Result result, const BandConfig& config) { + halResult = result; + halConfig = config; + }); + ASSERT_TRUE(configResult.isOk()); + ASSERT_EQ(Result::OK, halResult); + + // try to tune slightly above the limit and expect to fail + auto badChannel = halConfig.upperLimit + halConfig.spacings[0]; + auto tuneResult = mTuner->tune(badChannel, 0); + EXPECT_TRUE(tuneResult.isOk()); + EXPECT_EQ(Result::INVALID_ARGUMENTS, tuneResult); + EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); + + // tuning exactly at the limit should succeed + auto goodChannel = halConfig.upperLimit; + tuneResult = mTuner->tune(goodChannel, 0); + EXPECT_TRUE(tuneResult.isOk()); + EXPECT_EQ(Result::OK, tuneResult); + EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); +} + + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +}
diff --git a/broadcastradio/1.1/Android.bp b/broadcastradio/1.1/Android.bp new file mode 100644 index 0000000..c9a8b10 --- /dev/null +++ b/broadcastradio/1.1/Android.bp
@@ -0,0 +1,76 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.broadcastradio@1.1_hal", + srcs: [ + "types.hal", + "IBroadcastRadioFactory.hal", + "ITuner.hal", + "ITunerCallback.hal", + ], +} + +genrule { + name: "android.hardware.broadcastradio@1.1_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.broadcastradio@1.1", + srcs: [ + ":android.hardware.broadcastradio@1.1_hal", + ], + out: [ + "android/hardware/broadcastradio/1.1/types.cpp", + "android/hardware/broadcastradio/1.1/BroadcastRadioFactoryAll.cpp", + "android/hardware/broadcastradio/1.1/TunerAll.cpp", + "android/hardware/broadcastradio/1.1/TunerCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.broadcastradio@1.1_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.broadcastradio@1.1", + srcs: [ + ":android.hardware.broadcastradio@1.1_hal", + ], + out: [ + "android/hardware/broadcastradio/1.1/types.h", + "android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.1/IHwBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.1/BnHwBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.1/BpHwBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.1/BsBroadcastRadioFactory.h", + "android/hardware/broadcastradio/1.1/ITuner.h", + "android/hardware/broadcastradio/1.1/IHwTuner.h", + "android/hardware/broadcastradio/1.1/BnHwTuner.h", + "android/hardware/broadcastradio/1.1/BpHwTuner.h", + "android/hardware/broadcastradio/1.1/BsTuner.h", + "android/hardware/broadcastradio/1.1/ITunerCallback.h", + "android/hardware/broadcastradio/1.1/IHwTunerCallback.h", + "android/hardware/broadcastradio/1.1/BnHwTunerCallback.h", + "android/hardware/broadcastradio/1.1/BpHwTunerCallback.h", + "android/hardware/broadcastradio/1.1/BsTunerCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.broadcastradio@1.1", + generated_sources: ["android.hardware.broadcastradio@1.1_genc++"], + generated_headers: ["android.hardware.broadcastradio@1.1_genc++_headers"], + export_generated_headers: ["android.hardware.broadcastradio@1.1_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.broadcastradio@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.broadcastradio@1.0", + ], +}
diff --git a/broadcastradio/1.1/Android.mk b/broadcastradio/1.1/Android.mk new file mode 100644 index 0000000..0c4c55d --- /dev/null +++ b/broadcastradio/1.1/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2017 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/broadcastradio/1.1/IBroadcastRadioFactory.hal b/broadcastradio/1.1/IBroadcastRadioFactory.hal new file mode 100644 index 0000000..fce1cc0 --- /dev/null +++ b/broadcastradio/1.1/IBroadcastRadioFactory.hal
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 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.broadcastradio@1.1; + +import @1.0::IBroadcastRadioFactory; + +/** + * To use 1.1 features you must cast specific interfaces after being returned from 1.0 HAL, + * for example V1_1::ITuner::castFrom() after retrieving it from IBroadcastRadio::openTuner(). + * The 1.1 server must always return the 1.1 version of specific interface. + */ +interface IBroadcastRadioFactory extends @1.0::IBroadcastRadioFactory { +};
diff --git a/broadcastradio/1.1/ITuner.hal b/broadcastradio/1.1/ITuner.hal new file mode 100644 index 0000000..4f34019 --- /dev/null +++ b/broadcastradio/1.1/ITuner.hal
@@ -0,0 +1,50 @@ +/* + * Copyright (C) 2017 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.broadcastradio@1.1; + +import @1.0::ITuner; + +interface ITuner extends @1.0::ITuner { + + /** + * Retrieve current station information. + * @return result OK if scan successfully started + * NOT_INITIALIZED if another error occurs + * @return info Current program information. + */ + getProgramInformation_1_1() generates(Result result, ProgramInfo info); + + /** + * Retrieve station list. + * + * This call does not trigger actual scan, but operates on the list cached + * internally at the driver level. + * + * @param filter vendor-specific filter for the stations to be retrieved. + * An empty string MUST result in full list. + * Client application MUST verify vendor/product name + * before setting this parameter to anything else. + * @return result OK if the list was successfully retrieved. + * NOT_READY if the scan is in progress. + * NOT_STARTED if the scan has not been started. + * NOT_INITIALIZED if any other error occurs. + * @return programList List of stations available for user. + */ + getProgramList(string filter) + generates(ProgramListResult result, vec<ProgramInfo> programList); + +};
diff --git a/broadcastradio/1.1/ITunerCallback.hal b/broadcastradio/1.1/ITunerCallback.hal new file mode 100644 index 0000000..4af6b1f --- /dev/null +++ b/broadcastradio/1.1/ITunerCallback.hal
@@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 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.broadcastradio@1.1; + +import @1.0::ITunerCallback; + +/** + * Some methods of @1.1::ITunerCallback are updated versions of those from @1.0:ITunerCallback. + * All 1.1 drivers should call both (eg. tuneComplete and tuneComplete_1_1), while 1.1 clients + * should ignore 1.0 ones, to avoid receiving a callback twice. + */ +interface ITunerCallback extends @1.0::ITunerCallback { + /* + * Method called by the HAL when a tuning operation completes + * following a step(), scan() or tune() command. + * @param result OK if tune succeeded or TIMEOUT in case of time out. + * @param info A ProgramInfo structure describing the tuned station. + */ + oneway tuneComplete_1_1(Result result, ProgramInfo info); + + /* + * Method called by the HAL when a frequency switch occurs. + * @param info A ProgramInfo structure describing the new tuned station. + */ + oneway afSwitch_1_1(ProgramInfo info); +};
diff --git a/broadcastradio/1.1/WARNING b/broadcastradio/1.1/WARNING new file mode 100644 index 0000000..e867cfa --- /dev/null +++ b/broadcastradio/1.1/WARNING
@@ -0,0 +1 @@ +This is experimental interface, do not use it yet.
diff --git a/broadcastradio/1.1/default/Android.mk b/broadcastradio/1.1/default/Android.mk new file mode 100644 index 0000000..bb32d50 --- /dev/null +++ b/broadcastradio/1.1/default/Android.mk
@@ -0,0 +1,46 @@ +# +# Copyright (C) 2017 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.broadcastradio@1.1-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_CFLAGS += -Werror -Wall -Wextra +LOCAL_SRC_FILES := \ + BroadcastRadio.cpp \ + BroadcastRadioFactory.cpp \ + Tuner.cpp \ + Utils.cpp + +LOCAL_SHARED_LIBRARIES := \ + libhidlbase \ + libhidltransport \ + libutils \ + liblog \ + libhardware \ + android.hardware.broadcastradio@1.0 \ + android.hardware.broadcastradio@1.1 \ + libradio_metadata + +ifeq ($(strip $(AUDIOSERVER_MULTILIB)),) +LOCAL_MULTILIB := 32 +else +LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) +endif + +include $(BUILD_SHARED_LIBRARY)
diff --git a/broadcastradio/1.1/default/BroadcastRadio.cpp b/broadcastradio/1.1/default/BroadcastRadio.cpp new file mode 100644 index 0000000..611267b --- /dev/null +++ b/broadcastradio/1.1/default/BroadcastRadio.cpp
@@ -0,0 +1,140 @@ +/* + * Copyright (C) 2017 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. + */ +#define LOG_TAG "BroadcastRadio" +//#define LOG_NDEBUG 0 + +#include <log/log.h> + +#include "BroadcastRadio.h" +#include "Tuner.h" +#include "Utils.h" + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +using ::android::sp; + +BroadcastRadio::BroadcastRadio(Class classId) + : mStatus(Result::NOT_INITIALIZED), mClassId(classId), mHwDevice(NULL) +{ +} + +BroadcastRadio::~BroadcastRadio() +{ + if (mHwDevice != NULL) { + radio_hw_device_close(mHwDevice); + } +} + +void BroadcastRadio::onFirstRef() +{ + const hw_module_t *mod; + int rc; + ALOGI("%s mClassId %d", __FUNCTION__, mClassId); + + mHwDevice = NULL; + const char *classString = Utils::getClassString(mClassId); + if (classString == NULL) { + ALOGE("invalid class ID %d", mClassId); + mStatus = Result::INVALID_ARGUMENTS; + return; + } + + ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s", + __FUNCTION__, RADIO_HARDWARE_MODULE_ID, classString); + + rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, classString, &mod); + if (rc != 0) { + ALOGE("couldn't load radio module %s.%s (%s)", + RADIO_HARDWARE_MODULE_ID, classString, strerror(-rc)); + return; + } + rc = radio_hw_device_open(mod, &mHwDevice); + if (rc != 0) { + ALOGE("couldn't open radio hw device in %s.%s (%s)", + RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc)); + mHwDevice = NULL; + return; + } + if (mHwDevice->common.version != RADIO_DEVICE_API_VERSION_CURRENT) { + ALOGE("wrong radio hw device version %04x", mHwDevice->common.version); + radio_hw_device_close(mHwDevice); + mHwDevice = NULL; + } else { + mStatus = Result::OK; + } +} + +int BroadcastRadio::closeHalTuner(const struct radio_tuner *halTuner) +{ + ALOGV("%s", __FUNCTION__); + if (mHwDevice == NULL) { + return -ENODEV; + } + if (halTuner == 0) { + return -EINVAL; + } + return mHwDevice->close_tuner(mHwDevice, halTuner); +} + + +// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow. +Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) +{ + int rc; + radio_hal_properties_t halProperties; + Properties properties; + + if (mHwDevice == NULL) { + rc = -ENODEV; + goto exit; + } + rc = mHwDevice->get_properties(mHwDevice, &halProperties); + if (rc == 0) { + Utils::convertPropertiesFromHal(&properties, &halProperties); + } + +exit: + _hidl_cb(Utils::convertHalResult(rc), properties); + return Void(); +} + +Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio, + const sp<V1_0::ITunerCallback>& callback, openTuner_cb _hidl_cb) +{ + sp<Tuner> tunerImpl = new Tuner(callback, this); + + radio_hal_band_config_t halConfig; + const struct radio_tuner *halTuner; + Utils::convertBandConfigToHal(&halConfig, &config); + int rc = mHwDevice->open_tuner(mHwDevice, &halConfig, audio, Tuner::callback, + tunerImpl.get(), &halTuner); + if (rc == 0) { + tunerImpl->setHalTuner(halTuner); + } + + _hidl_cb(Utils::convertHalResult(rc), tunerImpl); + return Void(); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android
diff --git a/broadcastradio/1.1/default/BroadcastRadio.h b/broadcastradio/1.1/default/BroadcastRadio.h new file mode 100644 index 0000000..068979d --- /dev/null +++ b/broadcastradio/1.1/default/BroadcastRadio.h
@@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H + +#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h> +#include <android/hardware/broadcastradio/1.1/types.h> +#include <hardware/radio.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +using V1_0::Class; +using V1_0::BandConfig; +using V1_0::Properties; + +struct BroadcastRadio : public V1_0::IBroadcastRadio { + + BroadcastRadio(Class classId); + + // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadio follow. + Return<void> getProperties(getProperties_cb _hidl_cb) override; + Return<void> openTuner(const BandConfig& config, bool audio, + const sp<V1_0::ITunerCallback>& callback, openTuner_cb _hidl_cb) override; + + // RefBase + virtual void onFirstRef() override; + + Result initCheck() { return mStatus; } + int closeHalTuner(const struct radio_tuner *halTuner); + +private: + virtual ~BroadcastRadio(); + + static const char * sClassModuleNames[]; + + Result convertHalResult(int rc); + void convertBandConfigFromHal(BandConfig *config, + const radio_hal_band_config_t *halConfig); + void convertPropertiesFromHal(Properties *properties, + const radio_hal_properties_t *halProperties); + void convertBandConfigToHal(radio_hal_band_config_t *halConfig, + const BandConfig *config); + + Result mStatus; + Class mClassId; + struct radio_hw_device *mHwDevice; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H
diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp new file mode 100644 index 0000000..c8b6c39 --- /dev/null +++ b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 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. + */ +#include "BroadcastRadioFactory.h" +#include "BroadcastRadio.h" + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow. +Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) { + sp<BroadcastRadio> impl = new BroadcastRadio(classId); + Result retval = Result::NOT_INITIALIZED; + if (impl != 0) { + retval = impl->initCheck(); + } + _hidl_cb(retval, impl); + return Void(); +} + + +IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* /* name */) { + return new BroadcastRadioFactory(); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android
diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.h b/broadcastradio/1.1/default/BroadcastRadioFactory.h new file mode 100644 index 0000000..8eb8514 --- /dev/null +++ b/broadcastradio/1.1/default/BroadcastRadioFactory.h
@@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H + +#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h> +#include <android/hardware/broadcastradio/1.1/types.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +using V1_0::Class; + +struct BroadcastRadioFactory : public IBroadcastRadioFactory { + // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow. + Return<void> connectModule(Class classId, connectModule_cb _hidl_cb) override; +}; + +extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name); + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H
diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp new file mode 100644 index 0000000..b4eb184 --- /dev/null +++ b/broadcastradio/1.1/default/Tuner.cpp
@@ -0,0 +1,214 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "Tuner" +//#define LOG_NDEBUG 0 + +#include <log/log.h> + +#include "BroadcastRadio.h" +#include "Tuner.h" +#include "Utils.h" +#include <system/RadioMetadataWrapper.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +void Tuner::onCallback(radio_hal_event_t *halEvent) +{ + BandConfig config; + ProgramInfo info; + hidl_vec<MetaData> metadata; + + if (mCallback != 0) { + switch(halEvent->type) { + case RADIO_EVENT_CONFIG: + Utils::convertBandConfigFromHal(&config, &halEvent->config); + mCallback->configChange(Utils::convertHalResult(halEvent->status), config); + break; + case RADIO_EVENT_ANTENNA: + mCallback->antennaStateChange(halEvent->on); + break; + case RADIO_EVENT_TUNED: + Utils::convertProgramInfoFromHal(&info, &halEvent->info); + if (mCallback1_1 != nullptr) { + mCallback1_1->tuneComplete_1_1(Utils::convertHalResult(halEvent->status), info); + } + mCallback->tuneComplete(Utils::convertHalResult(halEvent->status), info.base); + break; + case RADIO_EVENT_METADATA: { + uint32_t channel; + uint32_t sub_channel; + if (radio_metadata_get_channel(halEvent->metadata, &channel, &sub_channel) == 0) { + Utils::convertMetaDataFromHal(metadata, halEvent->metadata); + mCallback->newMetadata(channel, sub_channel, metadata); + } + } break; + case RADIO_EVENT_TA: + mCallback->trafficAnnouncement(halEvent->on); + break; + case RADIO_EVENT_AF_SWITCH: + Utils::convertProgramInfoFromHal(&info, &halEvent->info); + if (mCallback1_1 != nullptr) { + mCallback1_1->afSwitch_1_1(info); + } + mCallback->afSwitch(info.base); + break; + case RADIO_EVENT_EA: + mCallback->emergencyAnnouncement(halEvent->on); + break; + case RADIO_EVENT_HW_FAILURE: + default: + mCallback->hardwareFailure(); + break; + } + } +} + +//static +void Tuner::callback(radio_hal_event_t *halEvent, void *cookie) +{ + wp<Tuner> weak(reinterpret_cast<Tuner*>(cookie)); + sp<Tuner> tuner = weak.promote(); + if (tuner == 0) return; + tuner->onCallback(halEvent); +} + +Tuner::Tuner(const sp<V1_0::ITunerCallback>& callback, const wp<BroadcastRadio>& parentDevice) + : mHalTuner(NULL), mCallback(callback), mCallback1_1(ITunerCallback::castFrom(callback)), + mParentDevice(parentDevice) +{ + ALOGV("%s", __FUNCTION__); +} + + +Tuner::~Tuner() +{ + ALOGV("%s", __FUNCTION__); + const sp<BroadcastRadio> parentDevice = mParentDevice.promote(); + if (parentDevice != 0) { + parentDevice->closeHalTuner(mHalTuner); + } +} + +// Methods from ::android::hardware::broadcastradio::V1_1::ITuner follow. +Return<Result> Tuner::setConfiguration(const BandConfig& config) { + ALOGV("%s", __FUNCTION__); + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + radio_hal_band_config_t halConfig; + Utils::convertBandConfigToHal(&halConfig, &config); + int rc = mHalTuner->set_configuration(mHalTuner, &halConfig); + return Utils::convertHalResult(rc); +} + +Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) { + int rc; + radio_hal_band_config_t halConfig; + BandConfig config; + + ALOGV("%s", __FUNCTION__); + if (mHalTuner == NULL) { + rc = -ENODEV; + goto exit; + } + rc = mHalTuner->get_configuration(mHalTuner, &halConfig); + if (rc == 0) { + Utils::convertBandConfigFromHal(&config, &halConfig); + } + +exit: + _hidl_cb(Utils::convertHalResult(rc), config); + return Void(); +} + +Return<Result> Tuner::scan(Direction direction, bool skipSubChannel) { + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + int rc = mHalTuner->scan(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel); + return Utils::convertHalResult(rc); +} + +Return<Result> Tuner::step(Direction direction, bool skipSubChannel) { + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + int rc = mHalTuner->step(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel); + return Utils::convertHalResult(rc); +} + +Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) { + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + int rc = mHalTuner->tune(mHalTuner, channel, subChannel); + return Utils::convertHalResult(rc); +} + +Return<Result> Tuner::cancel() { + if (mHalTuner == NULL) { + return Utils::convertHalResult(-ENODEV); + } + int rc = mHalTuner->cancel(mHalTuner); + return Utils::convertHalResult(rc); +} + +Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + return getProgramInformation_1_1([&](Result result, const ProgramInfo& info) { + _hidl_cb(result, info.base); + }); +} + +Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) { + int rc; + radio_program_info_t halInfo; + RadioMetadataWrapper metadataWrapper(&halInfo.metadata); + ProgramInfo info; + + ALOGV("%s", __FUNCTION__); + if (mHalTuner == NULL) { + rc = -ENODEV; + goto exit; + } + + rc = mHalTuner->get_program_information(mHalTuner, &halInfo); + if (rc == 0) { + Utils::convertProgramInfoFromHal(&info, &halInfo); + } + +exit: + _hidl_cb(Utils::convertHalResult(rc), info); + return Void(); +} + +Return<void> Tuner::getProgramList(const hidl_string& filter __unused, getProgramList_cb _hidl_cb) { + hidl_vec<ProgramInfo> pList; + // TODO(b/34054813): do the actual implementation. + _hidl_cb(ProgramListResult::NOT_INITIALIZED, pList); + return Void(); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android
diff --git a/broadcastradio/1.1/default/Tuner.h b/broadcastradio/1.1/default/Tuner.h new file mode 100644 index 0000000..fcf053a --- /dev/null +++ b/broadcastradio/1.1/default/Tuner.h
@@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H + +#include <android/hardware/broadcastradio/1.1/ITuner.h> +#include <android/hardware/broadcastradio/1.1/ITunerCallback.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +using V1_0::Direction; + +struct BroadcastRadio; + +struct Tuner : public ITuner { + + Tuner(const sp<V1_0::ITunerCallback>& callback, const wp<BroadcastRadio>& mParentDevice); + + // Methods from ::android::hardware::broadcastradio::V1_1::ITuner follow. + Return<Result> setConfiguration(const BandConfig& config) override; + Return<void> getConfiguration(getConfiguration_cb _hidl_cb) override; + Return<Result> scan(Direction direction, bool skipSubChannel) override; + Return<Result> step(Direction direction, bool skipSubChannel) override; + Return<Result> tune(uint32_t channel, uint32_t subChannel) override; + Return<Result> cancel() override; + Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override; + Return<void> getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) override; + Return<void> getProgramList(const hidl_string& filter, getProgramList_cb _hidl_cb) override; + + static void callback(radio_hal_event_t *halEvent, void *cookie); + void onCallback(radio_hal_event_t *halEvent); + + void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; } + const struct radio_tuner *getHalTuner() { return mHalTuner; } + +private: + ~Tuner(); + + const struct radio_tuner *mHalTuner; + const sp<V1_0::ITunerCallback> mCallback; + const sp<V1_1::ITunerCallback> mCallback1_1; + const wp<BroadcastRadio> mParentDevice; +}; + + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H
diff --git a/broadcastradio/1.1/default/Utils.cpp b/broadcastradio/1.1/default/Utils.cpp new file mode 100644 index 0000000..e21344e --- /dev/null +++ b/broadcastradio/1.1/default/Utils.cpp
@@ -0,0 +1,299 @@ +/* + * Copyright (C) 2017 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. + */ +#define LOG_TAG "BroadcastRadioHalUtils" +//#define LOG_NDEBUG 0 + +#include <log/log.h> +#include <system/radio_metadata.h> + +#include "Utils.h" + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +using V1_0::Band; +using V1_0::Deemphasis; +using V1_0::Direction; +using V1_0::MetadataKey; +using V1_0::MetadataType; +using V1_0::Rds; + +const char *Utils::sClassModuleNames[] = { + RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */ + RADIO_HARDWARE_MODULE_ID_SAT, /* corresponds to RADIO_CLASS_SAT */ + RADIO_HARDWARE_MODULE_ID_DT, /* corresponds to RADIO_CLASS_DT */ +}; + +// make sure HIDL enum values are aligned with legacy values +static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM), + "AM/FM class mismatch with legacy"); +static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT), + "SAT class mismatch with legacy"); +static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT), + "DT class mismatch with legacy"); + +static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM), + "AM band mismatch with legacy"); +static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM), + "FM band mismatch with legacy"); +static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD), + "AM HD band mismatch with legacy"); +static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD), + "FM HD band mismatch with legacy"); + +static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE), + "RDS NONE mismatch with legacy"); +static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD), + "RDS WORLD mismatch with legacy"); +static_assert(RADIO_RDS_US == static_cast<int>(Rds::US), + "RDS US mismatch with legacy"); + +static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50), + "De-emphasis 50 mismatch with legacy"); +static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75), + "De-emphasis 75 mismatch with legacy"); + +static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP), + "Direction Up mismatch with legacy"); +static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN), + "Direction Up mismatch with legacy"); + +static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID), + "Metadata type INVALID mismatch with legacy"); +static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT), + "Metadata type INT mismatch with legacy"); +static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT), + "Metadata type TEXT mismatch with legacy"); +static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW), + "Metadata type RAW mismatch with legacy"); +static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK), + "Metadata type CLOCK mismatch with legacy"); + +static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID), + "Metadata key INVALID mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI), + "Metadata key RDS_PI mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS), + "Metadata key RDS_PS mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY), + "Metadata key RDS_PTY mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY), + "Metadata key RBDS_PTY mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT), + "Metadata key RDS_RT mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE), + "Metadata key TITLE mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST), + "Metadata key ARTIST mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM), + "Metadata key ALBUM mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE), + "Metadata key GENRE mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON), + "Metadata key ICON mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART), + "Metadata key ART mismatch with legacy"); +static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK), + "Metadata key CLOCK mismatch with legacy"); + + +//static +const char * Utils::getClassString(Class ClassId) +{ + int id = static_cast<int>(ClassId); + + if ((id < 0) || + (id >= NELEM(sClassModuleNames))) { + ALOGE("invalid class ID %d", id); + return NULL; + } + return sClassModuleNames[id]; +} + +//static +Result Utils::convertHalResult(int rc) +{ + switch (rc) { + case 0: + return Result::OK; + case -EINVAL: + return Result::INVALID_ARGUMENTS; + case -ENOSYS: + return Result::INVALID_STATE; + case -ETIMEDOUT: + return Result::TIMEOUT; + case -ENODEV: + default: + return Result::NOT_INITIALIZED; + } +} + +//static +void Utils::convertBandConfigFromHal( + BandConfig *config, + const radio_hal_band_config_t *halConfig) +{ + + config->type = static_cast<Band>(halConfig->type); + config->antennaConnected = halConfig->antenna_connected; + config->lowerLimit = halConfig->lower_limit; + config->upperLimit = halConfig->upper_limit; + config->spacings.setToExternal(const_cast<unsigned int *>(&halConfig->spacings[0]), + halConfig->num_spacings * sizeof(uint32_t)); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + config->spacings.resize(halConfig->num_spacings); + + if (config->type == Band::FM) { + config->ext.fm.deemphasis = static_cast<Deemphasis>(halConfig->fm.deemphasis); + config->ext.fm.stereo = halConfig->fm.stereo; + config->ext.fm.rds = static_cast<Rds>(halConfig->fm.rds); + config->ext.fm.ta = halConfig->fm.ta; + config->ext.fm.af = halConfig->fm.af; + config->ext.fm.ea = halConfig->fm.ea; + } else { + config->ext.am.stereo = halConfig->am.stereo; + } +} + +//static +void Utils::convertPropertiesFromHal(Properties *properties, + const radio_hal_properties_t *halProperties) +{ + properties->classId = static_cast<Class>(halProperties->class_id); + properties->implementor.setToExternal(halProperties->implementor, strlen(halProperties->implementor)); + properties->product.setToExternal(halProperties->product, strlen(halProperties->product)); + properties->version.setToExternal(halProperties->version, strlen(halProperties->version)); + properties->serial.setToExternal(halProperties->serial, strlen(halProperties->serial)); + properties->numTuners = halProperties->num_tuners; + properties->numAudioSources = halProperties->num_audio_sources; + properties->supportsCapture = halProperties->supports_capture; + + BandConfig *bands = + new BandConfig[halProperties->num_bands]; + for (size_t i = 0; i < halProperties->num_bands; i++) { + convertBandConfigFromHal(&bands[i], &halProperties->bands[i]); + } + properties->bands.setToExternal(bands, halProperties->num_bands); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + properties->bands.resize(halProperties->num_bands); + delete[] bands; +} + +//static +void Utils::convertBandConfigToHal(radio_hal_band_config_t *halConfig, const BandConfig *config) +{ + halConfig->type = static_cast<radio_band_t>(config->type); + halConfig->antenna_connected = config->antennaConnected; + halConfig->lower_limit = config->lowerLimit; + halConfig->upper_limit = config->upperLimit; + halConfig->num_spacings = config->spacings.size(); + if (halConfig->num_spacings > RADIO_NUM_SPACINGS_MAX) { + halConfig->num_spacings = RADIO_NUM_SPACINGS_MAX; + } + memcpy(halConfig->spacings, config->spacings.data(), + sizeof(uint32_t) * halConfig->num_spacings); + + if (config->type == Band::FM) { + halConfig->fm.deemphasis = static_cast<radio_deemphasis_t>(config->ext.fm.deemphasis); + halConfig->fm.stereo = config->ext.fm.stereo; + halConfig->fm.rds = static_cast<radio_rds_t>(config->ext.fm.rds); + halConfig->fm.ta = config->ext.fm.ta; + halConfig->fm.af = config->ext.fm.af; + halConfig->fm.ea = config->ext.fm.ea; + } else { + halConfig->am.stereo = config->ext.am.stereo; + } +} + + +//static +void Utils::convertProgramInfoFromHal(ProgramInfo *info, radio_program_info_t *halInfo) +{ + auto &info_1_1 = *info; + auto &info_1_0 = info->base; + + info_1_0.channel = halInfo->channel; + info_1_0.subChannel = halInfo->sub_channel; + info_1_0.tuned = halInfo->tuned; + info_1_0.stereo = halInfo->stereo; + info_1_0.digital = halInfo->digital; + info_1_0.signalStrength = halInfo->signal_strength; + convertMetaDataFromHal(info_1_0.metadata, halInfo->metadata); + // TODO(b/34348946): add support for HAL 1.1 fields + info_1_1.flags = 0; +} + +//static +int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata, radio_metadata_t *halMetadata) +{ + if (halMetadata == NULL) { + ALOGE("Invalid argument: halMetadata is NULL"); + return 0; + } + + int count = radio_metadata_get_count(halMetadata); + if (count <= 0) { + return count; + } + MetaData *newMetadata = new MetaData[count]; + int outCount = 0; + for (int i = 0; i < count; i++) { + radio_metadata_key_t key; + radio_metadata_type_t type; + void *value; + size_t size; + if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 || + size == 0) { + continue; + } + switch (type) { + case RADIO_METADATA_TYPE_INT: { + newMetadata[outCount].intValue = *(static_cast<int32_t *>(value)); + } break; + case RADIO_METADATA_TYPE_TEXT: { + newMetadata[outCount].stringValue = static_cast<char *>(value); + } break; + case RADIO_METADATA_TYPE_RAW: { + newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + newMetadata[outCount].rawValue.resize(size); + } break; + case RADIO_METADATA_TYPE_CLOCK: { + radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value); + newMetadata[outCount].clockValue.utcSecondsSinceEpoch = + clock->utc_seconds_since_epoch; + newMetadata[outCount].clockValue.timezoneOffsetInMinutes = + clock->timezone_offset_in_minutes; + } break; + } + newMetadata[outCount].type = static_cast<MetadataType>(type); + newMetadata[outCount].key = static_cast<MetadataKey>(key); + outCount++; + } + metadata.setToExternal(newMetadata, outCount); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + metadata.resize(outCount); + return outCount; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android
diff --git a/broadcastradio/1.1/default/Utils.h b/broadcastradio/1.1/default/Utils.h new file mode 100644 index 0000000..22902ba --- /dev/null +++ b/broadcastradio/1.1/default/Utils.h
@@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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. + */ +#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H +#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H + +#include <android/hardware/broadcastradio/1.1/types.h> +#include <hardware/radio.h> + +namespace android { +namespace hardware { +namespace broadcastradio { +namespace V1_1 { +namespace implementation { + +using V1_0::Class; +using V1_0::BandConfig; +using V1_0::MetaData; +using V1_0::Properties; + +class Utils { +public: + static const char * getClassString(Class ClassId); + static Result convertHalResult(int rc); + static void convertBandConfigFromHal(BandConfig *config, + const radio_hal_band_config_t *halConfig); + static void convertPropertiesFromHal(Properties *properties, + const radio_hal_properties_t *halProperties); + static void convertBandConfigToHal(radio_hal_band_config_t *halConfig, + const BandConfig *config); + static void convertProgramInfoFromHal(ProgramInfo *info, + radio_program_info_t *halInfo); + static int convertMetaDataFromHal(hidl_vec<MetaData>& metadata, + radio_metadata_t *halMetadata); +private: + static const char * sClassModuleNames[]; + +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace broadcastradio +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
diff --git a/broadcastradio/1.1/types.hal b/broadcastradio/1.1/types.hal new file mode 100644 index 0000000..b6f72d2 --- /dev/null +++ b/broadcastradio/1.1/types.hal
@@ -0,0 +1,63 @@ +/** + * Copyright 2017 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.broadcastradio@1.1; + +import @1.0::types; + +typedef @1.0::Result Result; + +enum ProgramListResult : Result { + NOT_READY, + NOT_STARTED, + TEMPORARILY_UNAVAILABLE, +}; + +/** + * Extra flags for program information. + */ +enum ProgramInfoFlags : uint32_t { + /** + * Set when the program is currently playing live stream. + * This may result in a slightly altered reception parameters, + * usually targetted at reduced latency. + */ + LIVE = 1 << 0, + + /** + * Radio stream is not playing, ie. due to bad reception conditions or + * buffering. In this state volume knob MAY be disabled to prevent user + * increasing volume too much. + */ + MUTED = 1 << 1, +}; + +/** + * Radio program information. Returned by the HAL with event RADIO_EVENT_TUNED. + * Contains information on currently tuned channel. + */ +struct ProgramInfo { + @1.0::ProgramInfo base; + bitfield<ProgramInfoFlags> flags; + + /** + * Vendors are allowed to define their own set of flags and store it in this + * field. They MUST verify vendor/product name from Properties struct + * (IBroadcastRadio::getProperties) before doing any interpretation + * of such values. + */ + uint32_t vendorFlags; +};
diff --git a/broadcastradio/1.1/vts/Android.mk b/broadcastradio/1.1/vts/Android.mk new file mode 100644 index 0000000..0c4c55d --- /dev/null +++ b/broadcastradio/1.1/vts/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2017 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp new file mode 100644 index 0000000..a4c0849 --- /dev/null +++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -0,0 +1,37 @@ +// +// Copyright (C) 2017 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. +// + +cc_test { + name: "VtsHalBroadcastradioV1_1TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalBroadcastradioV1_1TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.broadcastradio@1.0", + "android.hardware.broadcastradio@1.1", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +}
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp new file mode 100644 index 0000000..aad01f6 --- /dev/null +++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -0,0 +1,466 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "BroadcastRadioHidlHalTest" +#include <VtsHalHidlTargetTestBase.h> +#include <android-base/logging.h> +#include <cutils/native_handle.h> +#include <cutils/properties.h> +#include <hidl/HidlTransportSupport.h> +#include <utils/threads.h> + +#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h> +#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h> +#include <android/hardware/broadcastradio/1.1/ITuner.h> +#include <android/hardware/broadcastradio/1.1/ITunerCallback.h> +#include <android/hardware/broadcastradio/1.1/types.h> + + +namespace V1_0 = ::android::hardware::broadcastradio::V1_0; + +using ::android::sp; +using ::android::Mutex; +using ::android::Condition; +using ::android::hardware::Return; +using ::android::hardware::Status; +using ::android::hardware::Void; +using ::android::hardware::broadcastradio::V1_0::BandConfig; +using ::android::hardware::broadcastradio::V1_0::Class; +using ::android::hardware::broadcastradio::V1_0::Direction; +using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio; +using ::android::hardware::broadcastradio::V1_0::MetaData; +using ::android::hardware::broadcastradio::V1_0::Properties; +using ::android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory; +using ::android::hardware::broadcastradio::V1_1::ITuner; +using ::android::hardware::broadcastradio::V1_1::ITunerCallback; +using ::android::hardware::broadcastradio::V1_1::ProgramInfo; +using ::android::hardware::broadcastradio::V1_1::Result; + + +// The main test class for Broadcast Radio HIDL HAL. + +class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + virtual void SetUp() override { + auto factory = ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>(); + if (factory != 0) { + factory->connectModule(Class::AM_FM, + [&](Result retval, const ::android::sp<IBroadcastRadio>& result) { + if (retval == Result::OK) { + mRadio = IBroadcastRadio::castFrom(result); + } + }); + } + mTunerCallback = new MyCallback(this); + ASSERT_NE(nullptr, mRadio.get()); + ASSERT_NE(nullptr, mTunerCallback.get()); + } + + virtual void TearDown() override { + mTuner.clear(); + mRadio.clear(); + } + + class MyCallback : public ITunerCallback { + public: + + // ITunerCallback methods (see doc in ITunerCallback.hal) + virtual Return<void> hardwareFailure() { + ALOGI("%s", __FUNCTION__); + mParentTest->onHwFailureCallback(); + return Void(); + } + + virtual Return<void> configChange(Result result, const BandConfig& config __unused) { + ALOGI("%s result %d", __FUNCTION__, result); + mParentTest->onResultCallback(result); + return Void(); + } + + virtual Return<void> tuneComplete(Result result __unused, const V1_0::ProgramInfo& info __unused) { + return Void(); + } + + virtual Return<void> tuneComplete_1_1(Result result, const ProgramInfo& info __unused) { + ALOGI("%s result %d", __FUNCTION__, result); + mParentTest->onResultCallback(result); + return Void(); + } + + virtual Return<void> afSwitch(const V1_0::ProgramInfo& info __unused) { + return Void(); + } + + virtual Return<void> afSwitch_1_1(const ProgramInfo& info __unused) { + return Void(); + } + + virtual Return<void> antennaStateChange(bool connected) { + ALOGI("%s connected %d", __FUNCTION__, connected); + return Void(); + } + + virtual Return<void> trafficAnnouncement(bool active) { + ALOGI("%s active %d", __FUNCTION__, active); + return Void(); + } + + virtual Return<void> emergencyAnnouncement(bool active) { + ALOGI("%s active %d", __FUNCTION__, active); + return Void(); + } + + virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused, + const ::android::hardware::hidl_vec<MetaData>& metadata __unused) { + ALOGI("%s", __FUNCTION__); + return Void(); + } + + MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {} + + private: + // BroadcastRadioHidlTest instance to which callbacks will be notified. + BroadcastRadioHidlTest *mParentTest; + }; + + + /** + * Method called by MyCallback when a callback with no status or boolean value is received + */ + void onCallback() { + Mutex::Autolock _l(mLock); + onCallback_l(); + } + + /** + * Method called by MyCallback when hardwareFailure() callback is received + */ + void onHwFailureCallback() { + Mutex::Autolock _l(mLock); + mHwFailure = true; + onCallback_l(); + } + + /** + * Method called by MyCallback when a callback with status is received + */ + void onResultCallback(Result result) { + Mutex::Autolock _l(mLock); + mResultCallbackData = result; + onCallback_l(); + } + + /** + * Method called by MyCallback when a boolean indication is received + */ + void onBoolCallback(bool result) { + Mutex::Autolock _l(mLock); + mBoolCallbackData = result; + onCallback_l(); + } + + + BroadcastRadioHidlTest() : + mCallbackCalled(false), mBoolCallbackData(false), + mResultCallbackData(Result::OK), mHwFailure(false) {} + + void onCallback_l() { + if (!mCallbackCalled) { + mCallbackCalled = true; + mCallbackCond.broadcast(); + } + } + + + bool waitForCallback(nsecs_t reltime = 0) { + Mutex::Autolock _l(mLock); + nsecs_t endTime = systemTime() + reltime; + while (!mCallbackCalled) { + if (reltime == 0) { + mCallbackCond.wait(mLock); + } else { + nsecs_t now = systemTime(); + if (now > endTime) { + return false; + } + mCallbackCond.waitRelative(mLock, endTime - now); + } + } + return true; + } + + bool getProperties(); + bool openTuner(); + bool checkAntenna(); + + static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10); + static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30); + + sp<IBroadcastRadio> mRadio; + Properties mHalProperties; + sp<ITuner> mTuner; + sp<MyCallback> mTunerCallback; + Mutex mLock; + Condition mCallbackCond; + bool mCallbackCalled; + bool mBoolCallbackData; + Result mResultCallbackData; + bool mHwFailure; +}; + +// A class for test environment setup (kept since this file is a template). +class BroadcastRadioHidlEnvironment : public ::testing::Environment { + public: + virtual void SetUp() {} + virtual void TearDown() {} +}; + +bool BroadcastRadioHidlTest::getProperties() +{ + if (mHalProperties.bands.size() == 0) { + Result halResult = Result::NOT_INITIALIZED; + Return<void> hidlReturn = + mRadio->getProperties([&](Result result, const Properties& properties) { + halResult = result; + if (result == Result::OK) { + mHalProperties = properties; + } + }); + + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(Result::OK, halResult); + EXPECT_EQ(Class::AM_FM, mHalProperties.classId); + EXPECT_GT(mHalProperties.numTuners, 0u); + EXPECT_GT(mHalProperties.bands.size(), 0u); + } + return mHalProperties.bands.size() > 0; +} + +bool BroadcastRadioHidlTest::openTuner() +{ + if (!getProperties()) { + return false; + } + if (mTuner.get() == nullptr) { + Result halResult = Result::NOT_INITIALIZED; + auto hidlReturn = mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback, + [&](Result result, const sp<V1_0::ITuner>& tuner) { + halResult = result; + if (result == Result::OK) { + mTuner = ITuner::castFrom(tuner); + } + }); + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(Result::OK, halResult); + EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); + } + EXPECT_NE(nullptr, mTuner.get()); + return nullptr != mTuner.get(); +} + +bool BroadcastRadioHidlTest::checkAntenna() +{ + BandConfig halConfig; + Result halResult = Result::NOT_INITIALIZED; + Return<void> hidlReturn = + mTuner->getConfiguration([&](Result result, const BandConfig& config) { + halResult = result; + if (result == Result::OK) { + halConfig = config; + } + }); + + return ((halResult == Result::OK) && (halConfig.antennaConnected == true)); +} + + +/** + * Test IBroadcastRadio::getProperties() method + * + * Verifies that: + * - the HAL implements the method + * - the method returns 0 (no error) + * - the implementation class is AM_FM + * - the implementation supports at least one tuner + * - the implementation supports at one band + */ +TEST_F(BroadcastRadioHidlTest, GetProperties) { + EXPECT_TRUE(getProperties()); +} + +/** + * Test IBroadcastRadio::openTuner() method + * + * Verifies that: + * - the HAL implements the method + * - the method returns 0 (no error) and a valid ITuner interface + */ +TEST_F(BroadcastRadioHidlTest, OpenTuner) { + EXPECT_TRUE(openTuner()); +} + +/** + * Test ITuner::setConfiguration() and getConfiguration methods + * + * Verifies that: + * - the HAL implements both methods + * - the methods return 0 (no error) + * - the configuration callback is received within kConfigCallbacktimeoutNs ns + * - the configuration read back from HAl has the same class Id + */ +TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) { + ASSERT_TRUE(openTuner()); + // test setConfiguration + mCallbackCalled = false; + Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); + EXPECT_EQ(Result::OK, mResultCallbackData); + + // test getConfiguration + BandConfig halConfig; + Result halResult; + Return<void> hidlReturn = + mTuner->getConfiguration([&](Result result, const BandConfig& config) { + halResult = result; + if (result == Result::OK) { + halConfig = config; + } + }); + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(Result::OK, halResult); + EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type); +} + +/** + * Test ITuner::scan + * + * Verifies that: + * - the HAL implements the method + * - the method returns 0 (no error) + * - the tuned callback is received within kTuneCallbacktimeoutNs ns + */ +TEST_F(BroadcastRadioHidlTest, Scan) { + ASSERT_TRUE(openTuner()); + ASSERT_TRUE(checkAntenna()); + // test scan UP + mCallbackCalled = false; + Return<Result> hidlResult = mTuner->scan(Direction::UP, true); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); + + // test scan DOWN + mCallbackCalled = false; + hidlResult = mTuner->scan(Direction::DOWN, true); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); +} + +/** + * Test ITuner::step + * + * Verifies that: + * - the HAL implements the method + * - the method returns 0 (no error) + * - the tuned callback is received within kTuneCallbacktimeoutNs ns + */ +TEST_F(BroadcastRadioHidlTest, Step) { + ASSERT_TRUE(openTuner()); + ASSERT_TRUE(checkAntenna()); + // test step UP + mCallbackCalled = false; + Return<Result> hidlResult = mTuner->step(Direction::UP, true); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); + + // test step DOWN + mCallbackCalled = false; + hidlResult = mTuner->step(Direction::DOWN, true); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); +} + +/** + * Test ITuner::tune, getProgramInformation and cancel methods + * + * Verifies that: + * - the HAL implements the methods + * - the methods return 0 (no error) + * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune() + */ +TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) { + ASSERT_TRUE(openTuner()); + ASSERT_TRUE(checkAntenna()); + + // test tune + ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u); + ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit); + + // test scan UP + uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit; + uint32_t upperLimit = mHalProperties.bands[0].upperLimit; + uint32_t spacing = mHalProperties.bands[0].spacings[0]; + + uint32_t channel = + lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing; + mCallbackCalled = false; + mResultCallbackData = Result::NOT_INITIALIZED; + Return<Result> hidlResult = mTuner->tune(channel, 0); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); + EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); + + // test getProgramInformation + ProgramInfo halInfo; + Result halResult = Result::NOT_INITIALIZED; + Return<void> hidlReturn = mTuner->getProgramInformation_1_1( + [&](Result result, const ProgramInfo& info) { + halResult = result; + if (result == Result::OK) { + halInfo = info; + } + }); + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(Result::OK, halResult); + auto &halInfo_1_1 = halInfo.base; + if (mResultCallbackData == Result::OK) { + EXPECT_TRUE(halInfo_1_1.tuned); + EXPECT_LE(halInfo_1_1.channel, upperLimit); + EXPECT_GE(halInfo_1_1.channel, lowerLimit); + } else { + EXPECT_EQ(false, halInfo_1_1.tuned); + } + + // test cancel + mTuner->tune(lowerLimit, 0); + hidlResult = mTuner->cancel(); + EXPECT_TRUE(hidlResult.isOk()); + EXPECT_EQ(Result::OK, hidlResult); +} + + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +}
diff --git a/broadcastradio/Android.bp b/broadcastradio/Android.bp new file mode 100644 index 0000000..5cacbf3 --- /dev/null +++ b/broadcastradio/Android.bp
@@ -0,0 +1,7 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/vts/functional", + "1.1", + "1.1/vts/functional", +]
diff --git a/camera/Android.bp b/camera/Android.bp new file mode 100644 index 0000000..3869766 --- /dev/null +++ b/camera/Android.bp
@@ -0,0 +1,13 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "common/1.0", + "common/1.0/default", + "device/1.0", + "device/1.0/default", + "device/3.2", + "device/3.2/default", + "metadata/3.2", + "provider/2.4", + "provider/2.4/default", + "provider/2.4/vts/functional", +]
diff --git a/camera/README.md b/camera/README.md new file mode 100644 index 0000000..8ce3352 --- /dev/null +++ b/camera/README.md
@@ -0,0 +1,12 @@ +## Camera HALs ## +--- + +## Overview: ## + +The camera.* HAL tree is used by the Android camera service to discover and +operate camera devices available on the device. + +More details and versioning information can be found within each particular HAL. + +More complete information about the Android camera HAL and subsystem can be found at +[source.android.com](http://source.android.com/devices/camera/index.html).
diff --git a/camera/common/1.0/Android.bp b/camera/common/1.0/Android.bp new file mode 100644 index 0000000..aea6e76 --- /dev/null +++ b/camera/common/1.0/Android.bp
@@ -0,0 +1,53 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.camera.common@1.0_hal", + srcs: [ + "types.hal", + ], +} + +genrule { + name: "android.hardware.camera.common@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.common@1.0", + srcs: [ + ":android.hardware.camera.common@1.0_hal", + ], + out: [ + "android/hardware/camera/common/1.0/types.cpp", + ], +} + +genrule { + name: "android.hardware.camera.common@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.common@1.0", + srcs: [ + ":android.hardware.camera.common@1.0_hal", + ], + out: [ + "android/hardware/camera/common/1.0/types.h", + ], +} + +cc_library_shared { + name: "android.hardware.camera.common@1.0", + generated_sources: ["android.hardware.camera.common@1.0_genc++"], + generated_headers: ["android.hardware.camera.common@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.camera.common@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + ], +}
diff --git a/camera/common/1.0/Android.mk b/camera/common/1.0/Android.mk new file mode 100644 index 0000000..9e05172 --- /dev/null +++ b/camera/common/1.0/Android.mk
@@ -0,0 +1,372 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.camera.common@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +# +# Build types.hal (CameraDeviceStatus) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraDeviceStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.CameraDeviceStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataType) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraMetadataType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.CameraMetadataType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraResourceCost) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraResourceCost.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.CameraResourceCost + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TagBoundaryId) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/TagBoundaryId.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.TagBoundaryId + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TorchMode) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/TorchMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.TorchMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TorchModeStatus) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/TorchModeStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.TorchModeStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VendorTag) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/VendorTag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.VendorTag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VendorTagSection) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/VendorTagSection.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.VendorTagSection + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.camera.common@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +# +# Build types.hal (CameraDeviceStatus) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraDeviceStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.CameraDeviceStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataType) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraMetadataType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.CameraMetadataType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraResourceCost) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/CameraResourceCost.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.CameraResourceCost + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TagBoundaryId) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/TagBoundaryId.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.TagBoundaryId + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TorchMode) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/TorchMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.TorchMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TorchModeStatus) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/TorchModeStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.TorchModeStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VendorTag) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/VendorTag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.VendorTag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (VendorTagSection) +# +GEN := $(intermediates)/android/hardware/camera/common/V1_0/VendorTagSection.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.common@1.0::types.VendorTagSection + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp new file mode 100644 index 0000000..6437480 --- /dev/null +++ b/camera/common/1.0/default/Android.bp
@@ -0,0 +1,21 @@ +cc_library_static { + name: "android.hardware.camera.common@1.0-helper", + defaults: ["hidl_defaults"], + srcs: [ + "CameraModule.cpp", + "CameraMetadata.cpp", + "VendorTagDescriptor.cpp", + "HandleImporter.cpp"], + cflags: [ + "-Werror", + "-Wextra", + "-Wall", + ], + shared_libs: [ + "liblog", + "libhardware", + "libcamera_metadata"], + include_dirs: ["system/media/private/camera/include"], + export_include_dirs : ["include"] +} +
diff --git a/camera/common/1.0/default/CameraMetadata.cpp b/camera/common/1.0/default/CameraMetadata.cpp new file mode 100644 index 0000000..44c2040 --- /dev/null +++ b/camera/common/1.0/default/CameraMetadata.cpp
@@ -0,0 +1,568 @@ +/* + * Copyright (C) 2016 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. + */ + +// #define LOG_NDEBUG 0 + +#define LOG_TAG "CamComm1.0-MD" +#include <utils/Log.h> +#include <utils/Errors.h> + +#include "CameraMetadata.h" +#include "VendorTagDescriptor.h" + +namespace android { +namespace hardware { +namespace camera { +namespace common { +namespace V1_0 { +namespace helper { + +#define ALIGN_TO(val, alignment) \ + (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1)) + +CameraMetadata::CameraMetadata() : + mBuffer(NULL), mLocked(false) { +} + +CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) : + mLocked(false) +{ + mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity); +} + +CameraMetadata::CameraMetadata(const CameraMetadata &other) : + mLocked(false) { + mBuffer = clone_camera_metadata(other.mBuffer); +} + +CameraMetadata::CameraMetadata(camera_metadata_t *buffer) : + mBuffer(NULL), mLocked(false) { + acquire(buffer); +} + +CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) { + return operator=(other.mBuffer); +} + +CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) { + if (mLocked) { + ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__); + return *this; + } + + if (CC_LIKELY(buffer != mBuffer)) { + camera_metadata_t *newBuffer = clone_camera_metadata(buffer); + clear(); + mBuffer = newBuffer; + } + return *this; +} + +CameraMetadata::~CameraMetadata() { + mLocked = false; + clear(); +} + +const camera_metadata_t* CameraMetadata::getAndLock() const { + mLocked = true; + return mBuffer; +} + +status_t CameraMetadata::unlock(const camera_metadata_t *buffer) const { + if (!mLocked) { + ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__); + return INVALID_OPERATION; + } + if (buffer != mBuffer) { + ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!", + __FUNCTION__); + return BAD_VALUE; + } + mLocked = false; + return OK; +} + +camera_metadata_t* CameraMetadata::release() { + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return NULL; + } + camera_metadata_t *released = mBuffer; + mBuffer = NULL; + return released; +} + +void CameraMetadata::clear() { + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return; + } + if (mBuffer) { + free_camera_metadata(mBuffer); + mBuffer = NULL; + } +} + +void CameraMetadata::acquire(camera_metadata_t *buffer) { + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return; + } + clear(); + mBuffer = buffer; + + ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != OK, + "%s: Failed to validate metadata structure %p", + __FUNCTION__, buffer); +} + +void CameraMetadata::acquire(CameraMetadata &other) { + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return; + } + acquire(other.release()); +} + +status_t CameraMetadata::append(const CameraMetadata &other) { + return append(other.mBuffer); +} + +status_t CameraMetadata::append(const camera_metadata_t* other) { + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + size_t extraEntries = get_camera_metadata_entry_count(other); + size_t extraData = get_camera_metadata_data_count(other); + resizeIfNeeded(extraEntries, extraData); + + return append_camera_metadata(mBuffer, other); +} + +size_t CameraMetadata::entryCount() const { + return (mBuffer == NULL) ? 0 : + get_camera_metadata_entry_count(mBuffer); +} + +bool CameraMetadata::isEmpty() const { + return entryCount() == 0; +} + +status_t CameraMetadata::sort() { + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + return sort_camera_metadata(mBuffer); +} + +status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) { + int tagType = get_camera_metadata_tag_type(tag); + if ( CC_UNLIKELY(tagType == -1)) { + ALOGE("Update metadata entry: Unknown tag %d", tag); + return INVALID_OPERATION; + } + if ( CC_UNLIKELY(tagType != expectedType) ) { + ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; " + "got type %s data instead ", + get_camera_metadata_tag_name(tag), tag, + camera_metadata_type_names[tagType], + camera_metadata_type_names[expectedType]); + return INVALID_OPERATION; + } + return OK; +} + +status_t CameraMetadata::update(uint32_t tag, + const int32_t *data, size_t data_count) { + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + if ( (res = checkType(tag, TYPE_INT32)) != OK) { + return res; + } + return updateImpl(tag, (const void*)data, data_count); +} + +status_t CameraMetadata::update(uint32_t tag, + const uint8_t *data, size_t data_count) { + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + if ( (res = checkType(tag, TYPE_BYTE)) != OK) { + return res; + } + return updateImpl(tag, (const void*)data, data_count); +} + +status_t CameraMetadata::update(uint32_t tag, + const float *data, size_t data_count) { + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + if ( (res = checkType(tag, TYPE_FLOAT)) != OK) { + return res; + } + return updateImpl(tag, (const void*)data, data_count); +} + +status_t CameraMetadata::update(uint32_t tag, + const int64_t *data, size_t data_count) { + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + if ( (res = checkType(tag, TYPE_INT64)) != OK) { + return res; + } + return updateImpl(tag, (const void*)data, data_count); +} + +status_t CameraMetadata::update(uint32_t tag, + const double *data, size_t data_count) { + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) { + return res; + } + return updateImpl(tag, (const void*)data, data_count); +} + +status_t CameraMetadata::update(uint32_t tag, + const camera_metadata_rational_t *data, size_t data_count) { + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) { + return res; + } + return updateImpl(tag, (const void*)data, data_count); +} + +status_t CameraMetadata::update(uint32_t tag, + const String8 &string) { + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + if ( (res = checkType(tag, TYPE_BYTE)) != OK) { + return res; + } + // string.size() doesn't count the null termination character. + return updateImpl(tag, (const void*)string.string(), string.size() + 1); +} + +status_t CameraMetadata::update(const camera_metadata_ro_entry &entry) { + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + if ( (res = checkType(entry.tag, entry.type)) != OK) { + return res; + } + return updateImpl(entry.tag, (const void*)entry.data.u8, entry.count); +} + +status_t CameraMetadata::updateImpl(uint32_t tag, const void *data, + size_t data_count) { + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + int type = get_camera_metadata_tag_type(tag); + if (type == -1) { + ALOGE("%s: Tag %d not found", __FUNCTION__, tag); + return BAD_VALUE; + } + // Safety check - ensure that data isn't pointing to this metadata, since + // that would get invalidated if a resize is needed + size_t bufferSize = get_camera_metadata_size(mBuffer); + uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer); + uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data); + if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) { + ALOGE("%s: Update attempted with data from the same metadata buffer!", + __FUNCTION__); + return INVALID_OPERATION; + } + + size_t data_size = calculate_camera_metadata_entry_data_size(type, + data_count); + + res = resizeIfNeeded(1, data_size); + + if (res == OK) { + camera_metadata_entry_t entry; + res = find_camera_metadata_entry(mBuffer, tag, &entry); + if (res == NAME_NOT_FOUND) { + res = add_camera_metadata_entry(mBuffer, + tag, data, data_count); + } else if (res == OK) { + res = update_camera_metadata_entry(mBuffer, + entry.index, data, data_count, NULL); + } + } + + if (res != OK) { + ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)", + __FUNCTION__, get_camera_metadata_section_name(tag), + get_camera_metadata_tag_name(tag), tag, strerror(-res), res); + } + + IF_ALOGV() { + ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != + OK, + + "%s: Failed to validate metadata structure after update %p", + __FUNCTION__, mBuffer); + } + + return res; +} + +bool CameraMetadata::exists(uint32_t tag) const { + camera_metadata_ro_entry entry; + return find_camera_metadata_ro_entry(mBuffer, tag, &entry) == 0; +} + +camera_metadata_entry_t CameraMetadata::find(uint32_t tag) { + status_t res; + camera_metadata_entry entry; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + entry.count = 0; + return entry; + } + res = find_camera_metadata_entry(mBuffer, tag, &entry); + if (CC_UNLIKELY( res != OK )) { + entry.count = 0; + entry.data.u8 = NULL; + } + return entry; +} + +camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const { + status_t res; + camera_metadata_ro_entry entry; + res = find_camera_metadata_ro_entry(mBuffer, tag, &entry); + if (CC_UNLIKELY( res != OK )) { + entry.count = 0; + entry.data.u8 = NULL; + } + return entry; +} + +status_t CameraMetadata::erase(uint32_t tag) { + camera_metadata_entry_t entry; + status_t res; + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return INVALID_OPERATION; + } + res = find_camera_metadata_entry(mBuffer, tag, &entry); + if (res == NAME_NOT_FOUND) { + return OK; + } else if (res != OK) { + ALOGE("%s: Error looking for entry %s.%s (%x): %s %d", + __FUNCTION__, + get_camera_metadata_section_name(tag), + get_camera_metadata_tag_name(tag), tag, strerror(-res), res); + return res; + } + res = delete_camera_metadata_entry(mBuffer, entry.index); + if (res != OK) { + ALOGE("%s: Error deleting entry %s.%s (%x): %s %d", + __FUNCTION__, + get_camera_metadata_section_name(tag), + get_camera_metadata_tag_name(tag), tag, strerror(-res), res); + } + return res; +} + +void CameraMetadata::dump(int fd, int verbosity, int indentation) const { + dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation); +} + +status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) { + if (mBuffer == NULL) { + mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2); + if (mBuffer == NULL) { + ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__); + return NO_MEMORY; + } + } else { + size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer); + size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer); + size_t newEntryCount = currentEntryCount + + extraEntries; + newEntryCount = (newEntryCount > currentEntryCap) ? + newEntryCount * 2 : currentEntryCap; + + size_t currentDataCount = get_camera_metadata_data_count(mBuffer); + size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer); + size_t newDataCount = currentDataCount + + extraData; + newDataCount = (newDataCount > currentDataCap) ? + newDataCount * 2 : currentDataCap; + + if (newEntryCount > currentEntryCap || + newDataCount > currentDataCap) { + camera_metadata_t *oldBuffer = mBuffer; + mBuffer = allocate_camera_metadata(newEntryCount, + newDataCount); + if (mBuffer == NULL) { + ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__); + return NO_MEMORY; + } + append_camera_metadata(mBuffer, oldBuffer); + free_camera_metadata(oldBuffer); + } + } + return OK; +} + +void CameraMetadata::swap(CameraMetadata& other) { + if (mLocked) { + ALOGE("%s: CameraMetadata is locked", __FUNCTION__); + return; + } else if (other.mLocked) { + ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__); + return; + } + + camera_metadata* thisBuf = mBuffer; + camera_metadata* otherBuf = other.mBuffer; + + other.mBuffer = thisBuf; + mBuffer = otherBuf; +} + +status_t CameraMetadata::getTagFromName(const char *name, + const VendorTagDescriptor* vTags, uint32_t *tag) { + + if (name == nullptr || tag == nullptr) return BAD_VALUE; + + size_t nameLength = strlen(name); + + const SortedVector<String8> *vendorSections; + size_t vendorSectionCount = 0; + + if (vTags != NULL) { + vendorSections = vTags->getAllSectionNames(); + vendorSectionCount = vendorSections->size(); + } + + // First, find the section by the longest string match + const char *section = NULL; + size_t sectionIndex = 0; + size_t sectionLength = 0; + size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount; + for (size_t i = 0; i < totalSectionCount; ++i) { + + const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] : + (*vendorSections)[i - ANDROID_SECTION_COUNT].string(); + + ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str); + + if (strstr(name, str) == name) { // name begins with the section name + size_t strLength = strlen(str); + + ALOGV("%s: Name begins with section name", __FUNCTION__); + + // section name is the longest we've found so far + if (section == NULL || sectionLength < strLength) { + section = str; + sectionIndex = i; + sectionLength = strLength; + + ALOGV("%s: Found new best section (%s)", __FUNCTION__, section); + } + } + } + + // TODO: Make above get_camera_metadata_section_from_name ? + + if (section == NULL) { + return NAME_NOT_FOUND; + } else { + ALOGV("%s: Found matched section '%s' (%zu)", + __FUNCTION__, section, sectionIndex); + } + + // Get the tag name component of the name + const char *nameTagName = name + sectionLength + 1; // x.y.z -> z + if (sectionLength + 1 >= nameLength) { + return BAD_VALUE; + } + + // Match rest of name against the tag names in that section only + uint32_t candidateTag = 0; + if (sectionIndex < ANDROID_SECTION_COUNT) { + // Match built-in tags (typically android.*) + uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd) + tagBegin = camera_metadata_section_bounds[sectionIndex][0]; + tagEnd = camera_metadata_section_bounds[sectionIndex][1]; + + for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) { + const char *tagName = get_camera_metadata_tag_name(candidateTag); + + if (strcmp(nameTagName, tagName) == 0) { + ALOGV("%s: Found matched tag '%s' (%d)", + __FUNCTION__, tagName, candidateTag); + break; + } + } + + if (candidateTag == tagEnd) { + return NAME_NOT_FOUND; + } + } else if (vTags != NULL) { + // Match vendor tags (typically com.*) + const String8 sectionName(section); + const String8 tagName(nameTagName); + + status_t res = OK; + if ((res = vTags->lookupTag(tagName, sectionName, &candidateTag)) != OK) { + return NAME_NOT_FOUND; + } + } + + *tag = candidateTag; + return OK; +} + + +} // namespace helper +} // namespace V1_0 +} // namespace common +} // namespace camera +} // namespace hardware +} // namespace android
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp new file mode 100644 index 0000000..3a4bc9c --- /dev/null +++ b/camera/common/1.0/default/CameraModule.cpp
@@ -0,0 +1,453 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "CamComm1.0-CamModule" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include <utils/Trace.h> + +#include "CameraModule.h" + +namespace android { +namespace hardware { +namespace camera { +namespace common { +namespace V1_0 { +namespace helper { + +void CameraModule::deriveCameraCharacteristicsKeys( + uint32_t deviceVersion, CameraMetadata &chars) { + ATRACE_CALL(); + + Vector<int32_t> derivedCharKeys; + Vector<int32_t> derivedRequestKeys; + Vector<int32_t> derivedResultKeys; + // Keys added in HAL3.3 + if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) { + Vector<uint8_t> controlModes; + uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE; + chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1); + data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE; + chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1); + controlModes.push(ANDROID_CONTROL_MODE_AUTO); + camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES); + if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) { + controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE); + } + + // Only advertise CONTROL_OFF mode if 3A manual controls are supported. + bool isManualAeSupported = false; + bool isManualAfSupported = false; + bool isManualAwbSupported = false; + entry = chars.find(ANDROID_CONTROL_AE_AVAILABLE_MODES); + if (entry.count > 0) { + for (size_t i = 0; i < entry.count; i++) { + if (entry.data.u8[i] == ANDROID_CONTROL_AE_MODE_OFF) { + isManualAeSupported = true; + break; + } + } + } + entry = chars.find(ANDROID_CONTROL_AF_AVAILABLE_MODES); + if (entry.count > 0) { + for (size_t i = 0; i < entry.count; i++) { + if (entry.data.u8[i] == ANDROID_CONTROL_AF_MODE_OFF) { + isManualAfSupported = true; + break; + } + } + } + entry = chars.find(ANDROID_CONTROL_AWB_AVAILABLE_MODES); + if (entry.count > 0) { + for (size_t i = 0; i < entry.count; i++) { + if (entry.data.u8[i] == ANDROID_CONTROL_AWB_MODE_OFF) { + isManualAwbSupported = true; + break; + } + } + } + if (isManualAeSupported && isManualAfSupported && isManualAwbSupported) { + controlModes.push(ANDROID_CONTROL_MODE_OFF); + } + + chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes); + + entry = chars.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS); + // HAL3.2 devices passing existing CTS test should all support all LSC modes and LSC map + bool lensShadingModeSupported = false; + if (entry.count > 0) { + for (size_t i = 0; i < entry.count; i++) { + if (entry.data.i32[i] == ANDROID_SHADING_MODE) { + lensShadingModeSupported = true; + break; + } + } + } + Vector<uint8_t> lscModes; + Vector<uint8_t> lscMapModes; + lscModes.push(ANDROID_SHADING_MODE_FAST); + lscModes.push(ANDROID_SHADING_MODE_HIGH_QUALITY); + lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF); + if (lensShadingModeSupported) { + lscModes.push(ANDROID_SHADING_MODE_OFF); + lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON); + } + chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes); + chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes); + + derivedCharKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE); + derivedCharKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE); + derivedCharKeys.push(ANDROID_CONTROL_AVAILABLE_MODES); + derivedCharKeys.push(ANDROID_SHADING_AVAILABLE_MODES); + derivedCharKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES); + + // Need update android.control.availableHighSpeedVideoConfigurations since HAL3.3 + // adds batch size to this array. + entry = chars.find(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); + if (entry.count > 0) { + Vector<int32_t> highSpeedConfig; + for (size_t i = 0; i < entry.count; i += 4) { + highSpeedConfig.add(entry.data.i32[i]); // width + highSpeedConfig.add(entry.data.i32[i + 1]); // height + highSpeedConfig.add(entry.data.i32[i + 2]); // fps_min + highSpeedConfig.add(entry.data.i32[i + 3]); // fps_max + highSpeedConfig.add(1); // batchSize_max. default to 1 for HAL3.2 + } + chars.update(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, + highSpeedConfig); + } + } + + // Keys added in HAL3.4 + if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) { + // Check if HAL supports RAW_OPAQUE output + camera_metadata_entry entry = chars.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS); + bool supportRawOpaque = false; + bool supportAnyRaw = false; + const int STREAM_CONFIGURATION_SIZE = 4; + const int STREAM_FORMAT_OFFSET = 0; + const int STREAM_WIDTH_OFFSET = 1; + const int STREAM_HEIGHT_OFFSET = 2; + const int STREAM_IS_INPUT_OFFSET = 3; + Vector<int32_t> rawOpaqueSizes; + + for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) { + int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET]; + int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET]; + int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET]; + int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET]; + if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && + format == HAL_PIXEL_FORMAT_RAW_OPAQUE) { + supportRawOpaque = true; + rawOpaqueSizes.push(width); + rawOpaqueSizes.push(height); + // 2 bytes per pixel. This rough estimation is only used when + // HAL does not fill in the opaque raw size + rawOpaqueSizes.push(width * height *2); + } + if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && + (format == HAL_PIXEL_FORMAT_RAW16 || + format == HAL_PIXEL_FORMAT_RAW10 || + format == HAL_PIXEL_FORMAT_RAW12 || + format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) { + supportAnyRaw = true; + } + } + + if (supportRawOpaque) { + entry = chars.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE); + if (entry.count == 0) { + // Fill in estimated value if HAL does not list it + chars.update(ANDROID_SENSOR_OPAQUE_RAW_SIZE, rawOpaqueSizes); + derivedCharKeys.push(ANDROID_SENSOR_OPAQUE_RAW_SIZE); + } + } + + // Check if HAL supports any RAW output, if so, fill in postRawSensitivityBoost range + if (supportAnyRaw) { + int32_t defaultRange[2] = {100, 100}; + entry = chars.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE); + if (entry.count == 0) { + // Fill in default value (100, 100) + chars.update( + ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, + defaultRange, 2); + derivedCharKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE); + // Actual request/results will be derived by camera device. + derivedRequestKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST); + derivedResultKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST); + } + } + } + + // Always add a default for the pre-correction active array if the vendor chooses to omit this + camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); + if (entry.count == 0) { + Vector<int32_t> preCorrectionArray; + entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); + preCorrectionArray.appendArray(entry.data.i32, entry.count); + chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray); + derivedCharKeys.push(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); + } + + // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS + // This has to be done at this end of this function. + if (derivedCharKeys.size() > 0) { + appendAvailableKeys( + chars, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, derivedCharKeys); + } + if (derivedRequestKeys.size() > 0) { + appendAvailableKeys( + chars, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, derivedRequestKeys); + } + if (derivedResultKeys.size() > 0) { + appendAvailableKeys( + chars, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, derivedResultKeys); + } + return; +} + +void CameraModule::appendAvailableKeys(CameraMetadata &chars, + int32_t keyTag, const Vector<int32_t>& appendKeys) { + camera_metadata_entry entry = chars.find(keyTag); + Vector<int32_t> availableKeys; + availableKeys.setCapacity(entry.count + appendKeys.size()); + for (size_t i = 0; i < entry.count; i++) { + availableKeys.push(entry.data.i32[i]); + } + for (size_t i = 0; i < appendKeys.size(); i++) { + availableKeys.push(appendKeys[i]); + } + chars.update(keyTag, availableKeys); +} + +CameraModule::CameraModule(camera_module_t *module) { + if (module == NULL) { + ALOGE("%s: camera hardware module must not be null", __FUNCTION__); + assert(0); + } + mModule = module; +} + +CameraModule::~CameraModule() +{ + while (mCameraInfoMap.size() > 0) { + camera_info cameraInfo = mCameraInfoMap.editValueAt(0); + if (cameraInfo.static_camera_characteristics != NULL) { + free_camera_metadata( + const_cast<camera_metadata_t*>(cameraInfo.static_camera_characteristics)); + } + mCameraInfoMap.removeItemsAt(0); + } +} + +int CameraModule::init() { + ATRACE_CALL(); + int res = OK; + if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && + mModule->init != NULL) { + ATRACE_BEGIN("camera_module->init"); + res = mModule->init(); + ATRACE_END(); + } + mCameraInfoMap.setCapacity(getNumberOfCameras()); + return res; +} + +int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { + ATRACE_CALL(); + Mutex::Autolock lock(mCameraInfoLock); + if (cameraId < 0) { + ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId); + return -EINVAL; + } + + // Only override static_camera_characteristics for API2 devices + int apiVersion = mModule->common.module_api_version; + if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) { + int ret; + ATRACE_BEGIN("camera_module->get_camera_info"); + ret = mModule->get_camera_info(cameraId, info); + // Fill in this so CameraService won't be confused by + // possibly 0 device_version + info->device_version = CAMERA_DEVICE_API_VERSION_1_0; + ATRACE_END(); + return ret; + } + + ssize_t index = mCameraInfoMap.indexOfKey(cameraId); + if (index == NAME_NOT_FOUND) { + // Get camera info from raw module and cache it + camera_info rawInfo, cameraInfo; + ATRACE_BEGIN("camera_module->get_camera_info"); + int ret = mModule->get_camera_info(cameraId, &rawInfo); + ATRACE_END(); + if (ret != 0) { + return ret; + } + int deviceVersion = rawInfo.device_version; + if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_0) { + // static_camera_characteristics is invalid + *info = rawInfo; + return ret; + } + CameraMetadata m; + m = rawInfo.static_camera_characteristics; + deriveCameraCharacteristicsKeys(rawInfo.device_version, m); + cameraInfo = rawInfo; + cameraInfo.static_camera_characteristics = m.release(); + index = mCameraInfoMap.add(cameraId, cameraInfo); + } + + assert(index != NAME_NOT_FOUND); + // return the cached camera info + *info = mCameraInfoMap[index]; + return OK; +} + +int CameraModule::getDeviceVersion(int cameraId) { + ssize_t index = mDeviceVersionMap.indexOfKey(cameraId); + if (index == NAME_NOT_FOUND) { + int deviceVersion; + if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) { + struct camera_info info; + getCameraInfo(cameraId, &info); + deviceVersion = info.device_version; + } else { + deviceVersion = CAMERA_DEVICE_API_VERSION_1_0; + } + index = mDeviceVersionMap.add(cameraId, deviceVersion); + } + assert(index != NAME_NOT_FOUND); + return mDeviceVersionMap[index]; +} + +int CameraModule::open(const char* id, struct hw_device_t** device) { + int res; + ATRACE_BEGIN("camera_module->open"); + res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device)); + ATRACE_END(); + return res; +} + +bool CameraModule::isOpenLegacyDefined() const { + if (getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_3) { + return false; + } + return mModule->open_legacy != NULL; +} + +int CameraModule::openLegacy( + const char* id, uint32_t halVersion, struct hw_device_t** device) { + int res; + ATRACE_BEGIN("camera_module->open_legacy"); + res = mModule->open_legacy(&mModule->common, id, halVersion, device); + ATRACE_END(); + return res; +} + +int CameraModule::getNumberOfCameras() { + int numCameras; + ATRACE_BEGIN("camera_module->get_number_of_cameras"); + numCameras = mModule->get_number_of_cameras(); + ATRACE_END(); + return numCameras; +} + +int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) { + int res = OK; + ATRACE_BEGIN("camera_module->set_callbacks"); + if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) { + res = mModule->set_callbacks(callbacks); + } + ATRACE_END(); + return res; +} + +bool CameraModule::isVendorTagDefined() const { + return mModule->get_vendor_tag_ops != NULL; +} + +void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) { + if (mModule->get_vendor_tag_ops) { + ATRACE_BEGIN("camera_module->get_vendor_tag_ops"); + mModule->get_vendor_tag_ops(ops); + ATRACE_END(); + } +} + +bool CameraModule::isSetTorchModeSupported() const { + if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) { + if (mModule->set_torch_mode == NULL) { + ALOGE("%s: Module 2.4 device must support set torch API!", + __FUNCTION__); + return false; + } + return true; + } + return false; +} + +int CameraModule::setTorchMode(const char* camera_id, bool enable) { + int res = INVALID_OPERATION; + if (mModule->set_torch_mode != NULL) { + ATRACE_BEGIN("camera_module->set_torch_mode"); + res = mModule->set_torch_mode(camera_id, enable); + ATRACE_END(); + } + return res; +} + +status_t CameraModule::filterOpenErrorCode(status_t err) { + switch(err) { + case NO_ERROR: + case -EBUSY: + case -EINVAL: + case -EUSERS: + return err; + default: + break; + } + return -ENODEV; +} + +uint16_t CameraModule::getModuleApiVersion() const { + return mModule->common.module_api_version; +} + +const char* CameraModule::getModuleName() const { + return mModule->common.name; +} + +uint16_t CameraModule::getHalApiVersion() const { + return mModule->common.hal_api_version; +} + +const char* CameraModule::getModuleAuthor() const { + return mModule->common.author; +} + +void* CameraModule::getDso() { + return mModule->common.dso; +} + +} // namespace helper +} // namespace V1_0 +} // namespace common +} // namespace camera +} // namespace hardware +} // namespace android
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp new file mode 100644 index 0000000..dee2973 --- /dev/null +++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -0,0 +1,190 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "HandleImporter" +#include <utils/Log.h> +#include "HandleImporter.h" + +namespace android { +namespace hardware { +namespace camera { +namespace common { +namespace V1_0 { +namespace helper { + +HandleImporter HandleImporter::sHandleImporter; + +HandleImporter& HandleImporter::getInstance() { + sHandleImporter.initialize(); + return sHandleImporter; +} + +bool HandleImporter::initialize() { + // allow only one client + if (mInitialized) { + return false; + } + + if (!openGralloc()) { + return false; + } + + mInitialized = true; + return true; +} + +void HandleImporter::cleanup() { + if (!mInitialized) { + return; + } + + closeGralloc(); + mInitialized = false; +} + +// In IComposer, any buffer_handle_t is owned by the caller and we need to +// make a clone for hwcomposer2. We also need to translate empty handle +// to nullptr. This function does that, in-place. +bool HandleImporter::importBuffer(buffer_handle_t& handle) { + if (!handle->numFds && !handle->numInts) { + handle = nullptr; + return true; + } + + buffer_handle_t clone = cloneBuffer(handle); + if (!clone) { + return false; + } + + handle = clone; + return true; +} + +void HandleImporter::freeBuffer(buffer_handle_t handle) { + if (!handle) { + return; + } + + releaseBuffer(handle); +} + +bool HandleImporter::importFence(const native_handle_t* handle, int& fd) { + if (handle == nullptr || handle->numFds == 0) { + fd = -1; + } else if (handle->numFds == 1) { + fd = dup(handle->data[0]); + if (fd < 0) { + ALOGE("failed to dup fence fd %d", handle->data[0]); + return false; + } + } else { + ALOGE("invalid fence handle with %d file descriptors", + handle->numFds); + return false; + } + + return true; +} + +void HandleImporter::closeFence(int fd) { + if (fd >= 0) { + close(fd); + } +} + +bool HandleImporter::openGralloc() { + const hw_module_t* module; + int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); + if (err) { + ALOGE("failed to get gralloc module"); + return false; + } + + uint8_t major = (module->module_api_version >> 8) & 0xff; + if (major > 1) { + ALOGE("unknown gralloc module major version %d", major); + return false; + } + + if (major == 1) { + err = gralloc1_open(module, &mDevice); + if (err) { + ALOGE("failed to open gralloc1 device"); + return false; + } + + mRetain = reinterpret_cast<GRALLOC1_PFN_RETAIN>( + mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RETAIN)); + mRelease = reinterpret_cast<GRALLOC1_PFN_RELEASE>( + mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RELEASE)); + if (!mRetain || !mRelease) { + ALOGE("invalid gralloc1 device"); + gralloc1_close(mDevice); + return false; + } + } else { + mModule = reinterpret_cast<const gralloc_module_t*>(module); + } + + return true; +} + +void HandleImporter::closeGralloc() { + if (mDevice) { + gralloc1_close(mDevice); + } +} + +buffer_handle_t HandleImporter::cloneBuffer(buffer_handle_t handle) { + native_handle_t* clone = native_handle_clone(handle); + if (!clone) { + ALOGE("failed to clone buffer %p", handle); + return nullptr; + } + + bool err; + if (mDevice) { + err = (mRetain(mDevice, clone) != GRALLOC1_ERROR_NONE); + } else { + err = (mModule->registerBuffer(mModule, clone) != 0); + } + + if (err) { + ALOGE("failed to retain/register buffer %p", clone); + native_handle_close(clone); + native_handle_delete(clone); + return nullptr; + } + + return clone; +} + +void HandleImporter::releaseBuffer(buffer_handle_t handle) { + if (mDevice) { + mRelease(mDevice, handle); + } else { + mModule->unregisterBuffer(mModule, handle); + } + native_handle_close(handle); + native_handle_delete(const_cast<native_handle_t*>(handle)); +} + +} // namespace helper +} // namespace V1_0 +} // namespace common +} // namespace camera +} // namespace hardware +} // namespace android
diff --git a/camera/common/1.0/default/VendorTagDescriptor.cpp b/camera/common/1.0/default/VendorTagDescriptor.cpp new file mode 100644 index 0000000..db884a8 --- /dev/null +++ b/camera/common/1.0/default/VendorTagDescriptor.cpp
@@ -0,0 +1,367 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "CamComm1.0-VTDesc" + +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/Mutex.h> +#include <utils/Vector.h> +#include <utils/SortedVector.h> +#include <system/camera_metadata.h> +#include <camera_metadata_hidden.h> + +#include "VendorTagDescriptor.h" + +#include <stdio.h> +#include <string.h> + +namespace android { +namespace hardware { +namespace camera2 { +namespace params { + +VendorTagDescriptor::~VendorTagDescriptor() { + size_t len = mReverseMapping.size(); + for (size_t i = 0; i < len; ++i) { + delete mReverseMapping[i]; + } +} + +VendorTagDescriptor::VendorTagDescriptor() : + mTagCount(0), + mVendorOps() { +} + +VendorTagDescriptor::VendorTagDescriptor(const VendorTagDescriptor& src) { + copyFrom(src); +} + +VendorTagDescriptor& VendorTagDescriptor::operator=(const VendorTagDescriptor& rhs) { + copyFrom(rhs); + return *this; +} + +void VendorTagDescriptor::copyFrom(const VendorTagDescriptor& src) { + if (this == &src) return; + + size_t len = mReverseMapping.size(); + for (size_t i = 0; i < len; ++i) { + delete mReverseMapping[i]; + } + mReverseMapping.clear(); + + len = src.mReverseMapping.size(); + // Have to copy KeyedVectors inside mReverseMapping + for (size_t i = 0; i < len; ++i) { + KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>(); + *nameMapper = *(src.mReverseMapping.valueAt(i)); + mReverseMapping.add(src.mReverseMapping.keyAt(i), nameMapper); + } + // Everything else is simple + mTagToNameMap = src.mTagToNameMap; + mTagToSectionMap = src.mTagToSectionMap; + mTagToTypeMap = src.mTagToTypeMap; + mSections = src.mSections; + mTagCount = src.mTagCount; + mVendorOps = src.mVendorOps; +} + +int VendorTagDescriptor::getTagCount() const { + size_t size = mTagToNameMap.size(); + if (size == 0) { + return VENDOR_TAG_COUNT_ERR; + } + return size; +} + +void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const { + size_t size = mTagToNameMap.size(); + for (size_t i = 0; i < size; ++i) { + tagArray[i] = mTagToNameMap.keyAt(i); + } +} + +const char* VendorTagDescriptor::getSectionName(uint32_t tag) const { + ssize_t index = mTagToSectionMap.indexOfKey(tag); + if (index < 0) { + return VENDOR_SECTION_NAME_ERR; + } + return mSections[mTagToSectionMap.valueAt(index)].string(); +} + +ssize_t VendorTagDescriptor::getSectionIndex(uint32_t tag) const { + return mTagToSectionMap.valueFor(tag); +} + +const char* VendorTagDescriptor::getTagName(uint32_t tag) const { + ssize_t index = mTagToNameMap.indexOfKey(tag); + if (index < 0) { + return VENDOR_TAG_NAME_ERR; + } + return mTagToNameMap.valueAt(index).string(); +} + +int VendorTagDescriptor::getTagType(uint32_t tag) const { + ssize_t index = mTagToNameMap.indexOfKey(tag); + if (index < 0) { + return VENDOR_TAG_TYPE_ERR; + } + return mTagToTypeMap.valueFor(tag); +} + +const SortedVector<String8>* VendorTagDescriptor::getAllSectionNames() const { + return &mSections; +} + +status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const { + ssize_t index = mReverseMapping.indexOfKey(section); + if (index < 0) { + ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string()); + return BAD_VALUE; + } + + ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name); + if (nameIndex < 0) { + ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string()); + return BAD_VALUE; + } + + if (tag != NULL) { + *tag = mReverseMapping[index]->valueAt(nameIndex); + } + return OK; +} + +void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const { + + size_t size = mTagToNameMap.size(); + if (size == 0) { + dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n", + indentation, ""); + return; + } + + dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n", + indentation, "", size); + for (size_t i = 0; i < size; ++i) { + uint32_t tag = mTagToNameMap.keyAt(i); + + if (verbosity < 1) { + dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag); + continue; + } + String8 name = mTagToNameMap.valueAt(i); + uint32_t sectionId = mTagToSectionMap.valueFor(tag); + String8 sectionName = mSections[sectionId]; + int type = mTagToTypeMap.valueFor(tag); + const char* typeName = (type >= 0 && type < NUM_TYPES) ? + camera_metadata_type_names[type] : "UNKNOWN"; + dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2, + "", tag, name.string(), type, typeName, sectionName.string()); + } + +} + +} // namespace params +} // namespace camera2 + +namespace camera { +namespace common { +namespace V1_0 { +namespace helper { + +extern "C" { + +static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v); +static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray); +static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag); +static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag); +static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag); + +} /* extern "C" */ + +static Mutex sLock; +static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor; + +status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps, + /*out*/ + sp<VendorTagDescriptor>& descriptor) { + if (vOps == NULL) { + ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__); + return BAD_VALUE; + } + + int tagCount = vOps->get_tag_count(vOps); + if (tagCount < 0 || tagCount > INT32_MAX) { + ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount); + return BAD_VALUE; + } + + Vector<uint32_t> tagArray; + LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount, + "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount); + + vOps->get_all_tags(vOps, /*out*/tagArray.editArray()); + + sp<VendorTagDescriptor> desc = new VendorTagDescriptor(); + desc->mTagCount = tagCount; + + SortedVector<String8> sections; + KeyedVector<uint32_t, String8> tagToSectionMap; + + for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) { + uint32_t tag = tagArray[i]; + if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) { + ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag); + return BAD_VALUE; + } + const char *tagName = vOps->get_tag_name(vOps, tag); + if (tagName == NULL) { + ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag); + return BAD_VALUE; + } + desc->mTagToNameMap.add(tag, String8(tagName)); + const char *sectionName = vOps->get_section_name(vOps, tag); + if (sectionName == NULL) { + ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag); + return BAD_VALUE; + } + + String8 sectionString(sectionName); + + sections.add(sectionString); + tagToSectionMap.add(tag, sectionString); + + int tagType = vOps->get_tag_type(vOps, tag); + if (tagType < 0 || tagType >= NUM_TYPES) { + ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType); + return BAD_VALUE; + } + desc->mTagToTypeMap.add(tag, tagType); + } + + desc->mSections = sections; + + for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) { + uint32_t tag = tagArray[i]; + String8 sectionString = tagToSectionMap.valueFor(tag); + + // Set up tag to section index map + ssize_t index = sections.indexOf(sectionString); + LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index); + desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index)); + + // Set up reverse mapping + ssize_t reverseIndex = -1; + if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) { + KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>(); + reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper); + } + desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag); + } + + descriptor = desc; + return OK; +} + +status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc) { + status_t res = OK; + Mutex::Autolock al(sLock); + sGlobalVendorTagDescriptor = desc; + + vendor_tag_ops_t* opsPtr = NULL; + if (desc != NULL) { + opsPtr = &(desc->mVendorOps); + opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count; + opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags; + opsPtr->get_section_name = vendor_tag_descriptor_get_section_name; + opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name; + opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type; + } + if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) { + ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)." + , __FUNCTION__, strerror(-res), res); + } + return res; +} + +void VendorTagDescriptor::clearGlobalVendorTagDescriptor() { + Mutex::Autolock al(sLock); + set_camera_metadata_vendor_ops(NULL); + sGlobalVendorTagDescriptor.clear(); +} + +sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() { + Mutex::Autolock al(sLock); + return sGlobalVendorTagDescriptor; +} + +extern "C" { + +int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* /*v*/) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_TAG_COUNT_ERR; + } + return sGlobalVendorTagDescriptor->getTagCount(); +} + +void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* /*v*/, uint32_t* tagArray) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return; + } + sGlobalVendorTagDescriptor->getTagArray(tagArray); +} + +const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_SECTION_NAME_ERR; + } + return sGlobalVendorTagDescriptor->getSectionName(tag); +} + +const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_TAG_NAME_ERR; + } + return sGlobalVendorTagDescriptor->getTagName(tag); +} + +int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* /*v*/, uint32_t tag) { + Mutex::Autolock al(sLock); + if (sGlobalVendorTagDescriptor == NULL) { + ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__); + return VENDOR_TAG_TYPE_ERR; + } + return sGlobalVendorTagDescriptor->getTagType(tag); +} + +} /* extern "C" */ + +} // namespace helper +} // namespace V1_0 +} // namespace common +} // namespace camera +} // namespace hardware +} // namespace android
diff --git a/camera/common/1.0/default/include/CameraMetadata.h b/camera/common/1.0/default/include/CameraMetadata.h new file mode 100644 index 0000000..d5e4d56 --- /dev/null +++ b/camera/common/1.0/default/include/CameraMetadata.h
@@ -0,0 +1,230 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef CAMERA_COMMON_1_0_CAMERAMETADATA_H +#define CAMERA_COMMON_1_0_CAMERAMETADATA_H + +#include "system/camera_metadata.h" + +#include <utils/String8.h> +#include <utils/Vector.h> + +namespace android { +namespace hardware { +namespace camera { +namespace common { +namespace V1_0 { +namespace helper { + +class VendorTagDescriptor; + +/** + * A convenience wrapper around the C-based camera_metadata_t library. + */ +class CameraMetadata { + public: + /** Creates an empty object; best used when expecting to acquire contents + * from elsewhere */ + CameraMetadata(); + /** Creates an object with space for entryCapacity entries, with + * dataCapacity extra storage */ + CameraMetadata(size_t entryCapacity, size_t dataCapacity = 10); + + ~CameraMetadata(); + + /** Takes ownership of passed-in buffer */ + CameraMetadata(camera_metadata_t *buffer); + /** Clones the metadata */ + CameraMetadata(const CameraMetadata &other); + + /** + * Assignment clones metadata buffer. + */ + CameraMetadata &operator=(const CameraMetadata &other); + CameraMetadata &operator=(const camera_metadata_t *buffer); + + /** + * Get reference to the underlying metadata buffer. Ownership remains with + * the CameraMetadata object, but non-const CameraMetadata methods will not + * work until unlock() is called. Note that the lock has nothing to do with + * thread-safety, it simply prevents the camera_metadata_t pointer returned + * here from being accidentally invalidated by CameraMetadata operations. + */ + const camera_metadata_t* getAndLock() const; + + /** + * Unlock the CameraMetadata for use again. After this unlock, the pointer + * given from getAndLock() may no longer be used. The pointer passed out + * from getAndLock must be provided to guarantee that the right object is + * being unlocked. + */ + status_t unlock(const camera_metadata_t *buffer) const; + + /** + * Release a raw metadata buffer to the caller. After this call, + * CameraMetadata no longer references the buffer, and the caller takes + * responsibility for freeing the raw metadata buffer (using + * free_camera_metadata()), or for handing it to another CameraMetadata + * instance. + */ + camera_metadata_t* release(); + + /** + * Clear the metadata buffer and free all storage used by it + */ + void clear(); + + /** + * Acquire a raw metadata buffer from the caller. After this call, + * the caller no longer owns the raw buffer, and must not free or manipulate it. + * If CameraMetadata already contains metadata, it is freed. + */ + void acquire(camera_metadata_t* buffer); + + /** + * Acquires raw buffer from other CameraMetadata object. After the call, the argument + * object no longer has any metadata. + */ + void acquire(CameraMetadata &other); + + /** + * Append metadata from another CameraMetadata object. + */ + status_t append(const CameraMetadata &other); + + /** + * Append metadata from a raw camera_metadata buffer + */ + status_t append(const camera_metadata* other); + + /** + * Number of metadata entries. + */ + size_t entryCount() const; + + /** + * Is the buffer empty (no entires) + */ + bool isEmpty() const; + + /** + * Sort metadata buffer for faster find + */ + status_t sort(); + + /** + * Update metadata entry. Will create entry if it doesn't exist already, and + * will reallocate the buffer if insufficient space exists. Overloaded for + * the various types of valid data. + */ + status_t update(uint32_t tag, + const uint8_t *data, size_t data_count); + status_t update(uint32_t tag, + const int32_t *data, size_t data_count); + status_t update(uint32_t tag, + const float *data, size_t data_count); + status_t update(uint32_t tag, + const int64_t *data, size_t data_count); + status_t update(uint32_t tag, + const double *data, size_t data_count); + status_t update(uint32_t tag, + const camera_metadata_rational_t *data, size_t data_count); + status_t update(uint32_t tag, + const String8 &string); + status_t update(const camera_metadata_ro_entry &entry); + + + template<typename T> + status_t update(uint32_t tag, Vector<T> data) { + return update(tag, data.array(), data.size()); + } + + /** + * Check if a metadata entry exists for a given tag id + * + */ + bool exists(uint32_t tag) const; + + /** + * Get metadata entry by tag id + */ + camera_metadata_entry find(uint32_t tag); + + /** + * Get metadata entry by tag id, with no editing + */ + camera_metadata_ro_entry find(uint32_t tag) const; + + /** + * Delete metadata entry by tag + */ + status_t erase(uint32_t tag); + + /** + * Swap the underlying camera metadata between this and the other + * metadata object. + */ + void swap(CameraMetadata &other); + + /** + * Dump contents into FD for debugging. The verbosity levels are + * 0: Tag entry information only, no data values + * 1: Level 0 plus at most 16 data values per entry + * 2: All information + * + * The indentation parameter sets the number of spaces to add to the start + * each line of output. + */ + void dump(int fd, int verbosity = 1, int indentation = 0) const; + + /** + * Find tag id for a given tag name, also checking vendor tags if available. + * On success, returns OK and writes the tag id into tag. + * + * This is a slow method. + */ + static status_t getTagFromName(const char *name, + const VendorTagDescriptor* vTags, uint32_t *tag); + + private: + camera_metadata_t *mBuffer; + mutable bool mLocked; + + /** + * Check if tag has a given type + */ + status_t checkType(uint32_t tag, uint8_t expectedType); + + /** + * Base update entry method + */ + status_t updateImpl(uint32_t tag, const void *data, size_t data_count); + + /** + * Resize metadata buffer if needed by reallocating it and copying it over. + */ + status_t resizeIfNeeded(size_t extraEntries, size_t extraData); + +}; + +} // namespace helper +} // namespace V1_0 +} // namespace common +} // namespace camera +} // namespace hardware +} // namespace android + +#endif
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h new file mode 100644 index 0000000..9fbfbd5 --- /dev/null +++ b/camera/common/1.0/default/include/CameraModule.h
@@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef CAMERA_COMMON_1_0_CAMERAMODULE_H +#define CAMERA_COMMON_1_0_CAMERAMODULE_H + +#include <hardware/camera.h> +#include <utils/Mutex.h> +#include <utils/KeyedVector.h> +#include <utils/RefBase.h> + +#include "CameraMetadata.h" + +namespace android { +namespace hardware { +namespace camera { +namespace common { +namespace V1_0 { +namespace helper { +/** + * A wrapper class for HAL camera module. + * + * This class wraps camera_module_t returned from HAL to provide a wrapped + * get_camera_info implementation which CameraService generates some + * camera characteristics keys defined in newer HAL version on an older HAL. + */ +class CameraModule : public RefBase { +public: + explicit CameraModule(camera_module_t *module); + virtual ~CameraModule(); + + // Must be called after construction + // Returns OK on success, NO_INIT on failure + int init(); + + int getCameraInfo(int cameraId, struct camera_info *info); + int getDeviceVersion(int cameraId); + int getNumberOfCameras(void); + int open(const char* id, struct hw_device_t** device); + bool isOpenLegacyDefined() const; + int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device); + int setCallbacks(const camera_module_callbacks_t *callbacks); + bool isVendorTagDefined() const; + void getVendorTagOps(vendor_tag_ops_t* ops); + bool isSetTorchModeSupported() const; + int setTorchMode(const char* camera_id, bool enable); + uint16_t getModuleApiVersion() const; + const char* getModuleName() const; + uint16_t getHalApiVersion() const; + const char* getModuleAuthor() const; + // Only used by CameraModuleFixture native test. Do NOT use elsewhere. + void *getDso(); + +private: + // Derive camera characteristics keys defined after HAL device version + static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata &chars); + // Helper function to append available[request|result|chars]Keys + static void appendAvailableKeys(CameraMetadata &chars, + int32_t keyTag, const Vector<int32_t>& appendKeys); + status_t filterOpenErrorCode(status_t err); + camera_module_t *mModule; + KeyedVector<int, camera_info> mCameraInfoMap; + KeyedVector<int, int> mDeviceVersionMap; + Mutex mCameraInfoLock; +}; + +} // namespace helper +} // namespace V1_0 +} // namespace common +} // namespace camera +} // namespace hardware +} // namespace android + +#endif
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h new file mode 100644 index 0000000..def8982 --- /dev/null +++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H +#define CAMERA_COMMON_1_0_HANDLEIMPORTED_H + +#include <hardware/gralloc.h> +#include <hardware/gralloc1.h> +#include <system/window.h> + +namespace android { +namespace hardware { +namespace camera { +namespace common { +namespace V1_0 { +namespace helper { + +// Borrowed from graphics HAL. Use this until gralloc mapper HAL is working +class HandleImporter { +public: + static HandleImporter& getInstance(); + + // In IComposer, any buffer_handle_t is owned by the caller and we need to + // make a clone for hwcomposer2. We also need to translate empty handle + // to nullptr. This function does that, in-place. + bool importBuffer(buffer_handle_t& handle); + void freeBuffer(buffer_handle_t handle); + bool importFence(const native_handle_t* handle, int& fd); + void closeFence(int fd); + +private: + + HandleImporter() : mInitialized(false) {} + bool initialize(); + void cleanup(); + bool openGralloc(); + void closeGralloc(); + buffer_handle_t cloneBuffer(buffer_handle_t handle); + void releaseBuffer(buffer_handle_t handle); + + static HandleImporter sHandleImporter; + bool mInitialized; + + // gralloc1 + gralloc1_device_t* mDevice; + GRALLOC1_PFN_RETAIN mRetain; + GRALLOC1_PFN_RELEASE mRelease; + + // gralloc0 + const gralloc_module_t* mModule; +}; + +} // namespace helper +} // namespace V1_0 +} // namespace common +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // CAMERA_COMMON_1_0_HANDLEIMPORTED_H \ No newline at end of file
diff --git a/camera/common/1.0/default/include/VendorTagDescriptor.h b/camera/common/1.0/default/include/VendorTagDescriptor.h new file mode 100644 index 0000000..8d8ded9 --- /dev/null +++ b/camera/common/1.0/default/include/VendorTagDescriptor.h
@@ -0,0 +1,165 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H +#define CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H + +#include <utils/Vector.h> +#include <utils/KeyedVector.h> +#include <utils/String8.h> +#include <utils/RefBase.h> +#include <system/camera_vendor_tags.h> + +#include <stdint.h> + +namespace android { +namespace hardware { +namespace camera2 { +namespace params { + +/** + * VendorTagDescriptor objects are containers for the vendor tag + * definitions provided, and are typically used to pass the vendor tag + * information enumerated by the HAL to clients of the camera service. + */ +class VendorTagDescriptor { + public: + virtual ~VendorTagDescriptor(); + + VendorTagDescriptor(); + VendorTagDescriptor(const VendorTagDescriptor& src); + VendorTagDescriptor& operator=(const VendorTagDescriptor& rhs); + + void copyFrom(const VendorTagDescriptor& src); + + /** + * The following 'get*' methods implement the corresponding + * functions defined in + * system/media/camera/include/system/camera_vendor_tags.h + */ + + // Returns the number of vendor tags defined. + int getTagCount() const; + + // Returns an array containing the id's of vendor tags defined. + void getTagArray(uint32_t* tagArray) const; + + // Returns the section name string for a given vendor tag id. + const char* getSectionName(uint32_t tag) const; + + // Returns the index in section vectors returned in getAllSectionNames() + // for a given vendor tag id. -1 if input tag does not exist. + ssize_t getSectionIndex(uint32_t tag) const; + + // Returns the tag name string for a given vendor tag id. + const char* getTagName(uint32_t tag) const; + + // Returns the tag type for a given vendor tag id. + int getTagType(uint32_t tag) const; + + /** + * Convenience method to get a vector containing all vendor tag + * sections, or an empty vector if none are defined. + * The pointer is valid for the lifetime of the VendorTagDescriptor, + * or until copyFrom is invoked. + */ + const SortedVector<String8>* getAllSectionNames() const; + + /** + * Lookup the tag id for a given tag name and section. + * + * Returns OK on success, or a negative error code. + */ + status_t lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const; + + /** + * Dump the currently configured vendor tags to a file descriptor. + */ + void dump(int fd, int verbosity, int indentation) const; + + protected: + KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping; + KeyedVector<uint32_t, String8> mTagToNameMap; + KeyedVector<uint32_t, uint32_t> mTagToSectionMap; // Value is offset in mSections + KeyedVector<uint32_t, int32_t> mTagToTypeMap; + SortedVector<String8> mSections; + // must be int32_t to be compatible with Parcel::writeInt32 + int32_t mTagCount; + + vendor_tag_ops mVendorOps; +}; +} /* namespace params */ +} /* namespace camera2 */ + +namespace camera { +namespace common { +namespace V1_0 { +namespace helper { + +/** + * This version of VendorTagDescriptor must be stored in Android sp<>, and adds support for using it + * as a global tag descriptor. + * + * It's a child class of the basic hardware::camera2::params::VendorTagDescriptor since basic + * Parcelable objects cannot require being kept in an sp<> and still work with auto-generated AIDL + * interface implementations. + */ +class VendorTagDescriptor : + public ::android::hardware::camera2::params::VendorTagDescriptor, + public LightRefBase<VendorTagDescriptor> { + + public: + + /** + * Create a VendorTagDescriptor object from the given vendor_tag_ops_t + * struct. + * + * Returns OK on success, or a negative error code. + */ + static status_t createDescriptorFromOps(const vendor_tag_ops_t* vOps, + /*out*/ + sp<VendorTagDescriptor>& descriptor); + + /** + * Sets the global vendor tag descriptor to use for this process. + * Camera metadata operations that access vendor tags will use the + * vendor tag definitions set this way. + * + * Returns OK on success, or a negative error code. + */ + static status_t setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc); + + /** + * Returns the global vendor tag descriptor used by this process. + * This will contain NULL if no vendor tags are defined. + */ + static sp<VendorTagDescriptor> getGlobalVendorTagDescriptor(); + + /** + * Clears the global vendor tag descriptor used by this process. + */ + static void clearGlobalVendorTagDescriptor(); + +}; + +} // namespace helper +} // namespace V1_0 +} // namespace common +} // namespace camera +} // namespace hardware +} // namespace android + +#endif /* CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H */
diff --git a/camera/common/1.0/types.hal b/camera/common/1.0/types.hal new file mode 100644 index 0000000..0393107 --- /dev/null +++ b/camera/common/1.0/types.hal
@@ -0,0 +1,413 @@ +/* + * Copyright (C) 2016 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.camera.common@1.0; + +/** + * Common enumeration and structure definitions for all HALs under + * android.hardware.camera + */ + +/** + * Status codes for camera HAL method calls. + * + */ +enum Status : uint32_t { + /** + * Method call succeeded + */ + OK = 0, + + /** + * One of the arguments to the method call is invalid. For example, + * the camera ID is unknown. + */ + ILLEGAL_ARGUMENT = 1, + + /** + * The specified camera device is already in use + */ + CAMERA_IN_USE = 2, + + /** + * The HAL cannot support more simultaneous cameras in use. + */ + MAX_CAMERAS_IN_USE = 3, + + /** + * This HAL does not support this method. + */ + METHOD_NOT_SUPPORTED = 4, + + /** + * The specified camera device does not support this operation. + */ + OPERATION_NOT_SUPPORTED = 5, + + /** + * This camera device is no longer connected or otherwise available for use + */ + CAMERA_DISCONNECTED = 6, + + /** + * The HAL has encountered an internal error and cannot complete the + * request. + */ + INTERNAL_ERROR = 7 +}; + +/** + * Possible states that the flash unit on a closed camera device can be set to + * via the ICameraProvider::setTorchMode() method. + */ +enum TorchMode : uint32_t { + OFF = 0, // Turn off the flash + ON = 1 // Turn on the flash to torch mode +}; + +/** + * Camera metadata type - duplicated from VNDK libcamera_metadata for vendor tag + * definitions. + */ +enum CameraMetadataType : uint32_t { + // Unsigned 8-bit integer (uint8_t) + BYTE = 0, + // Signed 32-bit integer (int32_t) + INT32 = 1, + // 32-bit float (float) + FLOAT = 2, + // Signed 64-bit integer (int64_t) + INT64 = 3, + // 64-bit float (double) + DOUBLE = 4, + // A 64-bit fraction (camera_metadata_rational_t) + RATIONAL = 5 +}; + +/** + * A single vendor-unique metadata tag. + * The full name of the tag is <sectionName>.<tagName> + */ +struct VendorTag { + uint32_t tagId; // Tag identifier, must be >= TagBoundaryId::VENDOR + string tagName; // Name of tag, not including section name + CameraMetadataType tagType; +}; + +/** + * A set of related vendor tags. + */ +struct VendorTagSection { + string sectionName; // Section name; must be namespaced within vendor's name + vec<VendorTag> tags; // List of tags in this section +}; + +enum TagBoundaryId : uint32_t { + AOSP = 0x0, // First valid tag id for android-defined tags + VENDOR = 0x80000000u // First valid tag id for vendor extension tags +}; + +/** + * CameraDeviceStatus + * + * The current status of a camera device, as sent by a camera provider HAL + * through the ICameraProviderCallback::cameraDeviceStatusChange() call. + * + * At startup, the camera service must assume all internal camera devices listed + * by ICameraProvider::getCameraIdList() are in the PRESENT state. The provider + * must invoke ICameraProviderCallback::cameraDeviceStatusChange to inform the + * service of any initially NOT_PRESENT internal devices, and of any PRESENT + * external camera devices, as soon as the camera service has called + * ICameraProvider::setCallback(). + * + * Allowed state transitions: + * PRESENT -> NOT_PRESENT + * NOT_PRESENT -> ENUMERATING + * NOT_PRESENT -> PRESENT + * ENUMERATING -> PRESENT + * ENUMERATING -> NOT_PRESENT + */ +enum CameraDeviceStatus : uint32_t { + /** + * The camera device is not currently connected, and trying to reference it + * in provider method calls must return status code ILLEGAL_ARGUMENT. + * + */ + NOT_PRESENT = 0, + + /** + * The camera device is connected, and opening it is possible, as long as + * sufficient resources are available. + * + * By default, the framework must assume all devices returned by + * ICameraProvider::getCameraIdList() are in this state. + */ + PRESENT = 1, + + /** + * The camera device is connected, but it is undergoing enumeration and + * startup, and so opening the device must return CAMERA_IN_USE. + * + * Attempting to call ICameraProvider::getCameraCharacteristics() must + * succeed, however. + */ + ENUMERATING = 2, + +}; + +/** + * TorchModeStatus: + * + * The current status of the torch mode on a given camera device, sent by a + * camera provider HAL via the ICameraProviderCallback::TorchModeStatusChange() + * call. + * + * The torch mode status of a camera device is applicable only when the camera + * device is present. The camera service must not call + * ICameraProvider::setTorchMode() to turn on torch mode of a camera device if + * the camera device is not present. At camera service startup time, the + * framework must assume torch modes are in the AVAILABLE_OFF state if the + * camera device is present and the camera characteristics entry + * android.flash.info.available is reported as true via + * ICameraProvider::getCameraCharacteristics() call. The same is assumed for + * external camera devices when they are initially connected. + * + * The camera service requires the following behaviors from the camera provider + * HAL when a camera device's status changes: + * + * 1. A previously-disconnected camera device becomes connected. After + * ICameraProviderCallback::CameraDeviceStatusChange() is invoked to inform + * the camera service that the camera device is present, the framework must + * assume the camera device's torch mode is in AVAILABLE_OFF state if it + * has a flash unit. The camera provider HAL does not need to invoke + * ICameraProviderCallback::TorchModeStatusChange() unless the flash unit + * is unavailable to use by ICameraProvider::setTorchMode(). + * + * 2. A previously-connected camera becomes disconnected. After + * ICameraProviderCallback::CameraDeviceStatusChange() is invoked to inform + * the camera service that the camera device is not present, the framework + * must not call ICameraProvider::setTorchMode() for the disconnected camera + * device until it is connected again. The camera provider HAL does not + * need to invoke ICameraProviderCallback::TorchModeStatusChange() + * separately to inform that the flash unit has become NOT_AVAILABLE. + * + * 3. openCameraDevice() or openCameraDeviceVersion() is called to open a + * camera device. The camera provider HAL must invoke + * ICameraProviderCallback::TorchModeStatusChange() for all flash units + * that have entered NOT_AVAILABLE state and can not be turned on by + * calling ICameraProvider::setTorchMode() due to this open() call. + * openCameraDevice() must not trigger AVAILABLE_OFF before NOT_AVAILABLE + * for all flash units that have become unavailable. + * + * 4. ICameraDevice.close() is called to close a camera device. The camera + * provider HAL must call ICameraProviderCallback::torchModeStatusChange() + * for all flash units that have now entered the AVAILABLE_OFF state and + * can be turned on by calling ICameraProvider::setTorchMode() again because + * of sufficient new camera resources being freed up by this close() call. + * + * Note that the camera service calling ICameraProvider::setTorchMode() + * successfully must trigger AVAILABLE_OFF or AVAILABLE_ON callback for the + * given camera device. Additionally it must trigger AVAILABLE_OFF callbacks + * for other previously-on torch modes if HAL cannot keep multiple devices' + * flashlights on simultaneously. + */ +enum TorchModeStatus : uint32_t { + /** + * The flash unit is no longer available and the torch mode can not be + * turned on by calling setTorchMode(). If the torch mode was AVAILABLE_ON, + * the flashlight must be turned off by the provider HAL before the provider + * HAL calls torchModeStatusChange(). + */ + NOT_AVAILABLE = 0, + + /** + * A torch mode has become off and is available to be turned on via + * ICameraProvider::setTorchMode(). This may happen in the following + * cases: + * 1. After the resources to turn on the torch mode have become available. + * 2. After ICameraProvider::setTorchMode() is called to turn off the torch + * mode. + * 3. After the camera service turned on the torch mode for some other + * camera device and the provider HAL had to turn off the torch modes + * of other camera device(s) that were previously on, due to lack of + * resources to keep them all on. + */ + AVAILABLE_OFF = 1, + + /** + * A torch mode has become on and is available to be turned off via + * ICameraProvider::setTorchMode(). This can happen only after + * ICameraProvider::setTorchMode() has been called to turn on the torch mode. + */ + AVAILABLE_ON = 2, + +}; + +/** + * CameraResourceCost: + * + * Structure defining the abstract resource cost of opening a camera device, + * and any usage conflicts between multiple camera devices. + * + * Obtainable via ICameraDevice::getResourceCost() + */ +struct CameraResourceCost { + /** + * The total resource "cost" of using this camera, represented as an integer + * value in the range [0, 100] where 100 represents total usage of the + * shared resource that is the limiting bottleneck of the camera subsystem. + * This may be a very rough estimate, and is used as a hint to the camera + * service to determine when to disallow multiple applications from + * simultaneously opening different cameras advertised by the camera + * service. + * + * The camera service must be able to simultaneously open and use any + * combination of camera devices exposed by the HAL where the sum of + * the resource costs of these cameras is <= 100. For determining cost, + * each camera device must be assumed to be configured and operating at + * the maximally resource-consuming framerate and stream size settings + * available in the configuration settings exposed for that device through + * the camera metadata. + * + * The camera service may still attempt to simultaneously open combinations + * of camera devices with a total resource cost > 100. This may succeed or + * fail. If this succeeds, combinations of configurations that are not + * supported due to resource constraints from having multiple open devices + * must fail during the configure calls. If the total resource cost is <= + * 100, open and configure must never fail for any stream configuration + * settings or other device capabilities that would normally succeed for a + * device when it is the only open camera device. + * + * This field may be used to determine whether background applications are + * allowed to use this camera device while other applications are using + * other camera devices. Note: multiple applications must never be allowed + * by the camera service to simultaneously open the same camera device. + * + * Example use cases: + * + * Ex. 1: Camera Device 0 = Back Camera + * Camera Device 1 = Front Camera + * - Using both camera devices causes a large framerate slowdown due to + * limited ISP bandwidth. + * + * Configuration: + * + * Camera Device 0 - resourceCost = 51 + * conflicting_devices = empty + * Camera Device 1 - resourceCost = 51 + * conflicting_devices = empty + * + * Result: + * + * Since the sum of the resource costs is > 100, if a higher-priority + * application has either device open, no lower-priority applications must + * be allowed by the camera service to open either device. If a + * lower-priority application is using a device that a higher-priority + * subsequently attempts to open, the lower-priority application must be + * forced to disconnect the the device. + * + * If the highest-priority application chooses, it may still attempt to + * open both devices (since these devices are not listed as conflicting in + * the conflicting_devices fields), but usage of these devices may fail in + * the open or configure calls. + * + * Ex. 2: Camera Device 0 = Left Back Camera + * Camera Device 1 = Right Back Camera + * Camera Device 2 = Combined stereo camera using both right and left + * back camera sensors used by devices 0, and 1 + * Camera Device 3 = Front Camera + * - Due to do hardware constraints, up to two cameras may be open at + * once. The combined stereo camera may never be used at the same time + * as either of the two back camera devices (device 0, 1), and typically + * requires too much bandwidth to use at the same time as the front + * camera (device 3). + * + * Configuration: + * + * Camera Device 0 - resourceCost = 50 + * conflicting_devices = { 2 } + * Camera Device 1 - resourceCost = 50 + * conflicting_devices = { 2 } + * Camera Device 2 - resourceCost = 100 + * conflicting_devices = { 0, 1 } + * Camera Device 3 - resourceCost = 50 + * conflicting_devices = empty + * + * Result: + * + * Based on the conflicting_devices fields, the camera service guarantees + * that the following sets of open devices must never be allowed: { 1, 2 + * }, { 0, 2 }. + * + * Based on the resourceCost fields, if a high-priority foreground + * application is using camera device 0, a background application would be + * allowed to open camera device 1 or 3 (but would be forced to disconnect + * it again if the foreground application opened another device). + * + * The highest priority application may still attempt to simultaneously + * open devices 0, 2, and 3, but the HAL may fail in open or configure + * calls for this combination. + * + * Ex. 3: Camera Device 0 = Back Camera + * Camera Device 1 = Front Camera + * Camera Device 2 = Low-power Front Camera that uses the same sensor + * as device 1, but only exposes image stream + * resolutions that can be used in low-power mode + * - Using both front cameras (device 1, 2) at the same time is impossible + * due a shared physical sensor. Using the back and "high-power" front + * camera (device 1) may be impossible for some stream configurations due + * to hardware limitations, but the "low-power" front camera option may + * always be used as it has special dedicated hardware. + * + * Configuration: + * + * Camera Device 0 - resourceCost = 100 + * conflicting_devices = empty + * Camera Device 1 - resourceCost = 100 + * conflicting_devices = { 2 } + * Camera Device 2 - resourceCost = 0 + * conflicting_devices = { 1 } + * Result: + * + * Based on the conflicting_devices fields, the camera service guarantees + * that the following sets of open devices must never be allowed: + * { 1, 2 }. + * + * Based on the resourceCost fields, only the highest priority application + * may attempt to open both device 0 and 1 at the same time. If a + * higher-priority application is not using device 1 or 2, a low-priority + * background application may open device 2 (but must be forced to + * disconnect it if a higher-priority application subsequently opens + * device 1 or 2). + */ + uint32_t resourceCost; + + /** + * An array of camera device IDs indicating other devices that cannot be + * simultaneously opened while this camera device is in use. + * + * This field is intended to be used to indicate that this camera device + * is a composite of several other camera devices, or otherwise has + * hardware dependencies that prohibit simultaneous usage. If there are no + * dependencies, an empty list may be returned to indicate this. + * + * The camera service must never simultaneously open any of the devices + * in this list while this camera device is open. + * + */ + vec<string> conflictingDevices; + +};
diff --git a/camera/common/README.md b/camera/common/README.md new file mode 100644 index 0000000..c177ad8 --- /dev/null +++ b/camera/common/README.md
@@ -0,0 +1,21 @@ +## Camera common HAL definitions ## +--- + +## Overview: ## + +The camera.common namesapce is used by the Android camera HALs for common +enumeration and structure definitions. + +This includes standard status codes returned by most camera HAL methods. + +More complete information about the Android camera HAL and subsystem can be found at +[source.android.com](http://source.android.com/devices/camera/index.html). + +## Version history: ## + +## types.hal: ## + +### @1.0: + +Common enum and struct definitions for all camera HAL interfaces. Does not +define any interfaces of its own.
diff --git a/camera/device/1.0/Android.bp b/camera/device/1.0/Android.bp new file mode 100644 index 0000000..b8560c7 --- /dev/null +++ b/camera/device/1.0/Android.bp
@@ -0,0 +1,82 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.camera.device@1.0_hal", + srcs: [ + "types.hal", + "ICameraDevice.hal", + "ICameraDeviceCallback.hal", + "ICameraDevicePreviewCallback.hal", + ], +} + +genrule { + name: "android.hardware.camera.device@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@1.0", + srcs: [ + ":android.hardware.camera.device@1.0_hal", + ], + out: [ + "android/hardware/camera/device/1.0/types.cpp", + "android/hardware/camera/device/1.0/CameraDeviceAll.cpp", + "android/hardware/camera/device/1.0/CameraDeviceCallbackAll.cpp", + "android/hardware/camera/device/1.0/CameraDevicePreviewCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.camera.device@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@1.0", + srcs: [ + ":android.hardware.camera.device@1.0_hal", + ], + out: [ + "android/hardware/camera/device/1.0/types.h", + "android/hardware/camera/device/1.0/ICameraDevice.h", + "android/hardware/camera/device/1.0/IHwCameraDevice.h", + "android/hardware/camera/device/1.0/BnHwCameraDevice.h", + "android/hardware/camera/device/1.0/BpHwCameraDevice.h", + "android/hardware/camera/device/1.0/BsCameraDevice.h", + "android/hardware/camera/device/1.0/ICameraDeviceCallback.h", + "android/hardware/camera/device/1.0/IHwCameraDeviceCallback.h", + "android/hardware/camera/device/1.0/BnHwCameraDeviceCallback.h", + "android/hardware/camera/device/1.0/BpHwCameraDeviceCallback.h", + "android/hardware/camera/device/1.0/BsCameraDeviceCallback.h", + "android/hardware/camera/device/1.0/ICameraDevicePreviewCallback.h", + "android/hardware/camera/device/1.0/IHwCameraDevicePreviewCallback.h", + "android/hardware/camera/device/1.0/BnHwCameraDevicePreviewCallback.h", + "android/hardware/camera/device/1.0/BpHwCameraDevicePreviewCallback.h", + "android/hardware/camera/device/1.0/BsCameraDevicePreviewCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.camera.device@1.0", + generated_sources: ["android.hardware.camera.device@1.0_genc++"], + generated_headers: ["android.hardware.camera.device@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.camera.device@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.camera.common@1.0", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.camera.common@1.0", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], +}
diff --git a/camera/device/1.0/ICameraDevice.hal b/camera/device/1.0/ICameraDevice.hal new file mode 100644 index 0000000..52d6cf0 --- /dev/null +++ b/camera/device/1.0/ICameraDevice.hal
@@ -0,0 +1,405 @@ +/* + * Copyright (C) 2016 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.camera.device@1.0; + +import android.hardware.camera.common@1.0::types; +import ICameraDeviceCallback; +import ICameraDevicePreviewCallback; + +/** + * Camera device HAL, legacy version + * + * DEPRECATED. New devices are strongly recommended to use Camera HAL v3.2 or + * newer. + * + * Supports the android.hardware.Camera API, and the android.hardware.camera2 + * API in LEGACY mode only. + * + * Will be removed in the Android P release. + */ +interface ICameraDevice { + + /** + * Get camera device resource cost information. + * + * This method may be called at any time, including before open() + * + * @return status Status code for the operation, one of: + * OK: + * On success. + * INTERNAL_ERROR: + * An unexpected internal camera HAL error occurred, and the + * resource cost is not available. + * CAMERA_DISCONNECTED: + * An external camera device has been disconnected, and is no longer + * available. This camera device interface is now stale, and a new + * instance must be acquired if the device is reconnected. All + * subsequent calls on this interface must return + * CAMERA_DISCONNECTED. + * @return resourceCost + * The resources required to open this camera device, or unspecified + * values if status is not OK. + */ + getResourceCost() generates (Status status, CameraResourceCost resourceCost); + + /** + * Get basic camera information. + * + * This method may be called at any time, including before open() + * + * @return status Status code for the operation, one of: + * OK: + * On success. + * INTERNAL_ERROR: + * An unexpected internal camera HAL error occurred, and the + * camera information is not available. + * CAMERA_DISCONNECTED: + * An external camera device has been disconnected, and is no longer + * available. This camera device interface is now stale, and a new + * instance must be acquired if the device is reconnected. All + * subsequent calls on this interface must return + * CAMERA_DISCONNECTED. + * @return info Basic information about this camera device, or unspecified + * values if status is not OK. + */ + getCameraInfo() generates (Status status, CameraInfo info); + + /** + * setTorchMode: + * + * Turn on or off the torch mode of the flash unit associated with a given + * camera ID. If the operation is successful, HAL must notify the framework + * torch state by invoking + * ICameraProviderCallback::torchModeStatusChange() with the new state. + * + * The camera device has a higher priority accessing the flash unit. When + * there are any resource conflicts, such as when open() is called to fully + * activate a camera device, the provider must notify the framework through + * ICameraProviderCallback::torchModeStatusChange() that the torch mode has + * been turned off and the torch mode state has become + * TORCH_MODE_STATUS_NOT_AVAILABLE. When resources to turn on torch mode + * become available again, the provider must notify the framework through + * ICameraProviderCallback::torchModeStatusChange() that the torch mode + * state has become TORCH_MODE_STATUS_AVAILABLE_OFF for set_torch_mode() to + * be called. + * + * When the framework calls setTorchMode() to turn on the torch mode of a + * flash unit, if HAL cannot keep multiple torch modes on simultaneously, + * HAL must turn off the torch mode that was turned on by + * a previous setTorchMode() call and notify the framework that the torch + * mode state of that flash unit has become TORCH_MODE_STATUS_AVAILABLE_OFF. + * + * @param torchMode The new mode to set the device flash unit to. + * + * @return status Status code for the operation, one of: + * OK: + * On a successful change to the torch state. + * INTERNAL_ERROR: + * The flash unit cannot be operated due to an unexpected internal + * error. + * ILLEGAL_ARGUMENT: + * The camera ID is unknown. + * CAMERA_IN_USE: + * This camera device has been opened, so the torch cannot be + * controlled until it is closed. + * MAX_CAMERAS_IN_USE: + * Due to other camera devices being open, or due to other + * resource constraints, the torch cannot be controlled currently. + * METHOD_NOT_SUPPORTED: + * This provider does not support direct operation of flashlight + * torch mode. The framework must open the camera device and turn + * the torch on through the device interface. + * OPERATION_NOT_SUPPORTED: + * This camera device does not have a flash unit. This must + * be returned if and only if parameter key flash-mode-values is not present. + * CAMERA_DISCONNECTED: + * An external camera device has been disconnected, and is no longer + * available. This camera device interface is now stale, and a new + * instance must be acquired if the device is reconnected. All + * subsequent calls on this interface must return + * CAMERA_DISCONNECTED. + * + */ + setTorchMode(TorchMode mode) generates (Status status); + + /** + * Dump state of the camera hardware. + * + * This must be callable at any time, whether the device is open or not. + * + * @param fd A native handle with one valid file descriptor. The descriptor + * must be able to be used with dprintf() or equivalent to dump the + * state of this camera device into the camera service dumpsys output. + * + * @return status The status code for this operation. + */ + dumpState(handle fd) generates (Status status); + + /** + * Open the camera device for active use. + * + * All methods besides getResourceCost(), getCameraInfo(), setTorchMode(), + * and dump() must not be called unless open() has been called successfully, + * and close() has not yet been called. + * + * @param callback Interface to invoke by the HAL for device callbacks. + * @return status Status code for the operation, one of: + * OK: + * On a successful open of the camera device. + * INTERNAL_ERROR: + * The camera device cannot be opened due to an internal + * error. + * ILLEGAL_ARGUMENT: + * The callback handle is invalid (for example, it is null). + * CAMERA_IN_USE: + * This camera device is already open. + * MAX_CAMERAS_IN_USE: + * The maximal number of camera devices that can be + * opened concurrently were opened already. + * CAMERA_DISCONNECTED: + * This external camera device has been disconnected, and is no + * longer available. This interface is now stale, and a new instance + * must be acquired if the device is reconnected. All subsequent + * calls on this interface must return CAMERA_DISCONNECTED. + */ + open(ICameraDeviceCallback callback) generates (Status status); + + + /***** + * All methods below this point must only be called between a successful + * open() call and a close() call. + */ + + /** Set the callback interface through which preview frames are sent */ + setPreviewWindow(ICameraDevicePreviewCallback window) + generates (Status status); + + /** + * Enable a message, or set of messages. + * + * @param msgType The bitfield of messages to enable. + */ + enableMsgType(FrameCallbackFlags msgType); + + /** + * Disable a message, or a set of messages. + * + * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera + * HAL must not rely on its client to call releaseRecordingFrame() to + * release video recording frames sent out by the cameral HAL before and + * after the disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera HAL + * clients must not modify/access any video recording frame after calling + * disableMsgType(CAMERA_MSG_VIDEO_FRAME). + * + * @param msgType The bitfield of messages to disable. + */ + disableMsgType(FrameCallbackFlags msgType); + + /** + * Query whether a message, or a set of messages, is enabled. Note that + * this is operates as an AND, if any of the messages queried are off, this + * must return false. + * + * @param msgType The bitfield of messages to query. + * @return enabled Whether all the specified flags are enabled. + */ + msgTypeEnabled(FrameCallbackFlags msgType) generates (bool enabled); + + /** + * Start preview mode. + * + * @return status The status code for this operation. + */ + startPreview() generates (Status status); + + /** + * Stop a previously started preview. + */ + stopPreview(); + + /** + * Returns true if preview is enabled. + * + * @return enabled Whether preview is currently enabled. + */ + previewEnabled() generates (bool enabled); + + /** + * Request the camera HAL to store meta data or real YUV data in the video + * buffers sent out via CAMERA_MSG_VIDEO_FRAME for a recording session. If + * it is not called, the default camera HAL behavior is to store real YUV + * data in the video buffers. + * + * This method must be called before startRecording() in order to be + * effective. + * + * If meta data is stored in the video buffers, it is up to the receiver of + * the video buffers to interpret the contents and to find the actual frame + * data with the help of the meta data in the buffer. How this is done is + * outside of the scope of this method. + * + * Some camera HALs may not support storing meta data in the video buffers, + * but all camera HALs must support storing real YUV data in the video + * buffers. If the camera HAL does not support storing the meta data in the + * video buffers when it is requested to do do, INVALID_OPERATION must be + * returned. It is very useful for the camera HAL to pass meta data rather + * than the actual frame data directly to the video encoder, since the + * amount of the uncompressed frame data can be very large if video size is + * large. + * + * @param enable Set to true to instruct the camera HAL to store meta data + * in the video buffers; false to instruct the camera HAL to store real + * YUV data in the video buffers. + * + * @return status OK on success. + */ + storeMetaDataInBuffers(bool enable) generates (Status status); + + /** + * Start record mode. + * + * When a record image is available, a CAMERA_MSG_VIDEO_FRAME message is + * sent with the corresponding frame. Every record frame must be released by + * a camera HAL client via releaseRecordingFrame() before the client calls + * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls + * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's + * responsibility to manage the life-cycle of the video recording frames, + * and the client must not modify/access any video recording frames. + * + * @return status The status code for the operation. + */ + startRecording() generates (Status status); + + /** + * Stop a previously started recording. + */ + stopRecording(); + + /** + * Returns true if recording is enabled. + * + * @return enabled True if recording is currently active. + */ + recordingEnabled() generates (bool enabled); + + /** + * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME in + * dataCallbackTimestamp. + * + * It is camera HAL client's responsibility to release video recording + * frames sent out by the camera HAL before the camera HAL receives a call + * to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives the call to + * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's + * responsibility to manage the life-cycle of the video recording frames. + * + * @param memId The memory buffer to release a recording frame from. + * @param bufferIndex The specific buffer index to return to the HAL. + */ + releaseRecordingFrame(MemoryId memId, uint32_t bufferIndex); + + /** + * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME in + * handleCallbackTimestamp. + * + * It is camera HAL client's responsibility to release video recording + * frames sent out by the camera HAL before the camera HAL receives a call + * to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives the call to + * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is the camera HAL's + * responsibility to manage the life-cycle of the video recording frames. + * + * @param memId The memory buffer to release a recording frame from. + * @param bufferIndex The specific buffer index to return to the HAL. + * @param frame The handle for a released video frame + */ + releaseRecordingFrameHandle(MemoryId memId, uint32_t bufferIndex, handle frame); + + /** + * Start auto focus. + * + * The notification callback routine is called with + * CAMERA_MSG_FOCUS once when focusing is complete. autoFocus() can be + * called again after that if another auto focus is needed. + * + * @return status The status code for this operation. + */ + autoFocus() generates (Status status); + + /** + * Cancels auto-focus function. + * + * If the auto-focus is still in progress, this function must cancel + * it. Whether the auto-focus is in progress or not, this function must + * return the focus position to the default. If the camera does not support + * auto-focus, this is a no-op. + * + * @return status The status code for this operation. + */ + cancelAutoFocus() generates (Status status); + + /** + * Take a picture. + * + * @return status The status code for this operation. + */ + takePicture() generates (Status status); + + /** + * Cancel a picture that was started with takePicture. Calling this method + * when no picture is being taken is a no-op. + * + * @return status The status code for this operation. + */ + cancelPicture() generates (Status status); + + /** + * Set the camera parameters. + * + * @param params The parameter string, consisting of + * '<key1>=<value1>; ...;<keyN>=<valueN>'. + * @return status The status code for this operation: + * OK: Parameter update was successful + * ILLEGAL_ARGUMENT: At least one parameter was invalid or not supported + * + */ + setParameters(string params) generates (Status status); + + /** + * Retrieve the camera parameters. + */ + getParameters() generates (string parms); + + /** + * Send command to camera driver. + * The meaning of the arguments is defined by the value of cmd, documented + * in the CommandType definition. + * + * @param cmd The command to invoke. + * @param arg1 The first argument for the command, if needed. + * @param arg2 The second argument for the command, if needed. + * + * @return status The status code for this operation. + */ + sendCommand(CommandType cmd, int32_t arg1, int32_t arg2) + generates (Status status); + + /** + * Release the hardware resources owned by this object, shutting down the + * camera device. + */ + close(); + +};
diff --git a/camera/device/1.0/ICameraDeviceCallback.hal b/camera/device/1.0/ICameraDeviceCallback.hal new file mode 100644 index 0000000..1b0db24 --- /dev/null +++ b/camera/device/1.0/ICameraDeviceCallback.hal
@@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 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.camera.device@1.0; + +interface ICameraDeviceCallback { + + /** + * Notify the camera service of a particular event occurring + * The meaning of each parameter is defined by the value of msgType, and + * documented in the definition of NotifyCallbackMsg. + * + * @param msgType The type of the event. + * @param ext1 The first parameter for the event, if needed. + * @param ext2 The second parameter for the event, if needed. + */ + notifyCallback(NotifyCallbackMsg msgType, int32_t ext1, int32_t ext2); + + /** + * Define a memory buffer from the provided handle and size, and return a + * unique identifier for the HAL to use to reference it with. + * + * TODO(b/33269977): Ensure this aligns with design and performance goals. + * + * @param descriptor A native handle that must have exactly one file + * descriptor in it; the file descriptor must be memory mappable to + * bufferSize * bufferCount bytes. + * @param bufferSize The number of bytes a single buffer consists of. + * @param bufferCount The number of contiguous buffers that the descriptor + * contains. + * + * @return memId A positive integer identifier for this memory buffer, for + * use with data callbacks and unregistering memory. 0 must be returned + * in case of error, such as if the descriptor does not contain exactly + * one FD. + */ + registerMemory(handle descriptor, uint32_t bufferSize, uint32_t bufferCount) + generates (MemoryId memId); + + /** + * Unregister a previously registered memory buffer + */ + unregisterMemory(MemoryId memId); + + /** + * Send a buffer of image data to the camera service + * + * @param msgType The kind of image buffer data this call represents. + * @param data A memory handle to the buffer containing the data. + * @param bufferIndex The offset into the memory handle where the buffer + * starts. + * + */ + dataCallback(DataCallbackMsg msgType, MemoryId data, uint32_t bufferIndex, + CameraFrameMetadata metadata); + + /** + * Send a buffer of image data to the camera service, with a timestamp + * + * @param msgType The kind of image buffer data this call represents. + * @param data A memory handle to the buffer containing the data. + * @param bufferIndex The offset into the memory handle where the buffer + * starts. + * @param timestamp The time this buffer was captured by the camera, in + * nanoseconds. + * + */ + dataCallbackTimestamp(DataCallbackMsg msgType, MemoryId data, uint32_t bufferIndex, + int64_t timestamp); + + /** + * Send a buffer of image data to the camera service, with a timestamp + * + * @param msgType The kind of image buffer data this call represents. + * @param handle The handle of image buffer data this call represents. + * @param data A memory handle to the buffer containing the data. + * @param bufferIndex The offset into the memory handle where the buffer + * starts. + * @param timestamp The time this buffer was captured by the camera, in + * nanoseconds. + * + * @return frameId a frame ID to be used with releaseRecordingFrameId later + * + */ + handleCallbackTimestamp(DataCallbackMsg msgType, handle frameData, MemoryId data, + uint32_t bufferIndex, int64_t timestamp); + +};
diff --git a/camera/device/1.0/ICameraDevicePreviewCallback.hal b/camera/device/1.0/ICameraDevicePreviewCallback.hal new file mode 100644 index 0000000..4c9b517 --- /dev/null +++ b/camera/device/1.0/ICameraDevicePreviewCallback.hal
@@ -0,0 +1,121 @@ +/* + * Copyright (C) 2016 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.camera.device@1.0; + +import android.hardware.camera.common@1.0::types; +import android.hardware.graphics.allocator@2.0::types; +import android.hardware.graphics.common@1.0::types; + +/** + * Camera device HAL@1.0 preview stream operation interface. + */ +interface ICameraDevicePreviewCallback { + + /** + * Acquire a buffer to write a preview buffer into. + * + * @return status The status code for this operation. If not OK, then + * buffer and stride must not be used. + * @return bufferId A unique ID for the returned buffer. + * @return buffer A handle to the buffer to write into. Must be non-null if the bufferId has not + * been seen by HAL before. Must be null if the bufferId is seen before. HAL must keep track + * of the bufferId to actual buffer handle mapping. + * @return stride The stride between two rows of pixels in this buffer. + */ + dequeueBuffer() generates (Status status, uint64_t bufferId, handle buffer, uint32_t stride); + + /** + * Send a filled preview buffer to its consumer. + * + * @param bufferId The bufferId of the preview buffer + * @return status The status code for this operation. + */ + enqueueBuffer(uint64_t bufferId) generates (Status status); + + /** + * Return a preview buffer unfilled. This buffer must not be sent on to the + * preview consumer as a valid buffer, but may be reused as if it were + * empty. + * + * @param bufferId The bufferId of the preview buffer + * @return status The status code for this operation. + */ + cancelBuffer(uint64_t bufferId) generates (Status status); + + /** + * Set the number of preview buffers needed by the HAL. + * + * @param count The maximum number of preview buffers to allocate. + * @return status The status code for this operation. + */ + setBufferCount(uint32_t count) generates (Status status); + + /** + * Set the dimensions and format of future preview buffers. + * + * The next buffer that is dequeued must match the requested size and + * format. + * + * @return Status The status code for this operation. + */ + setBuffersGeometry(uint32_t w, uint32_t h, + android.hardware.graphics.common@1.0::PixelFormat format) + generates (Status status); + + /** + * Set the valid region of image data for the next buffer(s) to be enqueued. + * + * @return Status The status code for this operation. + */ + setCrop(int32_t left, int32_t top, int32_t right, int32_t bottom) + generates (Status status); + + /** + * Set the producer usage flags for the next buffer(s) to be enqueued. + * + * @return Status The status code for this operation. + */ + setUsage(ProducerUsage usage) generates (Status status); + + /** + * Set the expected buffering mode for the preview output. + */ + setSwapInterval(int32_t interval) generates (Status status); + + /** + * Get the minimum number of buffers the preview consumer endpoint needs + * to hold for correct operation. + * + * @return Status The status code for this operation. + * @return count The number of buffers the consumer has requested. + */ + getMinUndequeuedBufferCount() generates (Status status, uint32_t count); + + /** + * Set the timestamp for the next buffer to enqueue + * + * Timestamps are measured in nanoseconds, and must be comparable + * and monotonically increasing between two frames in the same + * preview stream. They do not need to be comparable between + * consecutive or parallel preview streams, cameras, or app runs. + * + * @param timestamp The timestamp to set for future buffers. + * @return Status The status code for this operation. + */ + setTimestamp(int64_t timestamp) generates (Status status); + +};
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp new file mode 100644 index 0000000..5688fc1 --- /dev/null +++ b/camera/device/1.0/default/Android.bp
@@ -0,0 +1,29 @@ +cc_library_shared { + name: "camera.device@1.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + srcs: [ + "CameraDevice.cpp", + ], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.camera.device@1.0", + "android.hardware.camera.common@1.0", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + "libcutils", + "liblog", + "libhardware", + "libcamera_metadata", + "libbinder", + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper" + ], + export_include_dirs: ["."] +} +
diff --git a/camera/device/1.0/default/CameraDevice.cpp b/camera/device/1.0/default/CameraDevice.cpp new file mode 100644 index 0000000..819525b --- /dev/null +++ b/camera/device/1.0/default/CameraDevice.cpp
@@ -0,0 +1,948 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "CamDev@1.0-impl" +#include <utils/Log.h> +#include <hardware/camera.h> +#include <hardware/gralloc1.h> +#include <utils/Trace.h> + +#include "CameraDevice_1_0.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::graphics::allocator::V2_0::ProducerUsage; +using ::android::hardware::graphics::common::V1_0::PixelFormat; + +HandleImporter& CameraDevice::sHandleImporter = HandleImporter::getInstance(); + +Status CameraDevice::getHidlStatus(const int& status) { + switch (status) { + case 0: return Status::OK; + case -ENOSYS: return Status::OPERATION_NOT_SUPPORTED; + case -EBUSY : return Status::CAMERA_IN_USE; + case -EUSERS: return Status::MAX_CAMERAS_IN_USE; + case -ENODEV: return Status::INTERNAL_ERROR; + case -EINVAL: return Status::ILLEGAL_ARGUMENT; + default: + ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status); + return Status::INTERNAL_ERROR; + } +} + +status_t CameraDevice::getStatusT(const Status& s) { + switch(s) { + case Status::OK: + return OK; + case Status::ILLEGAL_ARGUMENT: + return BAD_VALUE; + case Status::CAMERA_IN_USE: + return -EBUSY; + case Status::MAX_CAMERAS_IN_USE: + return -EUSERS; + case Status::METHOD_NOT_SUPPORTED: + return UNKNOWN_TRANSACTION; + case Status::OPERATION_NOT_SUPPORTED: + return INVALID_OPERATION; + case Status::CAMERA_DISCONNECTED: + return DEAD_OBJECT; + case Status::INTERNAL_ERROR: + return INVALID_OPERATION; + } + ALOGW("Unexpected HAL status code %d", s); + return INVALID_OPERATION; +} + +Status CameraDevice::initStatus() const { + Mutex::Autolock _l(mLock); + Status status = Status::OK; + if (mInitFail) { + status = Status::INTERNAL_ERROR; + } else if (mDisconnected) { + status = Status::CAMERA_DISCONNECTED; + } + return status; +} + +CameraDevice::CameraDevice( + sp<CameraModule> module, const std::string& cameraId, + const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) : + mModule(module), + mCameraId(cameraId), + mDisconnected(false), + mCameraDeviceNames(cameraDeviceNames) { + mCameraIdInt = atoi(mCameraId.c_str()); + // Should not reach here as provider also validate ID + if (mCameraIdInt < 0 || mCameraIdInt >= module->getNumberOfCameras()) { + ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str()); + mInitFail = true; + } + + mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt); + if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_1_0 && !mModule->isOpenLegacyDefined()) { + ALOGI("%s: Camera id %s does not support HAL1.0", + __FUNCTION__, mCameraId.c_str()); + mInitFail = true; + } +} + +CameraDevice::~CameraDevice() { + Mutex::Autolock _l(mLock); + if (mDevice != nullptr) { + ALOGW("%s: camera %s is deleted while open", __FUNCTION__, mCameraId.c_str()); + close(); + } + mHalPreviewWindow.cleanUpCirculatingBuffers(); +} + + +void CameraDevice::setConnectionStatus(bool connected) { + Mutex::Autolock _l(mLock); + mDisconnected = !connected; + if (mDevice == nullptr) { + return; + } + if (!connected) { + ALOGW("%s: camera %s is disconneted. Closing", __FUNCTION__, mCameraId.c_str()); + close(); + } + return; +} + +void CameraDevice::CameraPreviewWindow::cleanUpCirculatingBuffers() { + Mutex::Autolock _l(mLock); + for (auto pair : mCirculatingBuffers) { + sHandleImporter.freeBuffer(pair.second); + } + mCirculatingBuffers.clear(); + mBufferIdMap.clear(); +} + +int CameraDevice::sDequeueBuffer(struct preview_stream_ops* w, + buffer_handle_t** buffer, int *stride) { + CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + + if (buffer == nullptr || stride == nullptr) { + ALOGE("%s: buffer (%p) and stride (%p) must not be null!", __FUNCTION__, buffer, stride); + return BAD_VALUE; + } + + Status s; + object->mPreviewCallback->dequeueBuffer( + [&](auto status, uint64_t bufferId, const auto& buf, uint32_t strd) { + s = status; + if (s == Status::OK) { + Mutex::Autolock _l(object->mLock); + if (object->mCirculatingBuffers.count(bufferId) == 0) { + buffer_handle_t importedBuf = buf.getNativeHandle(); + sHandleImporter.importBuffer(importedBuf); + if (importedBuf == nullptr) { + ALOGE("%s: preview buffer import failed!", __FUNCTION__); + s = Status::INTERNAL_ERROR; + return; + } else { + object->mCirculatingBuffers[bufferId] = importedBuf; + object->mBufferIdMap[&(object->mCirculatingBuffers[bufferId])] = bufferId; + } + } + *buffer = &(object->mCirculatingBuffers[bufferId]); + *stride = strd; + } + }); + return getStatusT(s); +} + +int CameraDevice::sLockBuffer(struct preview_stream_ops*, buffer_handle_t*) { + // TODO: make sure lock_buffer is indeed a no-op (and will always be) + return 0; +} + +int CameraDevice::sEnqueueBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer) { + CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + uint64_t bufferId = object->mBufferIdMap.at(buffer); + return getStatusT(object->mPreviewCallback->enqueueBuffer(bufferId)); +} + +int CameraDevice::sCancelBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer) { + CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + uint64_t bufferId = object->mBufferIdMap.at(buffer); + return getStatusT(object->mPreviewCallback->cancelBuffer(bufferId)); +} + +int CameraDevice::sSetBufferCount(struct preview_stream_ops* w, int count) { + CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + + object->cleanUpCirculatingBuffers(); + return getStatusT(object->mPreviewCallback->setBufferCount(count)); +} + +int CameraDevice::sSetBuffersGeometry(struct preview_stream_ops* w, + int width, int height, int format) { + CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + + object->cleanUpCirculatingBuffers(); + return getStatusT( + object->mPreviewCallback->setBuffersGeometry(width, height, (PixelFormat) format)); +} + +int CameraDevice::sSetCrop(struct preview_stream_ops *w, + int left, int top, int right, int bottom) { + CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + + return getStatusT(object->mPreviewCallback->setCrop(left, top, right, bottom)); +} + +int CameraDevice::sSetTimestamp(struct preview_stream_ops *w, int64_t timestamp) { + CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + + return getStatusT(object->mPreviewCallback->setTimestamp(timestamp)); +} + +int CameraDevice::sSetUsage(struct preview_stream_ops* w, int usage) { + CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + + object->cleanUpCirculatingBuffers(); + return getStatusT(object->mPreviewCallback->setUsage((ProducerUsage) usage)); +} + +int CameraDevice::sSetSwapInterval(struct preview_stream_ops *w, int interval) { + CameraPreviewWindow* object = static_cast<CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + + return getStatusT(object->mPreviewCallback->setSwapInterval(interval)); +} + +int CameraDevice::sGetMinUndequeuedBufferCount( + const struct preview_stream_ops *w, + int *count) { + const CameraPreviewWindow* object = static_cast<const CameraPreviewWindow*>(w); + if (object->mPreviewCallback == nullptr) { + ALOGE("%s: camera HAL calling preview ops while there is no preview window!", __FUNCTION__); + return INVALID_OPERATION; + } + if (count == nullptr) { + ALOGE("%s: count is null!", __FUNCTION__); + return BAD_VALUE; + } + + Status s; + object->mPreviewCallback->getMinUndequeuedBufferCount( + [&](auto status, uint32_t cnt) { + s = status; + if (s == Status::OK) { + *count = cnt; + } + }); + return getStatusT(s); +} + +CameraDevice::CameraHeapMemory::CameraHeapMemory(int fd, size_t buf_size, uint_t num_buffers) : + mBufSize(buf_size), + mNumBufs(num_buffers) { + mHeap = new MemoryHeapBase(fd, buf_size * num_buffers); + commonInitialization(); +} + +CameraDevice::CameraHeapMemory::CameraHeapMemory(size_t buf_size, uint_t num_buffers) : + mBufSize(buf_size), + mNumBufs(num_buffers) { + mHeap = new MemoryHeapBase(buf_size * num_buffers); + commonInitialization(); +} + +void CameraDevice::CameraHeapMemory::commonInitialization() { + handle.data = mHeap->base(); + handle.size = mBufSize * mNumBufs; + handle.handle = this; + + mBuffers = new sp<MemoryBase>[mNumBufs]; + for (uint_t i = 0; i < mNumBufs; i++) { + mBuffers[i] = new MemoryBase(mHeap, i * mBufSize, mBufSize); + } + + handle.release = sPutMemory; +} + +CameraDevice::CameraHeapMemory::~CameraHeapMemory() { + delete [] mBuffers; +} + +// shared memory methods +camera_memory_t* CameraDevice::sGetMemory(int fd, size_t buf_size, uint_t num_bufs, void *user) { + ALOGV("%s", __FUNCTION__); + CameraDevice* object = static_cast<CameraDevice*>(user); + if (object->mDeviceCallback == nullptr) { + ALOGE("%s: camera HAL request memory while camera is not opened!", __FUNCTION__); + return nullptr; + } + + CameraHeapMemory* mem; + native_handle_t* handle = native_handle_create(1,0); + + if (handle == nullptr) { + ALOGE("%s: native_handle_create failed!", __FUNCTION__); + return nullptr; + } + + if (fd < 0) { + mem = new CameraHeapMemory(buf_size, num_bufs); + } else { + mem = new CameraHeapMemory(fd, buf_size, num_bufs); + } + handle->data[0] = mem->mHeap->getHeapID(); + mem->incStrong(mem); + + hidl_handle hidlHandle = handle; + MemoryId id = object->mDeviceCallback->registerMemory(hidlHandle, buf_size, num_bufs); + mem->handle.mId = id; + if (object->mMemoryMap.count(id) != 0) { + ALOGE("%s: duplicate MemoryId %d returned by client!", __FUNCTION__, id); + } + object->mMemoryMap[id] = mem; + mem->handle.mDevice = object; + native_handle_delete(handle); + return &mem->handle; +} + +void CameraDevice::sPutMemory(camera_memory_t *data) { + if (!data) + return; + + CameraHeapMemory* mem = static_cast<CameraHeapMemory *>(data->handle); + CameraDevice* device = mem->handle.mDevice; + if (device == nullptr) { + ALOGE("%s: camera HAL return memory for a null device!", __FUNCTION__); + } + if (device->mDeviceCallback == nullptr) { + ALOGE("%s: camera HAL return memory while camera is not opened!", __FUNCTION__); + } + device->mDeviceCallback->unregisterMemory(mem->handle.mId); + device->mMemoryMap.erase(mem->handle.mId); + mem->decStrong(mem); +} + +// Callback forwarding methods +void CameraDevice::sNotifyCb(int32_t msg_type, int32_t ext1, int32_t ext2, void *user) { + ALOGV("%s", __FUNCTION__); + CameraDevice* object = static_cast<CameraDevice*>(user); + if (object->mDeviceCallback != nullptr) { + object->mDeviceCallback->notifyCallback((NotifyCallbackMsg) msg_type, ext1, ext2); + } +} + +void CameraDevice::sDataCb(int32_t msg_type, const camera_memory_t *data, unsigned int index, + camera_frame_metadata_t *metadata, void *user) { + ALOGV("%s", __FUNCTION__); + CameraDevice* object = static_cast<CameraDevice*>(user); + sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory*>(data->handle)); + if (index >= mem->mNumBufs) { + ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__, + index, mem->mNumBufs); + return; + } + if (object->mDeviceCallback != nullptr) { + CameraFrameMetadata hidlMetadata; + if (metadata) { + hidlMetadata.faces.resize(metadata->number_of_faces); + for (size_t i = 0; i < hidlMetadata.faces.size(); i++) { + hidlMetadata.faces[i].score = metadata->faces[i].score; + hidlMetadata.faces[i].id = metadata->faces[i].id; + for (int k = 0; k < 4; k++) { + hidlMetadata.faces[i].rect[k] = metadata->faces[i].rect[k]; + } + for (int k = 0; k < 2; k++) { + hidlMetadata.faces[i].leftEye[k] = metadata->faces[i].left_eye[k]; + } + for (int k = 0; k < 2; k++) { + hidlMetadata.faces[i].rightEye[k] = metadata->faces[i].right_eye[k]; + } + for (int k = 0; k < 2; k++) { + hidlMetadata.faces[i].mouth[k] = metadata->faces[i].mouth[k]; + } + } + } + CameraHeapMemory* mem = static_cast<CameraHeapMemory *>(data->handle); + object->mDeviceCallback->dataCallback( + (DataCallbackMsg) msg_type, mem->handle.mId, index, hidlMetadata); + } +} + +void CameraDevice::sDataCbTimestamp(nsecs_t timestamp, int32_t msg_type, + const camera_memory_t *data, unsigned index, void *user) { + ALOGV("%s", __FUNCTION__); + CameraDevice* object = static_cast<CameraDevice*>(user); + // Start refcounting the heap object from here on. When the clients + // drop all references, it will be destroyed (as well as the enclosed + // MemoryHeapBase. + sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory*>(data->handle)); + if (index >= mem->mNumBufs) { + ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__, + index, mem->mNumBufs); + return; + } + + native_handle_t* handle = nullptr; + if (object->mMetadataMode) { + if (mem->mBufSize == sizeof(VideoNativeHandleMetadata)) { + VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) + mem->mBuffers[index]->pointer(); + if (md->eType == VideoNativeHandleMetadata::kMetadataBufferTypeNativeHandleSource) { + handle = md->pHandle; + } + } + } + + if (object->mDeviceCallback != nullptr) { + if (handle == nullptr) { + object->mDeviceCallback->dataCallbackTimestamp( + (DataCallbackMsg) msg_type, mem->handle.mId, index, timestamp); + } else { + object->mDeviceCallback->handleCallbackTimestamp( + (DataCallbackMsg) msg_type, handle, mem->handle.mId, index, timestamp); + } + } +} + +void CameraDevice::initHalPreviewWindow() +{ + mHalPreviewWindow.cancel_buffer = sCancelBuffer; + mHalPreviewWindow.lock_buffer = sLockBuffer; + mHalPreviewWindow.dequeue_buffer = sDequeueBuffer; + mHalPreviewWindow.enqueue_buffer = sEnqueueBuffer; + mHalPreviewWindow.set_buffer_count = sSetBufferCount; + mHalPreviewWindow.set_buffers_geometry = sSetBuffersGeometry; + mHalPreviewWindow.set_crop = sSetCrop; + mHalPreviewWindow.set_timestamp = sSetTimestamp; + mHalPreviewWindow.set_usage = sSetUsage; + mHalPreviewWindow.set_swap_interval = sSetSwapInterval; + + mHalPreviewWindow.get_min_undequeued_buffer_count = + sGetMinUndequeuedBufferCount; +} + +// Methods from ::android::hardware::camera::device::V1_0::ICameraDevice follow. +Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) { + Status status = initStatus(); + CameraResourceCost resCost; + if (status == Status::OK) { + int cost = 100; + std::vector<std::string> conflicting_devices; + struct camera_info info; + + // If using post-2.4 module version, query the cost + conflicting devices from the HAL + if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) { + int ret = mModule->getCameraInfo(mCameraIdInt, &info); + if (ret == OK) { + cost = info.resource_cost; + for (size_t i = 0; i < info.conflicting_devices_length; i++) { + std::string cameraId(info.conflicting_devices[i]); + for (const auto& pair : mCameraDeviceNames) { + if (cameraId == pair.first) { + conflicting_devices.push_back(pair.second); + } + } + } + } else { + status = Status::INTERNAL_ERROR; + } + } + + if (status == Status::OK) { + resCost.resourceCost = cost; + resCost.conflictingDevices.resize(conflicting_devices.size()); + for (size_t i = 0; i < conflicting_devices.size(); i++) { + resCost.conflictingDevices[i] = conflicting_devices[i]; + ALOGV("CamDevice %s is conflicting with camDevice %s", + mCameraId.c_str(), resCost.conflictingDevices[i].c_str()); + } + } + } + _hidl_cb(status, resCost); + return Void(); +} + +Return<void> CameraDevice::getCameraInfo(getCameraInfo_cb _hidl_cb) { + Status status = initStatus(); + CameraInfo cameraInfo; + if (status == Status::OK) { + struct camera_info info; + int ret = mModule->getCameraInfo(mCameraIdInt, &info); + if (ret == OK) { + cameraInfo.facing = (CameraFacing) info.facing; + // Device 1.0 does not support external camera facing. + // The closest approximation would be front camera. + // TODO: figure out should we override here or let + // camera service handle it. + if (cameraInfo.facing == CameraFacing::EXTERNAL) { + cameraInfo.facing = CameraFacing::FRONT; + } + cameraInfo.orientation = info.orientation; + } else { + ALOGE("%s: get camera info failed!", __FUNCTION__); + status = Status::INTERNAL_ERROR; + } + } + _hidl_cb(status, cameraInfo); + return Void(); +} + +Return<Status> CameraDevice::setTorchMode(TorchMode mode) { + if (!mModule->isSetTorchModeSupported()) { + return Status::METHOD_NOT_SUPPORTED; + } + + Status status = initStatus(); + if (status == Status::OK) { + bool enable = (mode == TorchMode::ON) ? true : false; + status = getHidlStatus(mModule->setTorchMode(mCameraId.c_str(), enable)); + } + return status; +} + +Return<Status> CameraDevice::dumpState(const hidl_handle& handle) { + Mutex::Autolock _l(mLock); + if (handle.getNativeHandle() == nullptr) { + ALOGE("%s: handle must not be null", __FUNCTION__); + return Status::ILLEGAL_ARGUMENT; + } + if (handle->numFds != 1 || handle->numInts != 0) { + ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints", + __FUNCTION__, handle->numFds, handle->numInts); + return Status::ILLEGAL_ARGUMENT; + } + int fd = handle->data[0]; + + if (mDevice != nullptr) { + if (mDevice->ops->dump) { // It's fine if the HAL doesn't implement dump() + return getHidlStatus(mDevice->ops->dump(mDevice, fd)); + } + } + return Status::OK; +} + +Return<Status> CameraDevice::open(const sp<ICameraDeviceCallback>& callback) { + ALOGI("Opening camera %s", mCameraId.c_str()); + Mutex::Autolock _l(mLock); + + camera_info info; + status_t res = mModule->getCameraInfo(mCameraIdInt, &info); + if (res != OK) { + ALOGE("Could not get camera info: %s: %d", mCameraId.c_str(), res); + return getHidlStatus(res); + } + + int rc = OK; + if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 && + info.device_version > CAMERA_DEVICE_API_VERSION_1_0) { + // Open higher version camera device as HAL1.0 device. + rc = mModule->openLegacy(mCameraId.c_str(), + CAMERA_DEVICE_API_VERSION_1_0, + (hw_device_t **)&mDevice); + } else { + rc = mModule->open(mCameraId.c_str(), (hw_device_t **)&mDevice); + } + if (rc != OK) { + mDevice = nullptr; + ALOGE("Could not open camera %s: %d", mCameraId.c_str(), rc); + return getHidlStatus(rc); + } + + initHalPreviewWindow(); + mDeviceCallback = callback; + + if (mDevice->ops->set_callbacks) { + mDevice->ops->set_callbacks(mDevice, + sNotifyCb, sDataCb, sDataCbTimestamp, sGetMemory, this); + } + + return getHidlStatus(rc); +} + +Return<Status> CameraDevice::setPreviewWindow(const sp<ICameraDevicePreviewCallback>& window) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + + mHalPreviewWindow.mPreviewCallback = window; + if (mDevice->ops->set_preview_window) { + return getHidlStatus(mDevice->ops->set_preview_window(mDevice, + (window == nullptr) ? nullptr : &mHalPreviewWindow)); + } + return Status::INTERNAL_ERROR; // HAL should provide set_preview_window +} + +Return<void> CameraDevice::enableMsgType(uint32_t msgType) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Void(); + } + if (mDevice->ops->enable_msg_type) { + mDevice->ops->enable_msg_type(mDevice, msgType); + } + return Void(); +} + +Return<void> CameraDevice::disableMsgType(uint32_t msgType) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Void(); + } + if (mDevice->ops->disable_msg_type) { + mDevice->ops->disable_msg_type(mDevice, msgType); + } + return Void(); +} + +Return<bool> CameraDevice::msgTypeEnabled(uint32_t msgType) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return false; + } + if (mDevice->ops->msg_type_enabled) { + return mDevice->ops->msg_type_enabled(mDevice, msgType); + } + return false; +} + +Return<Status> CameraDevice::startPreview() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + if (mDevice->ops->start_preview) { + return getHidlStatus(mDevice->ops->start_preview(mDevice)); + } + return Status::INTERNAL_ERROR; // HAL should provide start_preview +} + +Return<void> CameraDevice::stopPreview() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Void(); + } + if (mDevice->ops->stop_preview) { + mDevice->ops->stop_preview(mDevice); + } + return Void(); +} + +Return<bool> CameraDevice::previewEnabled() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return false; + } + if (mDevice->ops->preview_enabled) { + return mDevice->ops->preview_enabled(mDevice); + } + return false; +} + +Return<Status> CameraDevice::storeMetaDataInBuffers(bool enable) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + if (mDevice->ops->store_meta_data_in_buffers) { + status_t s = mDevice->ops->store_meta_data_in_buffers(mDevice, enable); + if (s == OK && enable) { + mMetadataMode = true; + } + return getHidlStatus(s); + } + return enable ? Status::ILLEGAL_ARGUMENT : Status::OK; +} + +Return<Status> CameraDevice::startRecording() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + if (mDevice->ops->start_recording) { + return getHidlStatus(mDevice->ops->start_recording(mDevice)); + } + return Status::ILLEGAL_ARGUMENT; +} + +Return<void> CameraDevice::stopRecording() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Void(); + } + if (mDevice->ops->stop_recording) { + mDevice->ops->stop_recording(mDevice); + } + return Void(); +} + +Return<bool> CameraDevice::recordingEnabled() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return false; + } + if (mDevice->ops->recording_enabled) { + return mDevice->ops->recording_enabled(mDevice); + } + return false; +} + +void CameraDevice::releaseRecordingFrameLocked( + uint32_t memId, uint32_t bufferIndex, const native_handle_t* handle) { + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return; + } + if (mDevice->ops->release_recording_frame) { + CameraHeapMemory* camMemory = mMemoryMap.at(memId); + sp<MemoryHeapBase> heap = camMemory->mHeap; + if (bufferIndex >= camMemory->mNumBufs) { + ALOGE("%s: bufferIndex %d exceeds number of buffers %d", + __FUNCTION__, bufferIndex, camMemory->mNumBufs); + return; + } + sp<IMemory> mem = camMemory->mBuffers[bufferIndex]; + // TODO: simplify below logic once we verify offset is indeed idx * mBufSize + // and heap == heap2 + ssize_t offset; + size_t size; + sp<IMemoryHeap> heap2 = mem->getMemory(&offset, &size); + if ((size_t)offset != bufferIndex * camMemory->mBufSize) { + ALOGI("%s: unexpected offset %zd (was expecting %zu)", + __FUNCTION__, offset, bufferIndex * camMemory->mBufSize); + } + if (heap != heap2) { + ALOGE("%s: heap mismatch!", __FUNCTION__); + return; + } + void *data = ((uint8_t *)heap->base()) + offset; + if (handle) { + VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) data; + if (md->eType == VideoNativeHandleMetadata::kMetadataBufferTypeNativeHandleSource) { + // Input handle will be closed by HIDL transport later, so clone it + // HAL implementation is responsible to close/delete the clone + native_handle_t* clone = native_handle_clone(handle); + if (!clone) { + ALOGE("%s: failed to clone buffer %p", __FUNCTION__, handle); + return; + } + md->pHandle = clone; + } else { + ALOGE("%s:Malform VideoNativeHandleMetadata at memId %d, bufferId %d", + __FUNCTION__, memId, bufferIndex); + return; + } + } + mDevice->ops->release_recording_frame(mDevice, data); + } +} + +Return<void> CameraDevice::releaseRecordingFrame(uint32_t memId, uint32_t bufferIndex) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + releaseRecordingFrameLocked(memId, bufferIndex, nullptr); + return Void(); +} + +Return<void> CameraDevice::releaseRecordingFrameHandle( + uint32_t memId, uint32_t bufferIndex, const hidl_handle& frame) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + releaseRecordingFrameLocked( + memId, bufferIndex, frame.getNativeHandle()); + return Void(); +} + +Return<Status> CameraDevice::autoFocus() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + if (mDevice->ops->auto_focus) { + return getHidlStatus(mDevice->ops->auto_focus(mDevice)); + } + return Status::ILLEGAL_ARGUMENT; +} + +Return<Status> CameraDevice::cancelAutoFocus() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + if (mDevice->ops->cancel_auto_focus) { + return getHidlStatus(mDevice->ops->cancel_auto_focus(mDevice)); + } + return Status::ILLEGAL_ARGUMENT; +} + +Return<Status> CameraDevice::takePicture() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + if (mDevice->ops->take_picture) { + return getHidlStatus(mDevice->ops->take_picture(mDevice)); + } + return Status::ILLEGAL_ARGUMENT; +} + +Return<Status> CameraDevice::cancelPicture() { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + if (mDevice->ops->cancel_picture) { + return getHidlStatus(mDevice->ops->cancel_picture(mDevice)); + } + return Status::ILLEGAL_ARGUMENT; +} + +Return<Status> CameraDevice::setParameters(const hidl_string& params) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + if (mDevice->ops->set_parameters) { + return getHidlStatus(mDevice->ops->set_parameters(mDevice, params.c_str())); + } + return Status::ILLEGAL_ARGUMENT; +} + +Return<void> CameraDevice::getParameters(getParameters_cb _hidl_cb) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + hidl_string outStr; + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + _hidl_cb(outStr); + return Void(); + } + if (mDevice->ops->get_parameters) { + char *temp = mDevice->ops->get_parameters(mDevice); + outStr = temp; + if (mDevice->ops->put_parameters) { + mDevice->ops->put_parameters(mDevice, temp); + } else { + free(temp); + } + } + _hidl_cb(outStr); + return Void(); +} + +Return<Status> CameraDevice::sendCommand(CommandType cmd, int32_t arg1, int32_t arg2) { + ALOGV("%s(%s)", __FUNCTION__, mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if (!mDevice) { + ALOGE("%s called while camera is not opened", __FUNCTION__); + return Status::OPERATION_NOT_SUPPORTED; + } + if (mDevice->ops->send_command) { + return getHidlStatus(mDevice->ops->send_command(mDevice, (int32_t) cmd, arg1, arg2)); + } + return Status::ILLEGAL_ARGUMENT; +} + +Return<void> CameraDevice::close() { + ALOGI("Closing camera %s", mCameraId.c_str()); + Mutex::Autolock _l(mLock); + if(mDevice) { + int rc = mDevice->common.close(&mDevice->common); + if (rc != OK) { + ALOGE("Could not close camera %s: %d", mCameraId.c_str(), rc); + } + mDevice = nullptr; + } + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android
diff --git a/camera/device/1.0/default/CameraDevice_1_0.h b/camera/device/1.0/default/CameraDevice_1_0.h new file mode 100644 index 0000000..2568f86 --- /dev/null +++ b/camera/device/1.0/default/CameraDevice_1_0.h
@@ -0,0 +1,224 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V1_0_CAMERADEVICE_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V1_0_CAMERADEVICE_H + +#include <unordered_map> +#include "utils/Mutex.h" +#include "utils/SortedVector.h" +#include <binder/MemoryBase.h> +#include <binder/MemoryHeapBase.h> +#include "CameraModule.h" +#include "HandleImporter.h" + +#include <android/hardware/camera/device/1.0/ICameraDevice.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::camera::common::V1_0::CameraResourceCost; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::TorchMode; +using ::android::hardware::camera::common::V1_0::helper::CameraModule; +using ::android::hardware::camera::common::V1_0::helper::HandleImporter; +using ::android::hardware::camera::device::V1_0::CameraInfo; +using ::android::hardware::camera::device::V1_0::CommandType; +using ::android::hardware::camera::device::V1_0::ICameraDevice; +using ::android::hardware::camera::device::V1_0::ICameraDeviceCallback; +using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback; +using ::android::hardware::camera::device::V1_0::MemoryId; +using ::android::hidl::base::V1_0::IBase; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +struct CameraDevice : public ICameraDevice { + + // Called by provider HAL. Provider HAL must ensure the uniqueness of + // CameraDevice object per cameraId, or there could be multiple CameraDevice + // trying to access the same physical camera. + // Also, provider will have to keep track of all CameraDevice objects in + // order to notify CameraDevice when the underlying camera is detached + CameraDevice(sp<CameraModule> module, + const std::string& cameraId, + const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames); + ~CameraDevice(); + + // Caller must use this method to check if CameraDevice ctor failed + bool isInitFailed() { return mInitFail; } + // Used by provider HAL to signal external camera disconnected + void setConnectionStatus(bool connected); + + // Methods from ::android::hardware::camera::device::V1_0::ICameraDevice follow. + Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override; + Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb) override; + Return<Status> setTorchMode(TorchMode mode) override; + Return<Status> dumpState(const hidl_handle& fd) override; + Return<Status> open(const sp<ICameraDeviceCallback>& callback) override; + Return<Status> setPreviewWindow(const sp<ICameraDevicePreviewCallback>& window) override; + Return<void> enableMsgType(uint32_t msgType) override; + Return<void> disableMsgType(uint32_t msgType) override; + Return<bool> msgTypeEnabled(uint32_t msgType) override; + Return<Status> startPreview() override; + Return<void> stopPreview() override; + Return<bool> previewEnabled() override; + Return<Status> storeMetaDataInBuffers(bool enable) override; + Return<Status> startRecording() override; + Return<void> stopRecording() override; + Return<bool> recordingEnabled() override; + Return<void> releaseRecordingFrame(uint32_t memId, uint32_t bufferIndex) override; + Return<void> releaseRecordingFrameHandle( + uint32_t memId, uint32_t bufferIndex, const hidl_handle& frame) override; + Return<Status> autoFocus() override; + Return<Status> cancelAutoFocus() override; + Return<Status> takePicture() override; + Return<Status> cancelPicture() override; + Return<Status> setParameters(const hidl_string& params) override; + Return<void> getParameters(getParameters_cb _hidl_cb) override; + Return<Status> sendCommand(CommandType cmd, int32_t arg1, int32_t arg2) override; + Return<void> close() override; + +private: + struct CameraMemory : public camera_memory_t { + MemoryId mId; + CameraDevice* mDevice; + }; + + class CameraHeapMemory : public RefBase { + public: + CameraHeapMemory(int fd, size_t buf_size, uint_t num_buffers = 1); + explicit CameraHeapMemory(size_t buf_size, uint_t num_buffers = 1); + void commonInitialization(); + virtual ~CameraHeapMemory(); + + size_t mBufSize; + uint_t mNumBufs; + // TODO: b/35887419: use hidl_memory instead and get rid of libbinder + sp<MemoryHeapBase> mHeap; + sp<MemoryBase>* mBuffers; + CameraMemory handle; + }; + + // TODO: b/35625849 + // Meta data buffer layout for passing a native_handle to codec + // matching frameworks/native/include/media/hardware/MetadataBufferType.h and + // frameworks/native/include/media/hardware/HardwareAPI.h + struct VideoNativeHandleMetadata { + static const uint32_t kMetadataBufferTypeNativeHandleSource = 3; + uint32_t eType; // must be kMetadataBufferTypeNativeHandleSource + native_handle_t* pHandle; + }; + + const sp<CameraModule> mModule; + const std::string mCameraId; + // const after ctor + int mCameraIdInt; + int mDeviceVersion; + + camera_device_t* mDevice = nullptr; + + void initHalPreviewWindow(); + struct CameraPreviewWindow : public preview_stream_ops { + // Called when we expect buffer will be re-allocated + void cleanUpCirculatingBuffers(); + + Mutex mLock; + sp<ICameraDevicePreviewCallback> mPreviewCallback = nullptr; + std::unordered_map<uint64_t, buffer_handle_t> mCirculatingBuffers; + std::unordered_map<buffer_handle_t*, uint64_t> mBufferIdMap; + } mHalPreviewWindow; + + // gating access to mDevice, mInitFail, mDisconnected + mutable Mutex mLock; + + bool mInitFail = false; + // Set by provider (when external camera is connected/disconnected) + bool mDisconnected; + + static HandleImporter& sHandleImporter; + + const SortedVector<std::pair<std::string, std::string>>& mCameraDeviceNames; + + sp<ICameraDeviceCallback> mDeviceCallback = nullptr; + + std::unordered_map<MemoryId, CameraHeapMemory*> mMemoryMap; + + bool mMetadataMode = false; + + void releaseRecordingFrameLocked(uint32_t memId, uint32_t bufferIndex, const native_handle_t*); + + // shared memory methods + static camera_memory_t* sGetMemory(int fd, size_t buf_size, uint_t num_bufs, void *user); + static void sPutMemory(camera_memory_t *data); + + // Device callback forwarding methods + static void sNotifyCb(int32_t msg_type, int32_t ext1, int32_t ext2, void *user); + static void sDataCb(int32_t msg_type, const camera_memory_t *data, unsigned int index, + camera_frame_metadata_t *metadata, void *user); + static void sDataCbTimestamp(nsecs_t timestamp, int32_t msg_type, + const camera_memory_t *data, unsigned index, void *user); + + // Preview window callback forwarding methods + static int sDequeueBuffer(struct preview_stream_ops* w, + buffer_handle_t** buffer, int *stride); + + static int sLockBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer); + + static int sEnqueueBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer); + + static int sCancelBuffer(struct preview_stream_ops* w, buffer_handle_t* buffer); + + static int sSetBufferCount(struct preview_stream_ops* w, int count); + + static int sSetBuffersGeometry(struct preview_stream_ops* w, + int width, int height, int format); + + static int sSetCrop(struct preview_stream_ops *w, int left, int top, int right, int bottom); + + static int sSetTimestamp(struct preview_stream_ops *w, int64_t timestamp); + + static int sSetUsage(struct preview_stream_ops* w, int usage); + + static int sSetSwapInterval(struct preview_stream_ops *w, int interval); + + static int sGetMinUndequeuedBufferCount(const struct preview_stream_ops *w, int *count); + + // convert conventional HAL status to HIDL Status + static Status getHidlStatus(const int&); + static status_t getStatusT(const Status& s); + + Status initStatus() const; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V1_0_CAMERADEVICE_H
diff --git a/camera/device/1.0/types.hal b/camera/device/1.0/types.hal new file mode 100644 index 0000000..b32c938 --- /dev/null +++ b/camera/device/1.0/types.hal
@@ -0,0 +1,256 @@ +/* + * Copyright (C) 2016 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.camera.device@1.0; + +enum CameraFacing : uint32_t { + /** The facing of the camera is opposite to that of the screen. */ + BACK = 0, + /** The facing of the camera is the same as that of the screen. */ + FRONT = 1, + /** + * The facing of the camera is not fixed relative to the screen. + * The cameras with this facing are external cameras, e.g. USB cameras. + */ + EXTERNAL = 2 +}; + +/** + * Basic information about a camera device, always accessible via + * ICameraDevice::getCameraInfo(). + */ +struct CameraInfo { + /** + * The direction that this device faces. + */ + CameraFacing facing; + + /** + * The orientation of the camera image. The value is the angle that the + * camera image needs to be rotated clockwise so it shows correctly on the + * display in its natural orientation. It must be 0, 90, 180, or 270. + * + * For example, suppose a device has a naturally tall screen. The + * back-facing camera sensor is mounted in landscape. You are looking at the + * screen. If the top side of the camera sensor is aligned with the right + * edge of the screen in natural orientation, the value must be 90. If the + * top side of a front-facing camera sensor is aligned with the right of the + * screen, the value must be 270. + * + * An external camera device must leave this set to 0. + * + */ + uint32_t orientation; + +}; + +/** + * Message types for ICameraDevice@1.0::enableMsgType()/disableMsgType() + * + * A set of bit masks for specifying how the received preview frames are + * handled before the previewCallback() call. + * + * The least significant 3 bits of an "int" value are used for this purpose: + * + * ..... 0 0 0 + * ^ ^ ^ + * | | |---------> determine whether the callback is enabled or not + * | |-----------> determine whether the callback is one-shot or not + * |-------------> determine whether the frame is copied out or not + * + * WARNING: When a frame is sent directly without copying, it is the frame + * receiver's responsiblity to make sure that the frame data won't get + * corrupted by subsequent preview frames filled by the camera. This flag is + * recommended only when copying out data brings significant performance price + * and the handling/processing of the received frame data is always faster than + * the preview frame rate so that data corruption won't occur. + * + * For instance, + * 1. 0x00 disables the callback. In this case, copy out and one shot bits + * are ignored. + * 2. 0x01 enables a callback without copying out the received frames. A + * typical use case is the Camcorder application to avoid making costly + * frame copies. + * 3. 0x05 is enabling a callback with frame copied out repeatedly. A typical + * use case is the Camera application. + * 4. 0x07 is enabling a callback with frame copied out only once. A typical + * use case is the Barcode scanner application. + */ +enum FrameCallbackFlag : uint32_t { + ENABLE_MASK = 0x01, + ONE_SHOT_MASK = 0x02, + COPY_OUT_MASK = 0x04, + /** Typical use cases */ + NOOP = 0x00, + CAMCORDER = 0x01, + CAMERA = 0x05, + BARCODE_SCANNER = 0x07 +}; + +typedef bitfield<FrameCallbackFlag> FrameCallbackFlags; + +/** + * Subset of commands in /system/core/include/system/camera.h relevant for + * ICameraDevice@1.0::sendCommand() + */ +enum CommandType : uint32_t { + START_SMOOTH_ZOOM = 1, + STOP_SMOOTH_ZOOM = 2, + + /** + * Start the face detection. This must be called only after preview is + * started. The camera must notify the listener of CAMERA_MSG_FACE and the + * detected faces in the preview frame. The detected faces may be the same + * as the previous ones. Apps must call CAMERA_CMD_STOP_FACE_DETECTION to + * stop the face detection. This method is supported if CameraParameters + * KEY_MAX_NUM_HW_DETECTED_FACES or KEY_MAX_NUM_SW_DETECTED_FACES is bigger + * than 0. Hardware and software face detection must not be running at the + * same time. If the face detection has started, apps must not send this + * again. + * + * In hardware face detection mode, CameraParameters KEY_WHITE_BALANCE, + * KEY_FOCUS_AREAS and KEY_METERING_AREAS have no effect. + * + * arg1 is the face detection type. It can be CAMERA_FACE_DETECTION_HW or + * CAMERA_FACE_DETECTION_SW. If the type of face detection requested is not + * supported, the HAL must return BAD_VALUE. + */ + START_FACE_DETECTION = 6, + + /** + * Stop the face detection. + */ + STOP_FACE_DETECTION = 7, + + /** + * Enable/disable focus move callback (CAMERA_MSG_FOCUS_MOVE). Passing + * arg1 = 0 must disable, while passing arg1 = 1 must enable the callback. + */ + ENABLE_FOCUS_MOVE_MSG = 8, + + /** + * Configure an explicit format to use for video recording metadata mode. + * This can be used to switch the format from the + * default IMPLEMENTATION_DEFINED gralloc format to some other + * device-supported format, and the default dataspace from the BT_709 color + * space to some other device-supported dataspace. arg1 is the HAL pixel + * format, and arg2 is the HAL dataSpace. This command returns + * INVALID_OPERATION error if it is sent after video recording is started, + * or the command is not supported at all. + * + * If the gralloc format is set to a format other than + * IMPLEMENTATION_DEFINED, then HALv3 devices must use gralloc usage flags + * of SW_READ_OFTEN. + */ + SET_VIDEO_FORMAT = 11 +}; + +/** + * Message types for ICameraDevice1Callback::notifyCallback() + */ +enum NotifyCallbackMsg : uint32_t { + ERROR = 0x0001, + SHUTTER = 0x0002, + FOCUS = 0x0004, + ZOOM = 0x0008, + // Notify on autofocus start and stop. This is useful in continuous + // autofocus - FOCUS_MODE_CONTINUOUS_VIDEO and FOCUS_MODE_CONTINUOUS_PICTURE. + FOCUS_MOVE = 0x0800 +}; + +/** + * Message types for ICameraDevice1Callback::dataCallback() and + * ICameraDevice1Callback::dataCallbackTimestamp() + */ +enum DataCallbackMsg : uint32_t { + PREVIEW_FRAME = 0x0010, + VIDEO_FRAME = 0x0020, + POSTVIEW_FRAME = 0x0040, + RAW_IMAGE = 0x0080, + COMPRESSED_IMAGE = 0x0100, + RAW_IMAGE_NOTIFY = 0x0200, + // Preview frame metadata. This can be combined with + // CAMERA_MSG_PREVIEW_FRAME in dataCallback. For example, the apps can + // request FRAME and METADATA. Or the apps can request only FRAME or only + // METADATA. + PREVIEW_METADATA = 0x0400 +}; + +/** + * Information for a single detected face. + */ + struct CameraFace { + /** + * Bounds of the face [left, top, right, bottom]. (-1000, -1000) represents + * the top-left of the camera field of view, and (1000, 1000) represents the + * bottom-right of the field of view. The width and height cannot be 0 or + * negative. This is supported by both hardware and software face detection. + * + * The direction is relative to the sensor orientation, that is, what the + * sensor sees. The direction is not affected by the rotation or mirroring + * of CAMERA_CMD_SET_DISPLAY_ORIENTATION. + */ + int32_t[4] rect; + + /** + * The confidence level of the face. The range is 1 to 100. 100 is the + * highest confidence. This is supported by both hardware and software + * face detection. + */ + int32_t score; + + /** + * An unique id per face while the face is visible to the tracker. If + * the face leaves the field-of-view and comes back, it will get a new + * id. If the value is 0, id is not supported. + */ + int32_t id; + + /** + * The coordinates of the center of the left eye. The range is -1000 to + * 1000. -2000, -2000 if this is not supported. + */ + int32_t[2] leftEye; + + /** + * The coordinates of the center of the right eye. The range is -1000 to + * 1000. -2000, -2000 if this is not supported. + */ + int32_t[2] rightEye; + + /** + * The coordinates of the center of the mouth. The range is -1000 to 1000. + * -2000, -2000 if this is not supported. + */ + int32_t[2] mouth; + +}; + +/** + * The metadata of the frame data, such as face detection result. + */ +struct CameraFrameMetadata { + /** + * A vector of the detected faces. + */ + vec<CameraFace> faces; +}; + +/* + * A simple integer handle to use to reference a particular memory buffer + * between the HAL and the framework. + */ +typedef uint32_t MemoryId;
diff --git a/camera/device/3.2/Android.bp b/camera/device/3.2/Android.bp new file mode 100644 index 0000000..a3ac721 --- /dev/null +++ b/camera/device/3.2/Android.bp
@@ -0,0 +1,82 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.camera.device@3.2_hal", + srcs: [ + "types.hal", + "ICameraDevice.hal", + "ICameraDeviceCallback.hal", + "ICameraDeviceSession.hal", + ], +} + +genrule { + name: "android.hardware.camera.device@3.2_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@3.2", + srcs: [ + ":android.hardware.camera.device@3.2_hal", + ], + out: [ + "android/hardware/camera/device/3.2/types.cpp", + "android/hardware/camera/device/3.2/CameraDeviceAll.cpp", + "android/hardware/camera/device/3.2/CameraDeviceCallbackAll.cpp", + "android/hardware/camera/device/3.2/CameraDeviceSessionAll.cpp", + ], +} + +genrule { + name: "android.hardware.camera.device@3.2_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.device@3.2", + srcs: [ + ":android.hardware.camera.device@3.2_hal", + ], + out: [ + "android/hardware/camera/device/3.2/types.h", + "android/hardware/camera/device/3.2/ICameraDevice.h", + "android/hardware/camera/device/3.2/IHwCameraDevice.h", + "android/hardware/camera/device/3.2/BnHwCameraDevice.h", + "android/hardware/camera/device/3.2/BpHwCameraDevice.h", + "android/hardware/camera/device/3.2/BsCameraDevice.h", + "android/hardware/camera/device/3.2/ICameraDeviceCallback.h", + "android/hardware/camera/device/3.2/IHwCameraDeviceCallback.h", + "android/hardware/camera/device/3.2/BnHwCameraDeviceCallback.h", + "android/hardware/camera/device/3.2/BpHwCameraDeviceCallback.h", + "android/hardware/camera/device/3.2/BsCameraDeviceCallback.h", + "android/hardware/camera/device/3.2/ICameraDeviceSession.h", + "android/hardware/camera/device/3.2/IHwCameraDeviceSession.h", + "android/hardware/camera/device/3.2/BnHwCameraDeviceSession.h", + "android/hardware/camera/device/3.2/BpHwCameraDeviceSession.h", + "android/hardware/camera/device/3.2/BsCameraDeviceSession.h", + ], +} + +cc_library_shared { + name: "android.hardware.camera.device@3.2", + generated_sources: ["android.hardware.camera.device@3.2_genc++"], + generated_headers: ["android.hardware.camera.device@3.2_genc++_headers"], + export_generated_headers: ["android.hardware.camera.device@3.2_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.camera.common@1.0", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.camera.common@1.0", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], +}
diff --git a/camera/device/3.2/ICameraDevice.hal b/camera/device/3.2/ICameraDevice.hal new file mode 100644 index 0000000..6e66bf3 --- /dev/null +++ b/camera/device/3.2/ICameraDevice.hal
@@ -0,0 +1,199 @@ +/* + * Copyright (C) 2016 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.camera.device@3.2; + +import android.hardware.camera.common@1.0::types; +import ICameraDeviceSession; +import ICameraDeviceCallback; + +/** + * Camera device HAL, first modern version + * + * Supports the android.hardware.Camera API, and the android.hardware.camera2 + * API at LIMITED or better hardware level. + * + */ +interface ICameraDevice { + + /** + * Get camera device resource cost information. + * + * @return status Status code for the operation, one of: + * OK: + * On success + * INTERNAL_ERROR: + * An unexpected internal camera HAL error occurred, and the + * resource cost is not available. + * CAMERA_DISCONNECTED: + * An external camera device has been disconnected, and is no longer + * available. This camera device interface is now stale, and a new + * instance must be acquired if the device is reconnected. All + * subsequent calls on this interface must return + * CAMERA_DISCONNECTED. + * @return resourceCost + * The resources required to open this camera device, or unspecified + * values if status is not OK. + */ + getResourceCost() generates (Status status, CameraResourceCost resourceCost); + + /** + * getCameraCharacteristics: + * + * Return the static camera information for this camera device. This + * information may not change between consecutive calls. + * + * When an external camera is disconnected, its camera id becomes + * invalid. Calling this method with this invalid camera id must result in + * ILLEGAL_ARGUMENT; this may happen even before the device status callback + * is invoked by the HAL. + * + * @return status Status code for the operation, one of: + * OK: + * On a successful open of the camera device. + * INTERNAL_ERROR: + * The camera device cannot be opened due to an internal + * error. + * CAMERA_DISCONNECTED: + * An external camera device has been disconnected, and is no longer + * available. This camera device interface is now stale, and a new + * instance must be acquired if the device is reconnected. All + * subsequent calls on this interface must return + * CAMERA_DISCONNECTED. + * + * @return cameraCharacteristics + * The static metadata for this camera device, or an empty metadata + * structure if status is not OK. + * + */ + getCameraCharacteristics() generates + (Status status, CameraMetadata cameraCharacteristics); + + /** + * setTorchMode: + * + * Turn on or off the torch mode of the flash unit associated with this + * camera device. If the operation is successful, HAL must notify the + * framework torch state by invoking + * ICameraProviderCallback::torchModeStatusChange() with the new state. + * + * An active camera session has a higher priority accessing the flash + * unit. When there are any resource conflicts, such as when open() is + * called to fully activate a camera device, the provider must notify the + * framework through ICameraProviderCallback::torchModeStatusChange() that + * the torch mode has been turned off and the torch mode state has become + * TORCH_MODE_STATUS_NOT_AVAILABLE. When resources to turn on torch mode + * become available again, the provider must notify the framework through + * ICameraProviderCallback::torchModeStatusChange() that the torch mode + * state has become TORCH_MODE_STATUS_AVAILABLE_OFF for set_torch_mode() to + * be called. + * + * When the client calls setTorchMode() to turn on the torch mode of a flash + * unit, if the HAL cannot keep multiple torch modes on simultaneously, the + * HAL must turn off the torch mode(s) that were turned on by previous + * setTorchMode() calls and notify the framework that the torch mode state + * of those flash unit(s) has become TORCH_MODE_STATUS_AVAILABLE_OFF. + * + * @param torchMode The new mode to set the device flash unit to. + * + * @return status Status code for the operation, one of: + * OK: + * On a successful change to the torch state + * INTERNAL_ERROR: + * The flash unit cannot be operated due to an unexpected internal + * error. + * ILLEGAL_ARGUMENT: + * The camera ID is unknown. + * CAMERA_IN_USE: + * This camera device has been opened, so the torch cannot be + * controlled until it is closed. + * MAX_CAMERAS_IN_USE: + * Due to other camera devices being open, or due to other + * resource constraints, the torch cannot be controlled currently. + * METHOD_NOT_SUPPORTED: + * This provider does not support direct operation of flashlight + * torch mode. The framework must open the camera device and turn + * the torch on through the device interface. + * OPERATION_NOT_SUPPORTED: + * This camera device does not have a flash unit. This can + * be returned if and only if android.flash.info.available is + * false. + * CAMERA_DISCONNECTED: + * An external camera device has been disconnected, and is no longer + * available. This camera device interface is now stale, and a new + * instance must be acquired if the device is reconnected. All + * subsequent calls on this interface must return + * CAMERA_DISCONNECTED. + * + */ + setTorchMode(TorchMode mode) generates (Status status); + + /** + * open: + * + * Power on and initialize this camera device for active use, returning a + * session handle for active operations. + * + * @param callback Interface to invoke by the HAL for device asynchronous + * events. + * @return status Status code for the operation, one of: + * OK: + * On a successful open of the camera device. + * INTERNAL_ERROR: + * The camera device cannot be opened due to an internal + * error. + * ILLEGAL_ARGUMENT: + * The callbacks handle is invalid (for example, it is null). + * CAMERA_IN_USE: + * This camera device is already open. + * MAX_CAMERAS_IN_USE: + * The maximal number of camera devices that can be + * opened concurrently were opened already. + * CAMERA_DISCONNECTED: + * This external camera device has been disconnected, and is no + * longer available. This interface is now stale, and a new instance + * must be acquired if the device is reconnected. All subsequent + * calls on this interface must return CAMERA_DISCONNECTED. + * @return cameraDevice The interface to the newly-opened camera session, + * or null if status is not OK. + */ + open(ICameraDeviceCallback callback) generates + (Status status, ICameraDeviceSession session); + + /** + * dumpState: + * + * Print out debugging state for the camera device. This may be called by + * the framework when the camera service is asked for a debug dump, which + * happens when using the dumpsys tool, or when capturing a bugreport. + * + * The passed-in file descriptor can be used to write debugging text using + * dprintf() or write(). The text must be in ASCII encoding only. + * + * In case this camera device has been disconnected, the dump must not fail, + * but may simply print out 'Device disconnected' or equivalent. + * + * Performance requirements: + * + * This must be a non-blocking call. The HAL should return from this call + * in 1ms, must return from this call in 10ms. This call must avoid + * deadlocks, as it may be called at any point during camera operation. + * Any synchronization primitives used (such as mutex locks or semaphores) + * must be acquired with a timeout. + */ + dumpState(handle fd); + +};
diff --git a/camera/device/3.2/ICameraDeviceCallback.hal b/camera/device/3.2/ICameraDeviceCallback.hal new file mode 100644 index 0000000..753d085 --- /dev/null +++ b/camera/device/3.2/ICameraDeviceCallback.hal
@@ -0,0 +1,126 @@ +/* + * Copyright (C) 2016 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.camera.device@3.2; + +import android.hardware.camera.common@1.0::types; + +/** + * + * Callback methods for the HAL to call into the framework. + * + * These methods are used to return metadata and image buffers for a completed + * or failed captures, and to notify the framework of asynchronous events such + * as errors. + * + * The framework must not call back into the HAL from within these callbacks, + * and these calls must not block for extended periods. + * + */ +interface ICameraDeviceCallback { + + /** + * processCaptureResult: + * + * Send results from a completed capture to the framework. + * processCaptureResult() may be invoked multiple times by the HAL in + * response to a single capture request. This allows, for example, the + * metadata and low-resolution buffers to be returned in one call, and + * post-processed JPEG buffers in a later call, once it is available. Each + * call must include the frame number of the request it is returning + * metadata or buffers for. + * + * A component (buffer or metadata) of the complete result may only be + * included in one process_capture_result call. A buffer for each stream, + * and the result metadata, must be returned by the HAL for each request in + * one of the processCaptureResult calls, even in case of errors producing + * some of the output. A call to processCaptureResult() with neither + * output buffers or result metadata is not allowed. + * + * The order of returning metadata and buffers for a single result does not + * matter, but buffers for a given stream must be returned in FIFO order. So + * the buffer for request 5 for stream A must always be returned before the + * buffer for request 6 for stream A. This also applies to the result + * metadata; the metadata for request 5 must be returned before the metadata + * for request 6. + * + * However, different streams are independent of each other, so it is + * acceptable and expected that the buffer for request 5 for stream A may be + * returned after the buffer for request 6 for stream B is. And it is + * acceptable that the result metadata for request 6 for stream B is + * returned before the buffer for request 5 for stream A is. + * + * The HAL retains ownership of result structure, which only needs to be + * valid to access during this call. The framework must copy whatever it + * needs before this call returns. + * + * The output buffers do not need to be filled yet; the framework must wait + * on the stream buffer release sync fence before reading the buffer + * data. Therefore, this method should be called by the HAL as soon as + * possible, even if some or all of the output buffers are still in + * being filled. The HAL must include valid release sync fences into each + * output_buffers stream buffer entry, or -1 if that stream buffer is + * already filled. + * + * If the result buffer cannot be constructed for a request, the HAL must + * return an empty metadata buffer, but still provide the output buffers and + * their sync fences. In addition, notify() must be called with an + * ERROR_RESULT message. + * + * If an output buffer cannot be filled, its status field must be set to + * STATUS_ERROR. In addition, notify() must be called with a ERROR_BUFFER + * message. + * + * If the entire capture has failed, then this method still needs to be + * called to return the output buffers to the framework. All the buffer + * statuses must be STATUS_ERROR, and the result metadata must be an + * empty buffer. In addition, notify() must be called with a ERROR_REQUEST + * message. In this case, individual ERROR_RESULT/ERROR_BUFFER messages + * must not be sent. + * + * Performance requirements: + * + * This is a non-blocking call. The framework must return this call in 5ms. + * + * The pipeline latency (see S7 for definition) should be less than or equal to + * 4 frame intervals, and must be less than or equal to 8 frame intervals. + * + */ + processCaptureResult(CaptureResult result); + + /** + * notify: + * + * Asynchronous notification callback from the HAL, fired for various + * reasons. Only for information independent of frame capture, or that + * require specific timing. + * + * Multiple threads may call notify() simultaneously. + * + * Buffers delivered to the framework must not be dispatched to the + * application layer until a start of exposure timestamp (or input image's + * start of exposure timestamp for a reprocess request) has been received + * via a SHUTTER notify() call. It is highly recommended to dispatch this + * call as early as possible. + * + * ------------------------------------------------------------------------ + * Performance requirements: + * + * This is a non-blocking call. The framework must return this call in 5ms. + */ + notify(NotifyMsg msg); + +};
diff --git a/camera/device/3.2/ICameraDeviceSession.hal b/camera/device/3.2/ICameraDeviceSession.hal new file mode 100644 index 0000000..e92d756 --- /dev/null +++ b/camera/device/3.2/ICameraDeviceSession.hal
@@ -0,0 +1,362 @@ +/* + * Copyright (C) 2016 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.camera.device@3.2; + +import android.hardware.camera.common@1.0::types; + +/** + * Camera device active session interface. + * + * Obtained via ICameraDevice::open(), this interface contains the methods to + * configure and request captures from an active camera device. + * + */ +interface ICameraDeviceSession { + + /** + * constructDefaultRequestSettings: + * + * Create capture settings for standard camera use cases. + * + * The device must return a settings buffer that is configured to meet the + * requested use case, which must be one of the CAMERA3_TEMPLATE_* + * enums. All request control fields must be included. + * + * Performance requirements: + * + * This must be a non-blocking call. The HAL should return from this call + * in 1ms, and must return from this call in 5ms. + * + * Return values: + * @return status Status code for the operation, one of: + * OK: + * On a successful construction of default settings. + * INTERNAL_ERROR: + * An unexpected internal error occurred, and the default settings + * are not available. + * ILLEGAL_ARGUMENT: + * The camera HAL does not support the input template type + * CAMERA_DISCONNECTED: + * An external camera device has been disconnected, and is no longer + * available. This camera device interface is now stale, and a new + * instance must be acquired if the device is reconnected. All + * subsequent calls on this interface must return + * CAMERA_DISCONNECTED. + * @return template The default capture request settings for the requested + * use case, or an empty metadata structure if status is not OK. + * + */ + constructDefaultRequestSettings(RequestTemplate type) generates + (Status status, CameraMetadata requestTemplate); + + /** + * configureStreams: + * + * Reset the HAL camera device processing pipeline and set up new input and + * output streams. This call replaces any existing stream configuration with + * the streams defined in the streamList. This method must be called at + * least once before a request is submitted with processCaptureRequest(). + * + * The streamList must contain at least one output-capable stream, and may + * not contain more than one input-capable stream. + * + * The streamList may contain streams that are also in the currently-active + * set of streams (from the previous call to configureStreams()). These + * streams must already have valid values for usage, maxBuffers, and the + * private pointer. + * + * If the HAL needs to change the stream configuration for an existing + * stream due to the new configuration, it may rewrite the values of usage + * and/or maxBuffers during the configure call. + * + * The framework must detect such a change, and may then reallocate the + * stream buffers before using buffers from that stream in a request. + * + * If a currently-active stream is not included in streamList, the HAL may + * safely remove any references to that stream. It must not be reused in a + * later configureStreams() call by the framework, and all the gralloc + * buffers for it must be freed after the configureStreams() call returns. + * + * If the stream is new, the maxBuffer field of the stream structure must be + * set to 0. The usage must be set to the consumer usage flags. The HAL + * device must set these fields in the configureStreams() return values. + * These fields are then used by the framework and the platform gralloc + * module to allocate the gralloc buffers for each stream. + * + * Newly allocated buffers may be included in a capture request at any time + * by the framework. Once a gralloc buffer is returned to the framework + * with processCaptureResult (and its respective releaseFence has been + * signaled) the framework may free or reuse it at any time. + * + * ------------------------------------------------------------------------ + * + * Preconditions: + * + * The framework must only call this method when no captures are being + * processed. That is, all results have been returned to the framework, and + * all in-flight input and output buffers have been returned and their + * release sync fences have been signaled by the HAL. The framework must not + * submit new requests for capture while the configureStreams() call is + * underway. + * + * Postconditions: + * + * The HAL device must configure itself to provide maximum possible output + * frame rate given the sizes and formats of the output streams, as + * documented in the camera device's static metadata. + * + * Performance requirements: + * + * This call is expected to be heavyweight and possibly take several hundred + * milliseconds to complete, since it may require resetting and + * reconfiguring the image sensor and the camera processing pipeline. + * Nevertheless, the HAL device should attempt to minimize the + * reconfiguration delay to minimize the user-visible pauses during + * application operational mode changes (such as switching from still + * capture to video recording). + * + * The HAL should return from this call in 500ms, and must return from this + * call in 1000ms. + * + * @return Status Status code for the operation, one of: + * OK: + * On successful stream configuration. + * INTERNAL_ERROR: + * If there has been a fatal error and the device is no longer + * operational. Only close() can be called successfully by the + * framework after this error is returned. + * ILLEGAL_ARGUMENT: + * If the requested stream configuration is invalid. Some examples + * of invalid stream configurations include: + * - Including more than 1 INPUT stream + * - Not including any OUTPUT streams + * - Including streams with unsupported formats, or an unsupported + * size for that format. + * - Including too many output streams of a certain format. + * - Unsupported rotation configuration + * - Stream sizes/formats don't satisfy the + * camera3_stream_configuration_t->operation_mode requirements + * for non-NORMAL mode, or the requested operation_mode is not + * supported by the HAL. + * The camera service cannot filter out all possible illegal stream + * configurations, since some devices may support more simultaneous + * streams or larger stream resolutions than the minimum required + * for a given camera device hardware level. The HAL must return an + * ILLEGAL_ARGUMENT for any unsupported stream set, and then be + * ready to accept a future valid stream configuration in a later + * configureStreams call. + * @return finalConfiguration The stream parameters desired by the HAL for + * each stream, including maximum buffers, the usage flags, and the + * override format. + * + */ + configureStreams(StreamConfiguration requestedConfiguration) + generates (Status status, + HalStreamConfiguration halConfiguration); + + /** + * processCaptureRequest: + * + * Send a new capture request to the HAL. The HAL must not return from + * this call until it is ready to accept the next request to process. Only + * one call to processCaptureRequest() must be made at a time by the + * framework, and the calls must all be from the same thread. The next call + * to processCaptureRequest() must be made as soon as a new request and + * its associated buffers are available. In a normal preview scenario, this + * means the function is generally called again by the framework almost + * instantly. + * + * The actual request processing is asynchronous, with the results of + * capture being returned by the HAL through the processCaptureResult() + * call. This call requires the result metadata to be available, but output + * buffers may simply provide sync fences to wait on. Multiple requests are + * expected to be in flight at once, to maintain full output frame rate. + * + * The framework retains ownership of the request structure. It is only + * guaranteed to be valid during this call. The HAL device must make copies + * of the information it needs to retain for the capture processing. The HAL + * is responsible for waiting on and closing the buffers' fences and + * returning the buffer handles to the framework. + * + * The HAL must write the file descriptor for the input buffer's release + * sync fence into input_buffer->release_fence, if input_buffer is not + * valid. If the HAL returns -1 for the input buffer release sync fence, the + * framework is free to immediately reuse the input buffer. Otherwise, the + * framework must wait on the sync fence before refilling and reusing the + * input buffer. + * + * The input/output buffers provided by the framework in each request + * may be brand new (having never before seen by the HAL). + * + * ------------------------------------------------------------------------ + * Performance considerations: + * + * Handling a new buffer should be extremely lightweight and there must be + * no frame rate degradation or frame jitter introduced. + * + * This call must return fast enough to ensure that the requested frame + * rate can be sustained, especially for streaming cases (post-processing + * quality settings set to FAST). The HAL should return this call in 1 + * frame interval, and must return from this call in 4 frame intervals. + * + * @return status Status code for the operation, one of: + * OK: + * On a successful start to processing the capture request + * ILLEGAL_ARGUMENT: + * If the input is malformed (the settings are empty when not + * allowed, there are 0 output buffers, etc) and capture processing + * cannot start. Failures during request processing must be + * handled by calling ICameraDeviceCallback::notify(). In case of + * this error, the framework retains responsibility for the + * stream buffers' fences and the buffer handles; the HAL must not + * close the fences or return these buffers with + * ICameraDeviceCallback::processCaptureResult(). + * INTERNAL_ERROR: + * If the camera device has encountered a serious error. After this + * error is returned, only the close() method can be successfully + * called by the framework. + * + */ + processCaptureRequest(CaptureRequest request) + generates (Status status); + + /** + * flush: + * + * Flush all currently in-process captures and all buffers in the pipeline + * on the given device. Generally, this method is used to dump all state as + * quickly as possible in order to prepare for a configure_streams() call. + * + * No buffers are required to be successfully returned, so every buffer + * held at the time of flush() (whether successfully filled or not) may be + * returned with CAMERA3_BUFFER_STATUS_ERROR. Note the HAL is still allowed + * to return valid (CAMERA3_BUFFER_STATUS_OK) buffers during this call, + * provided they are successfully filled. + * + * All requests currently in the HAL are expected to be returned as soon as + * possible. Not-in-process requests must return errors immediately. Any + * interruptible hardware blocks must be stopped, and any uninterruptible + * blocks must be waited on. + * + * flush() may be called concurrently to processCaptureRequest(), with the + * expectation that processCaptureRequest returns quickly and the + * request submitted in that processCaptureRequest call is treated like + * all other in-flight requests. Due to concurrency issues, it is possible + * that from the HAL's point of view, a processCaptureRequest() call may + * be started after flush has been invoked but has not returned yet. If such + * a call happens before flush() returns, the HAL must treat the new + * capture request like other in-flight pending requests (see #4 below). + * + * More specifically, the HAL must follow below requirements for various + * cases: + * + * 1. For captures that are too late for the HAL to cancel/stop, and must be + * completed normally by the HAL; i.e. the HAL can send shutter/notify + * and processCaptureResult and buffers as normal. + * + * 2. For pending requests that have not done any processing, the HAL must + * call notify CAMERA3_MSG_ERROR_REQUEST, and return all the output + * buffers with processCaptureResult in the error state + * (CAMERA3_BUFFER_STATUS_ERROR). The HAL must not place the release + * fence into an error state, instead, the release fences must be set to + * the acquire fences passed by the framework, or -1 if they have been + * waited on by the HAL already. This is also the path to follow for any + * captures for which the HAL already called notify() with + * CAMERA3_MSG_SHUTTER but won't be producing any metadata/valid buffers + * for. After CAMERA3_MSG_ERROR_REQUEST, for a given frame, only + * processCaptureResults with buffers in CAMERA3_BUFFER_STATUS_ERROR + * are allowed. No further notifys or processCaptureResult with + * non-empty metadata is allowed. + * + * 3. For partially completed pending requests that do not have all the + * output buffers or perhaps missing metadata, the HAL must follow + * below: + * + * 3.1. Call notify with CAMERA3_MSG_ERROR_RESULT if some of the expected + * result metadata (i.e. one or more partial metadata) won't be + * available for the capture. + * + * 3.2. Call notify with CAMERA3_MSG_ERROR_BUFFER for every buffer that + * won't be produced for the capture. + * + * 3.3. Call notify with CAMERA3_MSG_SHUTTER with the capture timestamp + * before any buffers/metadata are returned with + * processCaptureResult. + * + * 3.4. For captures that will produce some results, the HAL must not + * call CAMERA3_MSG_ERROR_REQUEST, since that indicates complete + * failure. + * + * 3.5. Valid buffers/metadata must be passed to the framework as + * normal. + * + * 3.6. Failed buffers must be returned to the framework as described + * for case 2. But failed buffers do not have to follow the strict + * ordering valid buffers do, and may be out-of-order with respect + * to valid buffers. For example, if buffers A, B, C, D, E are sent, + * D and E are failed, then A, E, B, D, C is an acceptable return + * order. + * + * 3.7. For fully-missing metadata, calling CAMERA3_MSG_ERROR_RESULT is + * sufficient, no need to call processCaptureResult with empty + * metadata or equivalent. + * + * 4. If a flush() is invoked while a processCaptureRequest() invocation + * is active, that process call must return as soon as possible. In + * addition, if a processCaptureRequest() call is made after flush() + * has been invoked but before flush() has returned, the capture request + * provided by the late processCaptureRequest call must be treated + * like a pending request in case #2 above. + * + * flush() must only return when there are no more outstanding buffers or + * requests left in the HAL. The framework may call configure_streams (as + * the HAL state is now quiesced) or may issue new requests. + * + * Note that it's sufficient to only support fully-succeeded and + * fully-failed result cases. However, it is highly desirable to support + * the partial failure cases as well, as it could help improve the flush + * call overall performance. + * + * Performance requirements: + * + * The HAL should return from this call in 100ms, and must return from this + * call in 1000ms. And this call must not be blocked longer than pipeline + * latency (see S7 for definition). + * + * @return status Status code for the operation, one of: + * OK: + * On a successful flush of the camera HAL. + * INTERNAL_ERROR: + * If the camera device has encountered a serious error. After this + * error is returned, only the close() method can be successfully + * called by the framework. + */ + flush() generates (Status status); + + /** + * close: + * + * Shut down the camera device. + * + * After this call, all calls to this session instance must return + * INTERNAL_ERROR. + * + * This method must always succeed, even if the device has encountered a + * serious error. + */ + close(); +};
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp new file mode 100644 index 0000000..e0dc5ff --- /dev/null +++ b/camera/device/3.2/default/Android.bp
@@ -0,0 +1,23 @@ +cc_library_shared { + name: "camera.device@3.2-impl", + defaults: ["hidl_defaults"], + proprietary: true, + srcs: ["CameraDevice.cpp", + "CameraDeviceSession.cpp", + "convert.cpp"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libutils", + "libcutils", + "android.hardware.camera.device@3.2", + "android.hardware.camera.provider@2.4", + "liblog", + "libhardware", + "libcamera_metadata" + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper" + ], + export_include_dirs: ["."] +}
diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp new file mode 100644 index 0000000..0a457ad --- /dev/null +++ b/camera/device/3.2/default/CameraDevice.cpp
@@ -0,0 +1,285 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "CamDev@3.2-impl" +#include <utils/Log.h> + +#include <utils/Vector.h> +#include <utils/Trace.h> +#include "CameraDevice_3_2.h" +#include <include/convert.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_2 { +namespace implementation { + +using ::android::hardware::camera::common::V1_0::Status; + +CameraDevice::CameraDevice( + sp<CameraModule> module, const std::string& cameraId, + const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) : + mModule(module), + mCameraId(cameraId), + mDisconnected(false), + mCameraDeviceNames(cameraDeviceNames) { + mCameraIdInt = atoi(mCameraId.c_str()); + // Should not reach here as provider also validate ID + if (mCameraIdInt < 0 || mCameraIdInt >= module->getNumberOfCameras()) { + ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str()); + mInitFail = true; + } + + mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt); + if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) { + ALOGE("%s: Camera id %s does not support HAL3.2+", + __FUNCTION__, mCameraId.c_str()); + mInitFail = true; + } +} + +CameraDevice::~CameraDevice() {} + +Status CameraDevice::initStatus() const { + Mutex::Autolock _l(mLock); + Status status = Status::OK; + if (mInitFail) { + status = Status::INTERNAL_ERROR; + } else if (mDisconnected) { + status = Status::CAMERA_DISCONNECTED; + } + return status; +} + +void CameraDevice::setConnectionStatus(bool connected) { + Mutex::Autolock _l(mLock); + mDisconnected = !connected; + if (mSession == nullptr) { + return; + } + sp<CameraDeviceSession> session = mSession.promote(); + if (session == nullptr) { + return; + } + // Only notify active session disconnect events. + // Users will need to re-open camera after disconnect event + if (!connected) { + session->disconnect(); + } + return; +} + +Status CameraDevice::getHidlStatus(int status) { + switch (status) { + case 0: return Status::OK; + case -ENOSYS: return Status::OPERATION_NOT_SUPPORTED; + case -EBUSY : return Status::CAMERA_IN_USE; + case -EUSERS: return Status::MAX_CAMERAS_IN_USE; + case -ENODEV: return Status::INTERNAL_ERROR; + case -EINVAL: return Status::ILLEGAL_ARGUMENT; + default: + ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status); + return Status::INTERNAL_ERROR; + } +} + +// Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. +Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) { + Status status = initStatus(); + CameraResourceCost resCost; + if (status == Status::OK) { + int cost = 100; + std::vector<std::string> conflicting_devices; + struct camera_info info; + + // If using post-2.4 module version, query the cost + conflicting devices from the HAL + if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) { + int ret = mModule->getCameraInfo(mCameraIdInt, &info); + if (ret == OK) { + cost = info.resource_cost; + for (size_t i = 0; i < info.conflicting_devices_length; i++) { + std::string cameraId(info.conflicting_devices[i]); + for (const auto& pair : mCameraDeviceNames) { + if (cameraId == pair.first) { + conflicting_devices.push_back(pair.second); + } + } + } + } else { + status = Status::INTERNAL_ERROR; + } + } + + if (status == Status::OK) { + resCost.resourceCost = cost; + resCost.conflictingDevices.resize(conflicting_devices.size()); + for (size_t i = 0; i < conflicting_devices.size(); i++) { + resCost.conflictingDevices[i] = conflicting_devices[i]; + ALOGV("CamDevice %s is conflicting with camDevice %s", + mCameraId.c_str(), resCost.conflictingDevices[i].c_str()); + } + } + } + _hidl_cb(status, resCost); + return Void(); +} + +Return<void> CameraDevice::getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) { + Status status = initStatus(); + CameraMetadata cameraCharacteristics; + if (status == Status::OK) { + //Module 2.1+ codepath. + struct camera_info info; + int ret = mModule->getCameraInfo(mCameraIdInt, &info); + if (ret == OK) { + convertToHidl(info.static_camera_characteristics, &cameraCharacteristics); + } else { + ALOGE("%s: get camera info failed!", __FUNCTION__); + status = Status::INTERNAL_ERROR; + } + } + _hidl_cb(status, cameraCharacteristics); + return Void(); +} + +Return<Status> CameraDevice::setTorchMode(TorchMode mode) { + if (!mModule->isSetTorchModeSupported()) { + return Status::METHOD_NOT_SUPPORTED; + } + + Status status = initStatus(); + if (status == Status::OK) { + bool enable = (mode == TorchMode::ON) ? true : false; + status = getHidlStatus(mModule->setTorchMode(mCameraId.c_str(), enable)); + } + return status; +} + +Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) { + Status status = initStatus(); + sp<CameraDeviceSession> session = nullptr; + + if (callback == nullptr) { + ALOGE("%s: cannot open camera %s. callback is null!", + __FUNCTION__, mCameraId.c_str()); + _hidl_cb(Status::ILLEGAL_ARGUMENT, session); + return Void(); + } + + if (status != Status::OK) { + // Provider will never pass initFailed device to client, so + // this must be a disconnected camera + ALOGE("%s: cannot open camera %s. camera is disconnected!", + __FUNCTION__, mCameraId.c_str()); + _hidl_cb(Status::CAMERA_DISCONNECTED, session); + return Void(); + } else { + mLock.lock(); + + ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mCameraIdInt); + session = mSession.promote(); + if (session != nullptr && !session->isClosed()) { + ALOGE("%s: cannot open an already opened camera!", __FUNCTION__); + mLock.unlock(); + _hidl_cb(Status::CAMERA_IN_USE, nullptr); + return Void(); + } + + /** Open HAL device */ + status_t res; + camera3_device_t *device; + + ATRACE_BEGIN("camera3->open"); + res = mModule->open(mCameraId.c_str(), + reinterpret_cast<hw_device_t**>(&device)); + ATRACE_END(); + + if (res != OK) { + ALOGE("%s: cannot open camera %s!", __FUNCTION__, mCameraId.c_str()); + mLock.unlock(); + _hidl_cb(getHidlStatus(res), nullptr); + return Void(); + } + + /** Cross-check device version */ + if (device->common.version < CAMERA_DEVICE_API_VERSION_3_2) { + ALOGE("%s: Could not open camera: " + "Camera device should be at least %x, reports %x instead", + __FUNCTION__, + CAMERA_DEVICE_API_VERSION_3_2, + device->common.version); + device->common.close(&device->common); + mLock.unlock(); + _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); + return Void(); + } + + session = new CameraDeviceSession(device, callback); + if (session == nullptr) { + ALOGE("%s: camera device session allocation failed", __FUNCTION__); + mLock.unlock(); + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } + if (session->isInitFailed()) { + ALOGE("%s: camera device session init failed", __FUNCTION__); + session = nullptr; + mLock.unlock(); + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } + mSession = session; + mLock.unlock(); + } + _hidl_cb(status, session); + return Void(); +} + +Return<void> CameraDevice::dumpState(const ::android::hardware::hidl_handle& handle) { + Mutex::Autolock _l(mLock); + if (handle.getNativeHandle() == nullptr) { + ALOGE("%s: handle must not be null", __FUNCTION__); + return Void(); + } + if (handle->numFds != 1 || handle->numInts != 0) { + ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints", + __FUNCTION__, handle->numFds, handle->numInts); + return Void(); + } + int fd = handle->data[0]; + if (mSession == nullptr) { + dprintf(fd, "No active camera device session instance\n"); + return Void(); + } + sp<CameraDeviceSession> session = mSession.promote(); + if (session == nullptr) { + dprintf(fd, "No active camera device session instance\n"); + return Void(); + } + // Call into active session to dump states + session->dumpState(handle); + return Void(); +} +// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice. + +} // namespace implementation +} // namespace V3_2 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp new file mode 100644 index 0000000..ae5d576 --- /dev/null +++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -0,0 +1,564 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "CamDevSession@3.2-impl" +#include <android/log.h> + +#include <utils/Trace.h> +#include <hardware/gralloc.h> +#include <hardware/gralloc1.h> +#include "CameraDeviceSession.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_2 { +namespace implementation { + +HandleImporter& CameraDeviceSession::sHandleImporter = HandleImporter::getInstance(); + +CameraDeviceSession::CameraDeviceSession( + camera3_device_t* device, const sp<ICameraDeviceCallback>& callback) : + camera3_callback_ops({&sProcessCaptureResult, &sNotify}), + mDevice(device), + mCallback(callback) { + mInitFail = initialize(); +} + +bool CameraDeviceSession::initialize() { + /** Initialize device with callback functions */ + ATRACE_BEGIN("camera3->initialize"); + status_t res = mDevice->ops->initialize(mDevice, this); + ATRACE_END(); + + if (res != OK) { + ALOGE("%s: Unable to initialize HAL device: %s (%d)", + __FUNCTION__, strerror(-res), res); + mDevice->common.close(&mDevice->common); + mClosed = true; + return true; + } + return false; +} + +CameraDeviceSession::~CameraDeviceSession() { + if (!isClosed()) { + ALOGE("CameraDeviceSession deleted before close!"); + close(); + } +} + +bool CameraDeviceSession::isClosed() { + Mutex::Autolock _l(mStateLock); + return mClosed; +} + +Status CameraDeviceSession::initStatus() const { + Mutex::Autolock _l(mStateLock); + Status status = Status::OK; + if (mInitFail) { + status = Status::INTERNAL_ERROR; + } else if (mDisconnected) { + status = Status::CAMERA_DISCONNECTED; + } else if (mClosed) { + status = Status::INTERNAL_ERROR; + } + return status; +} + +void CameraDeviceSession::disconnect() { + Mutex::Autolock _l(mStateLock); + mDisconnected = true; + ALOGW("%s: Camera device is disconnected. Closing.", __FUNCTION__); + if (!mClosed) { + mDevice->common.close(&mDevice->common); + mClosed = true; + } +} + +void CameraDeviceSession::dumpState(const native_handle_t* fd) { + if (!isClosed()) { + mDevice->ops->dump(mDevice, fd->data[0]); + } +} + +Status CameraDeviceSession::importRequest( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences) { + bool hasInputBuf = (request.inputBuffer.streamId != -1 && + request.inputBuffer.bufferId != 0); + size_t numOutputBufs = request.outputBuffers.size(); + size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0); + // Validate all I/O buffers + hidl_vec<buffer_handle_t> allBufs; + hidl_vec<uint64_t> allBufIds; + allBufs.resize(numBufs); + allBufIds.resize(numBufs); + allBufPtrs.resize(numBufs); + allFences.resize(numBufs); + std::vector<int32_t> streamIds(numBufs); + + for (size_t i = 0; i < numOutputBufs; i++) { + allBufs[i] = request.outputBuffers[i].buffer.getNativeHandle(); + allBufIds[i] = request.outputBuffers[i].bufferId; + allBufPtrs[i] = &allBufs[i]; + streamIds[i] = request.outputBuffers[i].streamId; + } + if (hasInputBuf) { + allBufs[numOutputBufs] = request.inputBuffer.buffer.getNativeHandle(); + allBufIds[numOutputBufs] = request.inputBuffer.bufferId; + allBufPtrs[numOutputBufs] = &allBufs[numOutputBufs]; + streamIds[numOutputBufs] = request.inputBuffer.streamId; + } + + for (size_t i = 0; i < numBufs; i++) { + buffer_handle_t buf = allBufs[i]; + uint64_t bufId = allBufIds[i]; + CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]]; + if (cbs.count(bufId) == 0) { + if (buf == nullptr) { + ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId); + return Status::ILLEGAL_ARGUMENT; + } + // Register a newly seen buffer + buffer_handle_t importedBuf = buf; + sHandleImporter.importBuffer(importedBuf); + if (importedBuf == nullptr) { + ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i); + return Status::INTERNAL_ERROR; + } else { + cbs[bufId] = importedBuf; + } + } + allBufPtrs[i] = &cbs[bufId]; + } + + // All buffers are imported. Now validate output buffer acquire fences + for (size_t i = 0; i < numOutputBufs; i++) { + if (!sHandleImporter.importFence( + request.outputBuffers[i].acquireFence, allFences[i])) { + ALOGE("%s: output buffer %zu acquire fence is invalid", __FUNCTION__, i); + cleanupInflightFences(allFences, i); + return Status::INTERNAL_ERROR; + } + } + + // Validate input buffer acquire fences + if (hasInputBuf) { + if (!sHandleImporter.importFence( + request.inputBuffer.acquireFence, allFences[numOutputBufs])) { + ALOGE("%s: input buffer acquire fence is invalid", __FUNCTION__); + cleanupInflightFences(allFences, numOutputBufs); + return Status::INTERNAL_ERROR; + } + } + return Status::OK; +} + +void CameraDeviceSession::cleanupInflightFences( + hidl_vec<int>& allFences, size_t numFences) { + for (size_t j = 0; j < numFences; j++) { + sHandleImporter.closeFence(allFences[j]); + } +} + +// Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow. +Return<void> CameraDeviceSession::constructDefaultRequestSettings( + RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb) { + Status status = initStatus(); + CameraMetadata outMetadata; + const camera_metadata_t *rawRequest; + if (status == Status::OK) { + ATRACE_BEGIN("camera3->construct_default_request_settings"); + rawRequest = mDevice->ops->construct_default_request_settings(mDevice, (int) type); + ATRACE_END(); + if (rawRequest == nullptr) { + ALOGI("%s: template %d is not supported on this camera device", + __FUNCTION__, type); + status = Status::ILLEGAL_ARGUMENT; + } else { + convertToHidl(rawRequest, &outMetadata); + } + } + _hidl_cb(status, outMetadata); + return Void(); +} + +Return<void> CameraDeviceSession::configureStreams( + const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) { + Status status = initStatus(); + HalStreamConfiguration outStreams; + + // hold the inflight lock for entire configureStreams scope since there must not be any + // inflight request/results during stream configuration. + Mutex::Autolock _l(mInflightLock); + if (!mInflightBuffers.empty()) { + ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!", + __FUNCTION__, mInflightBuffers.size()); + _hidl_cb(Status::INTERNAL_ERROR, outStreams); + return Void(); + } + + if (status != Status::OK) { + _hidl_cb(status, outStreams); + return Void(); + } + + camera3_stream_configuration_t stream_list; + hidl_vec<camera3_stream_t*> streams; + + stream_list.operation_mode = (uint32_t) requestedConfiguration.operationMode; + stream_list.num_streams = requestedConfiguration.streams.size(); + streams.resize(stream_list.num_streams); + stream_list.streams = streams.data(); + + for (uint32_t i = 0; i < stream_list.num_streams; i++) { + int id = requestedConfiguration.streams[i].id; + + if (mStreamMap.count(id) == 0) { + Camera3Stream stream; + convertFromHidl(requestedConfiguration.streams[i], &stream); + mStreamMap[id] = stream; + mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{}); + } else { + // width/height/format must not change, but usage/rotation might need to change + if (mStreamMap[id].stream_type != + (int) requestedConfiguration.streams[i].streamType || + mStreamMap[id].width != requestedConfiguration.streams[i].width || + mStreamMap[id].height != requestedConfiguration.streams[i].height || + mStreamMap[id].format != (int) requestedConfiguration.streams[i].format || + mStreamMap[id].data_space != (android_dataspace_t) + requestedConfiguration.streams[i].dataSpace) { + ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id); + _hidl_cb(Status::INTERNAL_ERROR, outStreams); + return Void(); + } + mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation; + mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage; + } + streams[i] = &mStreamMap[id]; + } + + ATRACE_BEGIN("camera3->configure_streams"); + status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list); + ATRACE_END(); + + // In case Hal returns error most likely it was not able to release + // the corresponding resources of the deleted streams. + if (ret == OK) { + // delete unused streams, note we do this after adding new streams to ensure new stream + // will not have the same address as deleted stream, and HAL has a chance to reference + // the to be deleted stream in configure_streams call + for(auto it = mStreamMap.begin(); it != mStreamMap.end();) { + int id = it->first; + bool found = false; + for (const auto& stream : requestedConfiguration.streams) { + if (id == stream.id) { + found = true; + break; + } + } + if (!found) { + // Unmap all buffers of deleted stream + // in case the configuration call succeeds and HAL + // is able to release the corresponding resources too. + cleanupBuffersLocked(id); + it = mStreamMap.erase(it); + } else { + ++it; + } + } + } + + if (ret == -EINVAL) { + status = Status::ILLEGAL_ARGUMENT; + } else if (ret != OK) { + status = Status::INTERNAL_ERROR; + } else { + convertToHidl(stream_list, &outStreams); + } + + _hidl_cb(status, outStreams); + return Void(); +} + +// Needs to get called after acquiring 'mInflightLock' +void CameraDeviceSession::cleanupBuffersLocked(int id) { + for (auto& pair : mCirculatingBuffers.at(id)) { + sHandleImporter.freeBuffer(pair.second); + } + mCirculatingBuffers[id].clear(); + mCirculatingBuffers.erase(id); +} + +Return<Status> CameraDeviceSession::processCaptureRequest(const CaptureRequest& request) { + Status status = initStatus(); + if (status != Status::OK) { + ALOGE("%s: camera init failed or disconnected", __FUNCTION__); + return status; + } + + camera3_capture_request_t halRequest; + halRequest.frame_number = request.frameNumber; + bool converted = convertFromHidl(request.settings, &halRequest.settings); + if (!converted) { + ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__); + return Status::INTERNAL_ERROR; + } + + hidl_vec<buffer_handle_t*> allBufPtrs; + hidl_vec<int> allFences; + bool hasInputBuf = (request.inputBuffer.streamId != -1 && + request.inputBuffer.bufferId != 0); + size_t numOutputBufs = request.outputBuffers.size(); + size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0); + status = importRequest(request, allBufPtrs, allFences); + if (status != Status::OK) { + return status; + } + + hidl_vec<camera3_stream_buffer_t> outHalBufs; + outHalBufs.resize(numOutputBufs); + { + Mutex::Autolock _l(mInflightLock); + if (hasInputBuf) { + auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber); + auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{}; + convertFromHidl( + allBufPtrs[numOutputBufs], request.inputBuffer.status, + &mStreamMap[request.inputBuffer.streamId], allFences[numOutputBufs], + &bufCache); + halRequest.input_buffer = &bufCache; + } else { + halRequest.input_buffer = nullptr; + } + + halRequest.num_output_buffers = numOutputBufs; + for (size_t i = 0; i < numOutputBufs; i++) { + auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber); + auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{}; + convertFromHidl( + allBufPtrs[i], request.outputBuffers[i].status, + &mStreamMap[request.outputBuffers[i].streamId], allFences[i], + &bufCache); + outHalBufs[i] = bufCache; + } + halRequest.output_buffers = outHalBufs.data(); + } + + ATRACE_ASYNC_BEGIN("frame capture", request.frameNumber); + ATRACE_BEGIN("camera3->process_capture_request"); + status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest); + ATRACE_END(); + if (ret != OK) { + Mutex::Autolock _l(mInflightLock); + ALOGE("%s: HAL process_capture_request call failed!", __FUNCTION__); + + cleanupInflightFences(allFences, numBufs); + if (hasInputBuf) { + auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber); + mInflightBuffers.erase(key); + } + for (size_t i = 0; i < numOutputBufs; i++) { + auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber); + mInflightBuffers.erase(key); + } + return Status::INTERNAL_ERROR; + } + + return Status::OK; +} + +Return<Status> CameraDeviceSession::flush() { + Status status = initStatus(); + if (status == Status::OK) { + // Flush is always supported on device 3.1 or later + status_t ret = mDevice->ops->flush(mDevice); + if (ret != OK) { + status = Status::INTERNAL_ERROR; + } + } + return status; +} + +Return<void> CameraDeviceSession::close() { + Mutex::Autolock _l(mStateLock); + if (!mClosed) { + { + Mutex::Autolock _l(mInflightLock); + if (!mInflightBuffers.empty()) { + ALOGE("%s: trying to close while there are still %zu inflight buffers!", + __FUNCTION__, mInflightBuffers.size()); + } + } + + ATRACE_BEGIN("camera3->close"); + mDevice->common.close(&mDevice->common); + ATRACE_END(); + + // free all imported buffers + for(auto& pair : mCirculatingBuffers) { + CirculatingBuffers& buffers = pair.second; + for (auto& p2 : buffers) { + sHandleImporter.freeBuffer(p2.second); + } + } + + mClosed = true; + } + return Void(); +} + +/** + * Static callback forwarding methods from HAL to instance + */ +void CameraDeviceSession::sProcessCaptureResult( + const camera3_callback_ops *cb, + const camera3_capture_result *hal_result) { + CameraDeviceSession *d = + const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); + + uint32_t frameNumber = hal_result->frame_number; + bool hasInputBuf = (hal_result->input_buffer != nullptr); + size_t numOutputBufs = hal_result->num_output_buffers; + size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0); + { + Mutex::Autolock _l(d->mInflightLock); + if (hasInputBuf) { + int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId; + // validate if buffer is inflight + auto key = std::make_pair(streamId, frameNumber); + if (d->mInflightBuffers.count(key) != 1) { + ALOGE("%s: input buffer for stream %d frame %d is not inflight!", + __FUNCTION__, streamId, frameNumber); + return; + } + } + + for (size_t i = 0; i < numOutputBufs; i++) { + int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId; + // validate if buffer is inflight + auto key = std::make_pair(streamId, frameNumber); + if (d->mInflightBuffers.count(key) != 1) { + ALOGE("%s: output buffer for stream %d frame %d is not inflight!", + __FUNCTION__, streamId, frameNumber); + return; + } + } + } + // We don't need to validate/import fences here since we will be passing them to camera service + // within the scope of this function + + CaptureResult result; + hidl_vec<native_handle_t*> releaseFences; + releaseFences.resize(numBufs); + result.frameNumber = frameNumber; + result.partialResult = hal_result->partial_result; + convertToHidl(hal_result->result, &result.result); + if (hasInputBuf) { + result.inputBuffer.streamId = + static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId; + result.inputBuffer.buffer = nullptr; + result.inputBuffer.status = (BufferStatus) hal_result->input_buffer->status; + // skip acquire fence since it's no use to camera service + if (hal_result->input_buffer->release_fence != -1) { + releaseFences[numOutputBufs] = native_handle_create(/*numFds*/1, /*numInts*/0); + releaseFences[numOutputBufs]->data[0] = hal_result->input_buffer->release_fence; + result.inputBuffer.releaseFence = releaseFences[numOutputBufs]; + } else { + releaseFences[numOutputBufs] = nullptr; + } + } else { + result.inputBuffer.streamId = -1; + } + + result.outputBuffers.resize(numOutputBufs); + for (size_t i = 0; i < numOutputBufs; i++) { + result.outputBuffers[i].streamId = + static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId; + result.outputBuffers[i].buffer = nullptr; + result.outputBuffers[i].status = (BufferStatus) hal_result->output_buffers[i].status; + // skip acquire fence since it's of no use to camera service + if (hal_result->output_buffers[i].release_fence != -1) { + releaseFences[i] = native_handle_create(/*numFds*/1, /*numInts*/0); + releaseFences[i]->data[0] = hal_result->output_buffers[i].release_fence; + result.outputBuffers[i].releaseFence = releaseFences[i]; + } else { + releaseFences[i] = nullptr; + } + } + + // Free inflight record/fences. + // Do this before call back to camera service because camera service might jump to + // configure_streams right after the processCaptureResult call so we need to finish + // updating inflight queues first + { + Mutex::Autolock _l(d->mInflightLock); + if (hasInputBuf) { + int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId; + auto key = std::make_pair(streamId, frameNumber); + // TODO (b/34169301): currently HAL closed the fence + //sHandleImporter.closeFence(d->mInflightBuffers[key].acquire_fence); + d->mInflightBuffers.erase(key); + } + + for (size_t i = 0; i < numOutputBufs; i++) { + int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId; + auto key = std::make_pair(streamId, frameNumber); + // TODO (b/34169301): currently HAL closed the fence + //sHandleImporter.closeFence(d->mInflightBuffers[key].acquire_fence); + d->mInflightBuffers.erase(key); + } + + if (d->mInflightBuffers.empty()) { + ALOGV("%s: inflight buffer queue is now empty!", __FUNCTION__); + } + } + + d->mCallback->processCaptureResult(result); + + for (size_t i = 0; i < releaseFences.size(); i++) { + // We don't close the FD here as HAL needs to signal it later. + native_handle_delete(releaseFences[i]); + } +} + +void CameraDeviceSession::sNotify( + const camera3_callback_ops *cb, + const camera3_notify_msg *msg) { + CameraDeviceSession *d = + const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb)); + NotifyMsg hidlMsg; + convertToHidl(msg, &hidlMsg); + if (hidlMsg.type == (MsgType) CAMERA3_MSG_ERROR && + hidlMsg.msg.error.errorStreamId != -1) { + if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) { + ALOGE("%s: unknown stream ID %d reports an error!", + __FUNCTION__, hidlMsg.msg.error.errorStreamId); + } + return; + } + d->mCallback->notify(hidlMsg); +} + +} // namespace implementation +} // namespace V3_2 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h new file mode 100644 index 0000000..3786e4b --- /dev/null +++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H + +#include <unordered_map> +#include "hardware/camera_common.h" +#include "hardware/camera3.h" +#include "utils/Mutex.h" +#include <android/hardware/camera/device/3.2/ICameraDevice.h> +#include <android/hardware/camera/device/3.2/ICameraDeviceSession.h> +#include <hidl/Status.h> +#include <hidl/MQDescriptor.h> +#include <include/convert.h> +#include "HandleImporter.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_2 { +namespace implementation { + +using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::HalStreamConfiguration; +using ::android::hardware::camera::device::V3_2::StreamConfiguration; +using ::android::hardware::camera::device::V3_2::ICameraDeviceSession; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::helper::HandleImporter; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::Mutex; + +/** + * Function pointer types with C calling convention to + * use for HAL callback functions. + */ +extern "C" { + typedef void (callbacks_process_capture_result_t)( + const struct camera3_callback_ops *, + const camera3_capture_result_t *); + + typedef void (callbacks_notify_t)( + const struct camera3_callback_ops *, + const camera3_notify_msg_t *); +} + +struct CameraDeviceSession : public ICameraDeviceSession, private camera3_callback_ops { + + CameraDeviceSession(camera3_device_t*, const sp<ICameraDeviceCallback>&); + ~CameraDeviceSession(); + // Call by CameraDevice to dump active device states + void dumpState(const native_handle_t* fd); + // Caller must use this method to check if CameraDeviceSession ctor failed + bool isInitFailed() { return mInitFail; } + // Used by CameraDevice to signal external camera disconnected + void disconnect(); + bool isClosed(); + + // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow. + Return<void> constructDefaultRequestSettings(RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb) override; + Return<void> configureStreams(const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) override; + Return<Status> processCaptureRequest(const CaptureRequest& request) override; + Return<Status> flush() override; + Return<void> close() override; + +private: + // protecting mClosed/mDisconnected/mInitFail + mutable Mutex mStateLock; + // device is closed either + // - closed by user + // - init failed + // - camera disconnected + bool mClosed = false; + + // Set by CameraDevice (when external camera is disconnected) + bool mDisconnected = false; + + camera3_device_t* mDevice; + const sp<ICameraDeviceCallback> mCallback; + // Stream ID -> Camera3Stream cache + std::map<int, Camera3Stream> mStreamMap; + + mutable Mutex mInflightLock; // protecting mInflightBuffers and mCirculatingBuffers + // (streamID, frameNumber) -> inflight buffer cache + std::map<std::pair<int, uint32_t>, camera3_stream_buffer_t> mInflightBuffers; + + // buffers currently ciculating between HAL and camera service + // key: bufferId sent via HIDL interface + // value: imported buffer_handle_t + // Buffer will be imported during process_capture_request and will be freed + // when the its stream is deleted or camera device session is closed + typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers; + // Stream ID -> circulating buffers map + std::map<int, CirculatingBuffers> mCirculatingBuffers; + + static HandleImporter& sHandleImporter; + + bool mInitFail; + bool initialize(); + + Status initStatus() const; + + // Validate and import request's input buffer and acquire fence + Status importRequest( + const CaptureRequest& request, + hidl_vec<buffer_handle_t*>& allBufPtrs, + hidl_vec<int>& allFences); + + static void cleanupInflightFences( + hidl_vec<int>& allFences, size_t numFences); + + void cleanupBuffersLocked(int id); + + /** + * Static callback forwarding methods from HAL to instance + */ + static callbacks_process_capture_result_t sProcessCaptureResult; + static callbacks_notify_t sNotify; +}; + +} // namespace implementation +} // namespace V3_2 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
diff --git a/camera/device/3.2/default/CameraDevice_3_2.h b/camera/device/3.2/default/CameraDevice_3_2.h new file mode 100644 index 0000000..4e86067 --- /dev/null +++ b/camera/device/3.2/default/CameraDevice_3_2.h
@@ -0,0 +1,112 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H +#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H + +#include "utils/Mutex.h" +#include "CameraModule.h" +#include "CameraMetadata.h" +#include "CameraDeviceSession.h" + +#include <android/hardware/camera/device/3.2/ICameraDevice.h> +#include <hidl/Status.h> +#include <hidl/MQDescriptor.h> + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_2 { +namespace implementation { + +using ::android::hardware::camera::device::V3_2::RequestTemplate; +using ::android::hardware::camera::device::V3_2::ICameraDevice; +using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback; +using ::android::hardware::camera::device::V3_2::ICameraDeviceSession; +using ::android::hardware::camera::common::V1_0::CameraResourceCost; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::TorchMode; +using ::android::hardware::camera::common::V1_0::helper::CameraModule; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::Mutex; + +/* + * The camera device HAL implementation is opened lazily (via the open call) + */ +struct CameraDevice : public ICameraDevice { + // Called by provider HAL. Provider HAL must ensure the uniqueness of + // CameraDevice object per cameraId, or there could be multiple CameraDevice + // trying to access the same physical camera. + // Also, provider will have to keep track of all CameraDevice objects in + // order to notify CameraDevice when the underlying camera is detached + CameraDevice(sp<CameraModule> module, + const std::string& cameraId, + const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames); + ~CameraDevice(); + // Caller must use this method to check if CameraDevice ctor failed + bool isInitFailed() { return mInitFail; } + // Used by provider HAL to signal external camera disconnected + void setConnectionStatus(bool connected); + + /* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */ + // The following method can be called without opening the actual camera device + Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override; + Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override; + Return<Status> setTorchMode(TorchMode mode) override; + + // Open the device HAL and also return a default capture session + Return<void> open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) override; + + + // Forward the dump call to the opened session, or do nothing + Return<void> dumpState(const ::android::hardware::hidl_handle& fd) override; + /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */ + +private: + const sp<CameraModule> mModule; + const std::string mCameraId; + // const after ctor + int mCameraIdInt; + int mDeviceVersion; + bool mInitFail = false; + // Set by provider (when external camera is connected/disconnected) + bool mDisconnected; + wp<CameraDeviceSession> mSession = nullptr; + + const SortedVector<std::pair<std::string, std::string>>& mCameraDeviceNames; + + // gating access to mSession and mDisconnected + mutable Mutex mLock; + + // convert conventional HAL status to HIDL Status + static Status getHidlStatus(int); + + Status initStatus() const; +}; + +} // namespace implementation +} // namespace V3_2 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp new file mode 100644 index 0000000..35676df --- /dev/null +++ b/camera/device/3.2/default/convert.cpp
@@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.camera.device@3.2-convert-impl" +#include <android/log.h> + +#include "include/convert.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_2 { +namespace implementation { + +using ::android::hardware::graphics::common::V1_0::Dataspace; +using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::camera::device::V3_2::ConsumerUsageFlags; +using ::android::hardware::camera::device::V3_2::ProducerUsageFlags; + +bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst) { + if (src.size() == 0) { + // Special case for null metadata + *dst = nullptr; + return true; + } + + const uint8_t* data = src.data(); + // sanity check the size of CameraMetadata match underlying camera_metadata_t + if (get_camera_metadata_size((camera_metadata_t*)data) != src.size()) { + ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__); + return false; + } + *dst = (camera_metadata_t*) data; + return true; +} + +// Note: existing data in dst will be gone. Caller still owns the memory of src +void convertToHidl(const camera_metadata_t *src, CameraMetadata* dst) { + if (src == nullptr) { + return; + } + size_t size = get_camera_metadata_size(src); + dst->setToExternal((uint8_t *) src, size); + return; +} + +void convertFromHidl(const Stream &src, Camera3Stream* dst) { + dst->mId = src.id; + dst->stream_type = (int) src.streamType; + dst->width = src.width; + dst->height = src.height; + dst->format = (int) src.format; + dst->data_space = (android_dataspace_t) src.dataSpace; + dst->rotation = (int) src.rotation; + dst->usage = (uint32_t) src.usage; + // Fields to be filled by HAL (max_buffers, priv) are initialized to 0 + dst->max_buffers = 0; + dst->priv = 0; + return; +} + +void convertToHidl(const Camera3Stream* src, HalStream* dst) { + dst->id = src->mId; + dst->overrideFormat = (PixelFormat) src->format; + dst->maxBuffers = src->max_buffers; + if (src->stream_type == CAMERA3_STREAM_OUTPUT) { + dst->consumerUsage = (ConsumerUsageFlags) 0; + dst->producerUsage = (ProducerUsageFlags) src->usage; + } else if (src->stream_type == CAMERA3_STREAM_INPUT) { + dst->producerUsage = (ProducerUsageFlags) 0; + dst->consumerUsage = (ConsumerUsageFlags) src->usage; + } else { + //Should not reach here per current HIDL spec, but we might end up adding + // bi-directional stream to HIDL. + ALOGW("%s: Stream type %d is not currently supported!", + __FUNCTION__, src->stream_type); + } +} + +void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst) { + dst->streams.resize(src.num_streams); + for (uint32_t i = 0; i < src.num_streams; i++) { + convertToHidl(static_cast<Camera3Stream*>(src.streams[i]), &dst->streams[i]); + } + return; +} + +void convertFromHidl( + buffer_handle_t* bufPtr, BufferStatus status, camera3_stream_t* stream, int acquireFence, + camera3_stream_buffer_t* dst) { + dst->stream = stream; + dst->buffer = bufPtr; + dst->status = (int) status; + dst->acquire_fence = acquireFence; + dst->release_fence = -1; // meant for HAL to fill in +} + +void convertToHidl(const camera3_notify_msg* src, NotifyMsg* dst) { + dst->type = (MsgType) src->type; + switch (src->type) { + case CAMERA3_MSG_ERROR: + { + // The camera3_stream_t* must be the same as what wrapper HAL passed to conventional + // HAL, or the ID lookup will return garbage. Caller should validate the ID here is + // indeed one of active stream IDs + Camera3Stream* stream = static_cast<Camera3Stream*>( + src->message.error.error_stream); + dst->msg.error.frameNumber = src->message.error.frame_number; + dst->msg.error.errorStreamId = (stream != nullptr) ? stream->mId : -1; + dst->msg.error.errorCode = (ErrorCode) src->message.error.error_code; + } + break; + case CAMERA3_MSG_SHUTTER: + dst->msg.shutter.frameNumber = src->message.shutter.frame_number; + dst->msg.shutter.timestamp = src->message.shutter.timestamp; + break; + default: + ALOGE("%s: HIDL type converion failed. Unknown msg type 0x%x", + __FUNCTION__, src->type); + } + return; +} + +} // namespace implementation +} // namespace V3_2 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android
diff --git a/camera/device/3.2/default/include/convert.h b/camera/device/3.2/default/include/convert.h new file mode 100644 index 0000000..96891f0 --- /dev/null +++ b/camera/device/3.2/default/include/convert.h
@@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_ + +#define HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_ + +#include <set> + + +#include <android/hardware/graphics/common/1.0/types.h> +#include <android/hardware/camera/device/3.2/types.h> +#include "hardware/camera3.h" + +namespace android { +namespace hardware { +namespace camera { +namespace device { +namespace V3_2 { +namespace implementation { + +// The camera3_stream_t sent to conventional HAL. Added mId fields to enable stream ID lookup +// fromt a downcasted camera3_stream +struct Camera3Stream : public camera3_stream { + int mId; +}; + +// *dst will point to the data owned by src, but src still owns the data after this call returns. +bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst); +void convertToHidl(const camera_metadata_t* src, CameraMetadata* dst); + +void convertFromHidl(const Stream &src, Camera3Stream* dst); +void convertToHidl(const Camera3Stream* src, HalStream* dst); + +void convertFromHidl( + buffer_handle_t*, BufferStatus, camera3_stream_t*, int acquireFence, // inputs + camera3_stream_buffer_t* dst); + +void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst); + +// The camera3_stream_t* in src must be the same as what wrapper HAL passed to conventional +// HAL, or the ID lookup will return garbage. Caller should validate the ID in ErrorMsg is +// indeed one of active stream IDs +void convertToHidl(const camera3_notify_msg* src, NotifyMsg* dst); + +} // namespace implementation +} // namespace V3_2 +} // namespace device +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
diff --git a/camera/device/3.2/types.hal b/camera/device/3.2/types.hal new file mode 100644 index 0000000..fe1edbf --- /dev/null +++ b/camera/device/3.2/types.hal
@@ -0,0 +1,947 @@ +/* + * Copyright (C) 2016 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.camera.device@3.2; + +import android.hardware.graphics.allocator@2.0::types; +import android.hardware.graphics.common@1.0::types; + +typedef vec<uint8_t> CameraMetadata; +typedef bitfield<ProducerUsage> ProducerUsageFlags; +typedef bitfield<ConsumerUsage> ConsumerUsageFlags; +typedef bitfield<Dataspace> DataspaceFlags; + +/** + * StreamType: + * + * The type of the camera stream, which defines whether the camera HAL device is + * the producer or the consumer for that stream, and how the buffers of the + * stream relate to the other streams. + */ +enum StreamType : uint32_t { + /** + * This stream is an output stream; the camera HAL device must fill buffers + * from this stream with newly captured or reprocessed image data. + */ + OUTPUT = 0, + + /** + * This stream is an input stream; the camera HAL device must read buffers + * from this stream and send them through the camera processing pipeline, + * as if the buffer was a newly captured image from the imager. + * + * The pixel format for input stream can be any format reported by + * android.scaler.availableInputOutputFormatsMap. The pixel format of the + * output stream that is used to produce the reprocessing data may be any + * format reported by android.scaler.availableStreamConfigurations. The + * supported input/output stream combinations depends the camera device + * capabilities, see android.scaler.availableInputOutputFormatsMap for + * stream map details. + * + * This kind of stream is generally used to reprocess data into higher + * quality images (that otherwise would cause a frame rate performance + * loss), or to do off-line reprocessing. + * + * The typical use cases are OPAQUE (typically ZSL) and YUV reprocessing, + * see S8.2, S8.3 and S10 for more details. + */ + INPUT = 1 + +}; + +/** + * StreamRotation: + * + * The required counterclockwise rotation of camera stream. + */ +enum StreamRotation : uint32_t { + /* No rotation */ + ROTATION_0 = 0, + + /* Rotate by 90 degree counterclockwise */ + ROTATION_90 = 1, + + /* Rotate by 180 degree counterclockwise */ + ROTATION_180 = 2, + + /* Rotate by 270 degree counterclockwise */ + ROTATION_270 = 3 + +}; + +/** + * StreamConfigurationMode: + * + * This defines the general operation mode for the HAL (for a given stream + * configuration) where modes besides NORMAL have different semantics, and + * usually limit the generality of the API in exchange for higher performance in + * some particular area. + */ +enum StreamConfigurationMode : uint32_t { + /** + * Normal stream configuration operation mode. This is the default camera + * operation mode, where all semantics of HAL APIs and metadata controls + * apply. + */ + NORMAL_MODE = 0, + + /** + * Special constrained high speed operation mode for devices that can not + * support high speed output in NORMAL mode. All streams in this + * configuration are operating at high speed mode and have different + * characteristics and limitations to achieve high speed output. The NORMAL + * mode can still be used for high speed output if the HAL can support high + * speed output while satisfying all the semantics of HAL APIs and metadata + * controls. It is recommended for the HAL to support high speed output in + * NORMAL mode (by advertising the high speed FPS ranges in + * android.control.aeAvailableTargetFpsRanges) if possible. + * + * This mode has below limitations/requirements: + * + * 1. The HAL must support up to 2 streams with sizes reported by + * android.control.availableHighSpeedVideoConfigurations. + * 2. In this mode, the HAL is expected to output up to 120fps or + * higher. This mode must support the targeted FPS range and size + * configurations reported by + * android.control.availableHighSpeedVideoConfigurations. + * 3. The HAL must support IMPLEMENTATION_DEFINED output + * stream format. + * 4. To achieve efficient high speed streaming, the HAL may have to + * aggregate multiple frames together and send to camera device for + * processing where the request controls are same for all the frames in + * this batch (batch mode). The HAL must support max batch size and the + * max batch size requirements defined by + * android.control.availableHighSpeedVideoConfigurations. + * 5. In this mode, the HAL must override aeMode, awbMode, and afMode to + * ON, ON, and CONTINUOUS_VIDEO, respectively. All post-processing + * block mode controls must be overridden to be FAST. Therefore, no + * manual control of capture and post-processing parameters is + * possible. All other controls operate the same as when + * android.control.mode == AUTO. This means that all other + * android.control.* fields must continue to work, such as + * + * android.control.aeTargetFpsRange + * android.control.aeExposureCompensation + * android.control.aeLock + * android.control.awbLock + * android.control.effectMode + * android.control.aeRegions + * android.control.afRegions + * android.control.awbRegions + * android.control.afTrigger + * android.control.aePrecaptureTrigger + * + * Outside of android.control.*, the following controls must work: + * + * android.flash.mode (TORCH mode only, automatic flash for still + * capture must not work since aeMode is ON) + * android.lens.opticalStabilizationMode (if it is supported) + * android.scaler.cropRegion + * android.statistics.faceDetectMode (if it is supported) + * + * For more details about high speed stream requirements, see + * android.control.availableHighSpeedVideoConfigurations and + * CONSTRAINED_HIGH_SPEED_VIDEO capability defined in + * android.request.availableCapabilities. + * + * This mode only needs to be supported by HALs that include + * CONSTRAINED_HIGH_SPEED_VIDEO in the android.request.availableCapabilities + * static metadata. + */ + CONSTRAINED_HIGH_SPEED_MODE = 1, + + /** + * A set of vendor-defined operating modes, for custom default camera + * application features that can't be implemented in the fully flexible fashion + * required for NORMAL_MODE. + */ + VENDOR_MODE_0 = 0x8000, + VENDOR_MODE_1, + VENDOR_MODE_2, + VENDOR_MODE_3, + VENDOR_MODE_4, + VENDOR_MODE_5, + VENDOR_MODE_6, + VENDOR_MODE_7 +}; + +/** + * Stream: + * + * A descriptor for a single camera input or output stream. A stream is defined + * by the framework by its buffer resolution and format, and additionally by the + * HAL with the gralloc usage flags and the maximum in-flight buffer count. + * + * If a configureStreams() call returns a non-fatal error, all active streams + * remain valid as if configureStreams() had not been called. + * + */ +struct Stream { + /** + * Stream ID - a nonnegative integer identifier for a stream. + * + * The identical stream ID must reference the same stream, with the same + * width/height/format, across consecutive calls to configureStreams. + * + * If previously-used stream ID is not used in a new call to + * configureStreams, then that stream is no longer active. Such a stream ID + * may be reused in a future configureStreams with a new + * width/height/format. + * + */ + int32_t id; + + /** + * The type of the stream (input vs output, etc). + */ + StreamType streamType; + + /** + * The width in pixels of the buffers in this stream + */ + uint32_t width; + + /** + * The height in pixels of the buffers in this stream + */ + uint32_t height; + + /** + * The pixel format for the buffers in this stream. + * + * If IMPLEMENTATION_DEFINED is used, then the platform + * gralloc module must select a format based on the usage flags provided by + * the camera device and the other endpoint of the stream. + * + */ + android.hardware.graphics.common@1.0::PixelFormat format; + + /** + * The gralloc usage flags for this stream, as needed by the consumer of + * the stream. + * + * The usage flags from the producer and the consumer must be combined + * together and then passed to the platform gralloc HAL module for + * allocating the gralloc buffers for each stream. + * + * The HAL may use these consumer flags to decide stream configuration. For + * streamType INPUT, the value of this field is always 0. For all streams + * passed via configureStreams(), the HAL must set its own + * additional usage flags in its output HalStreamConfiguration. + */ + ConsumerUsageFlags usage; + + /** + * A field that describes the contents of the buffer. The format and buffer + * dimensions define the memory layout and structure of the stream buffers, + * while dataSpace defines the meaning of the data within the buffer. + * + * For most formats, dataSpace defines the color space of the image data. + * In addition, for some formats, dataSpace indicates whether image- or + * depth-based data is requested. See + * android.hardware.graphics.common@1.0::types for details of formats and + * valid dataSpace values for each format. + * + * The HAL must use this dataSpace to configure the stream to the correct + * colorspace, or to select between color and depth outputs if + * supported. The dataspace values are set using the V0 dataspace + * definitions. + */ + DataspaceFlags dataSpace; + + /** + * The required output rotation of the stream. + * + * This must be inspected by HAL along with stream width and height. For + * example, if the rotation is 90 degree and the stream width and height is + * 720 and 1280 respectively, camera service must supply buffers of size + * 720x1280, and HAL must capture a 1280x720 image and rotate the image by + * 90 degree counterclockwise. The rotation field must be ignored when the + * stream type is input. + * + * The HAL must inspect this field during stream configuration and return + * IllegalArgument if HAL cannot perform such rotation. HAL must always + * support ROTATION_0, so a configureStreams() call must not fail for + * unsupported rotation if rotation field of all streams is ROTATION_0. + * + */ + StreamRotation rotation; + +}; + +/** + * StreamConfiguration: + * + * A structure of stream definitions, used by configureStreams(). This + * structure defines all the output streams and the reprocessing input + * stream for the current camera use case. + */ +struct StreamConfiguration { + /** + * An array of camera stream pointers, defining the input/output + * configuration for the camera HAL device. + * + * At most one input-capable stream may be defined. + * At least one output-capable stream must be defined. + */ + vec<Stream> streams; + + /** + * The operation mode of streams in this configuration. The HAL can use this + * mode as an indicator to set the stream property (e.g., + * HalStream::maxBuffers) appropriately. For example, if the + * configuration is + * CONSTRAINED_HIGH_SPEED_MODE, the HAL may + * want to set aside more buffers for batch mode operation (see + * android.control.availableHighSpeedVideoConfigurations for batch mode + * definition). + * + */ + StreamConfigurationMode operationMode; + +}; + +/** + * HalStream: + * + * The camera HAL's response to each requested stream configuration. + * + * The HAL may specify the desired format, maximum buffers, and + * usage flags for each stream. + * + */ +struct HalStream { + /** + * Stream ID - a nonnegative integer identifier for a stream. + * + * The ID must be one of the stream IDs passed into configureStreams. + */ + int32_t id; + + /** + * An override pixel format for the buffers in this stream. + * + * The HAL must respect the requested format in Stream unless it is + * IMPLEMENTATION_DEFINED, in which case the override format here must be + * used by the client instead, for this stream. This allows cross-platform + * HALs to use a standard format since IMPLEMENTATION_DEFINED formats often + * require device-specific information. In all other cases, the + * overrideFormat must match the requested format. + * + * When HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED is used, then the platform + * gralloc module must select a format based on the usage flags provided by + * the camera device and the other endpoint of the stream. + */ + android.hardware.graphics.common@1.0::PixelFormat overrideFormat; + + /** + * The gralloc usage flags for this stream, as needed by the HAL. + * + * For output streams, these are the HAL's producer usage flags. For input + * streams, these are the HAL's consumer usage flags. The usage flags from + * the producer and the consumer must be combined together and then passed + * to the platform graphics allocator HAL for allocating the gralloc buffers + * for each stream. + * + * If the stream's type is INPUT, then producerUsage must be 0, and + * consumerUsage must be set. For other types, producerUsage must be set, + * and consumerUsage must be 0. + */ + ProducerUsageFlags producerUsage; + ConsumerUsageFlags consumerUsage; + + /** + * The maximum number of buffers the HAL device may need to have dequeued at + * the same time. The HAL device may not have more buffers in-flight from + * this stream than this value. + */ + uint32_t maxBuffers; + +}; + +/** + * HalStreamConfiguration: + * + * A structure of stream definitions, returned by configureStreams(). This + * structure defines the HAL's desired parameters for each stream. + * + * All streams that were defined in the input to configureStreams() must have a + * corresponding entry in this structure when returned by configureStreams(). + */ +struct HalStreamConfiguration { + vec<HalStream> streams; +}; + +/** + * BufferStatus: + * + * The current status of a single stream buffer. + */ +enum BufferStatus : uint32_t { + /** + * The buffer is in a normal state, and can be used after waiting on its + * sync fence. + */ + OK = 0, + + /** + * The buffer does not contain valid data, and the data in it must not be + * used. The sync fence must still be waited on before reusing the buffer. + */ + ERROR = 1 +}; + +/** + * StreamBuffer: + * + * A single buffer from a camera3 stream. It includes a handle to its parent + * stream, the handle to the gralloc buffer itself, and sync fences + * + * The buffer does not specify whether it is to be used for input or output; + * that is determined by its parent stream type and how the buffer is passed to + * the HAL device. + */ +struct StreamBuffer { + /** + * The ID of the stream this buffer is associated with. -1 indicates an + * invalid (empty) StreamBuffer, in which case buffer must also point to + * null and bufferId must be 0. + */ + int32_t streamId; + + /** + * The unique ID of the buffer within this StreamBuffer. 0 indicates this + * StreamBuffer contains no buffer. + * For StreamBuffers sent to the HAL in a CaptureRequest, this ID uniquely + * identifies a buffer. When a buffer is sent to HAL for the first time, + * both bufferId and buffer handle must be filled. HAL must keep track of + * the mapping between bufferId and corresponding buffer until the + * corresponding stream is removed from stream configuration or until camera + * device session is closed. After the first time a buffer is introduced to + * HAL, in the future camera service must refer to the same buffer using + * only bufferId, and keep the buffer handle null. + */ + uint64_t bufferId; + + /** + * The graphics buffer handle to the buffer. + * + * For StreamBuffers sent to the HAL in a CaptureRequest, if the bufferId + * is not seen by the HAL before, this buffer handle is guaranteed to be a + * valid handle to a graphics buffer, with dimensions and format matching + * that of the stream. If the bufferId has been sent to the HAL before, this + * buffer handle must be null and HAL must look up the actual buffer handle + * to use from its own bufferId to buffer handle map. + * + * For StreamBuffers returned in a CaptureResult, this must be null, since + * the handle to the buffer is already known to the client (since the client + * sent it in the matching CaptureRequest), and the handle can be identified + * by the combination of frame number and stream ID. + */ + handle buffer; + + /** + * Current state of the buffer. The framework must not pass buffers to the + * HAL that are in an error state. In case a buffer could not be filled by + * the HAL, it must have its status set to ERROR when returned to the + * framework with processCaptureResult(). + */ + BufferStatus status; + + /** + * The acquire sync fence for this buffer. The HAL must wait on this fence + * fd before attempting to read from or write to this buffer. + * + * In a buffer included in a CaptureRequest, the client may set this to null + * to indicate that no waiting is necessary for this buffer. + * + * When the HAL returns an input or output buffer to the framework with + * processCaptureResult(), the acquireFence must be set to null. If the HAL + * never waits on the acquireFence due to an error in filling or reading a + * buffer, when calling processCaptureResult() the HAL must set the + * releaseFence of the buffer to be the acquireFence passed to it by the + * client. This allows the client to wait on the fence before reusing the + * buffer. + */ + handle acquireFence; + + /** + * The release sync fence for this buffer. The HAL must set this to a valid + * fence fd when returning the input buffer or output buffers to the client + * in a CaptureResult, or set it to null to indicate that no waiting is + * required for this buffer. + * + * The client must set this to be null for all buffers included in a + * processCaptureRequest call. + * + * After signaling the releaseFence for this buffer, the HAL + * must not make any further attempts to access this buffer as the + * ownership has been fully transferred back to the client. + * + * If this is null, then the ownership of this buffer is transferred back + * immediately upon the call of processCaptureResult. + */ + handle releaseFence; + +}; + +/** + * CameraBlob: + * + * Transport header for camera blob types; generally compressed JPEG buffers in + * output streams. + * + * To capture JPEG images, a stream is created using the pixel format + * HAL_PIXEL_FORMAT_BLOB and dataspace HAL_DATASPACE_V0_JFIF. The buffer size + * for the stream is calculated by the framework, based on the static metadata + * field android.jpeg.maxSize. Since compressed JPEG images are of variable + * size, the HAL needs to include the final size of the compressed image using + * this structure inside the output stream buffer. The camera blob ID field must + * be set to CameraBlobId::JPEG. + * + * The transport header must be at the end of the JPEG output stream + * buffer. That means the jpegBlobId must start at byte[buffer_size - + * sizeof(CameraBlob)], where the buffer_size is the size of gralloc + * buffer. Any HAL using this transport header must account for it in + * android.jpeg.maxSize. The JPEG data itself starts at the beginning of the + * buffer and must be blobSize bytes long. + */ +enum CameraBlobId : uint16_t { + JPEG = 0x00FF, +}; + +struct CameraBlob { + CameraBlobId blobId; + + uint32_t blobSize; +}; + +/** + * MsgType: + * + * Indicates the type of message sent, which specifies which member of the + * message union is valid. + * + */ +enum MsgType : uint32_t { + /** + * An error has occurred. NotifyMsg::Message::Error contains the + * error information. + */ + ERROR = 1, + + /** + * The exposure of a given request or processing a reprocess request has + * begun. NotifyMsg::Message::Shutter contains the information + * the capture. + */ + SHUTTER = 2 +}; + +/** + * Defined error codes for MsgType::ERROR + */ +enum ErrorCode : uint32_t { + /** + * A serious failure occured. No further frames or buffer streams must + * be produced by the device. Device must be treated as closed. The + * client must reopen the device to use it again. The frameNumber field + * is unused. + */ + ERROR_DEVICE = 1, + + /** + * An error has occurred in processing a request. No output (metadata or + * buffers) must be produced for this request. The frameNumber field + * specifies which request has been dropped. Subsequent requests are + * unaffected, and the device remains operational. + */ + ERROR_REQUEST = 2, + + /** + * An error has occurred in producing an output result metadata buffer + * for a request, but output stream buffers for it must still be + * available. Subsequent requests are unaffected, and the device remains + * operational. The frameNumber field specifies the request for which + * result metadata won't be available. + */ + ERROR_RESULT = 3, + + /** + * An error has occurred in placing an output buffer into a stream for a + * request. The frame metadata and other buffers may still be + * available. Subsequent requests are unaffected, and the device remains + * operational. The frameNumber field specifies the request for which the + * buffer was dropped, and errorStreamId indicates the stream + * that dropped the frame. + */ + ERROR_BUFFER = 4, +}; + +/** + * ErrorMsg: + * + * Message contents for MsgType::ERROR + */ +struct ErrorMsg { + /** + * Frame number of the request the error applies to. 0 if the frame number + * isn't applicable to the error. + */ + uint32_t frameNumber; + + /** + * Pointer to the stream that had a failure. -1 if the stream isn't + * applicable to the error. + */ + int32_t errorStreamId; + + /** + * The code for this error. + */ + ErrorCode errorCode; + +}; + +/** + * ShutterMsg: + * + * Message contents for MsgType::SHUTTER + */ +struct ShutterMsg { + /** + * Frame number of the request that has begun exposure or reprocessing. + */ + uint32_t frameNumber; + + /** + * Timestamp for the start of capture. For a reprocess request, this must + * be input image's start of capture. This must match the capture result + * metadata's sensor exposure start timestamp. + */ + uint64_t timestamp; + +}; + +/** + * NotifyMsg: + * + * The message structure sent to ICameraDevice3Callback::notify() + */ +struct NotifyMsg { + /** + * The message type. + */ + MsgType type; + + union Message { + /** + * Error message contents. Valid if type is MsgType::ERROR + */ + ErrorMsg error; + + /** + * Shutter message contents. Valid if type is MsgType::SHUTTER + */ + ShutterMsg shutter; + } msg; + +}; + +/** + * RequestTemplate: + * + * Available template types for + * ICameraDevice::constructDefaultRequestSettings() + */ +enum RequestTemplate : uint32_t { + /** + * Standard camera preview operation with 3A on auto. + */ + PREVIEW = 1, + + /** + * Standard camera high-quality still capture with 3A and flash on auto. + */ + STILL_CAPTURE = 2, + + /** + * Standard video recording plus preview with 3A on auto, torch off. + */ + VIDEO_RECORD = 3, + + /** + * High-quality still capture while recording video. Applications typically + * include preview, video record, and full-resolution YUV or JPEG streams in + * request. Must not cause stuttering on video stream. 3A on auto. + */ + VIDEO_SNAPSHOT = 4, + + /** + * Zero-shutter-lag mode. Application typically request preview and + * full-resolution data for each frame, and reprocess it to JPEG when a + * still image is requested by user. Settings must provide highest-quality + * full-resolution images without compromising preview frame rate. 3A on + * auto. + */ + ZERO_SHUTTER_LAG = 5, + + /** + * A basic template for direct application control of capture + * parameters. All automatic control is disabled (auto-exposure, auto-white + * balance, auto-focus), and post-processing parameters are set to preview + * quality. The manual capture parameters (exposure, sensitivity, etc.) + * are set to reasonable defaults, but may be overridden by the + * application depending on the intended use case. + */ + MANUAL = 6, + + /** + * First value for vendor-defined request templates + */ + VENDOR_TEMPLATE_START = 0x40000000, + +}; + +/** + * CaptureRequest: + * + * A single request for image capture/buffer reprocessing, sent to the Camera + * HAL device by the framework in processCaptureRequest(). + * + * The request contains the settings to be used for this capture, and the set of + * output buffers to write the resulting image data in. It may optionally + * contain an input buffer, in which case the request is for reprocessing that + * input buffer instead of capturing a new image with the camera sensor. The + * capture is identified by the frameNumber. + * + * In response, the camera HAL device must send a CaptureResult + * structure asynchronously to the framework, using the processCaptureResult() + * callback. + */ +struct CaptureRequest { + /** + * The frame number is an incrementing integer set by the framework to + * uniquely identify this capture. It needs to be returned in the result + * call, and is also used to identify the request in asynchronous + * notifications sent to ICameraDevice3Callback::notify(). + */ + uint32_t frameNumber; + + /** + * The settings buffer contains the capture and processing parameters for + * the request. As a special case, an empty settings buffer indicates that + * the settings are identical to the most-recently submitted capture + * request. A empty buffer cannot be used as the first submitted request + * after a configureStreams() call. + */ + CameraMetadata settings; + + /** + * The input stream buffer to use for this request, if any. + * + * An invalid inputBuffer is signified by a null inputBuffer::buffer, in + * which case the value of all other members of inputBuffer must be ignored. + * + * If inputBuffer is invalid, then the request is for a new capture from the + * imager. If inputBuffer is valid, the request is for reprocessing the + * image contained in inputBuffer, and the HAL must release the inputBuffer + * back to the client in a subsequent processCaptureResult call. + * + * The HAL is required to wait on the acquire sync fence of the input buffer + * before accessing it. + * + */ + StreamBuffer inputBuffer; + + /** + * An array of at least 1 stream buffers, to be filled with image + * data from this capture/reprocess. The HAL must wait on the acquire fences + * of each stream buffer before writing to them. + * + * The HAL takes ownership of the handles in outputBuffers; the client + * must not access them until they are returned in a CaptureResult. + * + * Any or all of the buffers included here may be brand new in this + * request (having never before seen by the HAL). + */ + vec<StreamBuffer> outputBuffers; + +}; + +/** + * CaptureResult: + * + * The result of a single capture/reprocess by the camera HAL device. This is + * sent to the framework asynchronously with processCaptureResult(), in + * response to a single capture request sent to the HAL with + * processCaptureRequest(). Multiple processCaptureResult() calls may be + * performed by the HAL for each request. + * + * Each call, all with the same frame + * number, may contain some subset of the output buffers, and/or the result + * metadata. + * + * The result structure contains the output metadata from this capture, and the + * set of output buffers that have been/will be filled for this capture. Each + * output buffer may come with a release sync fence that the framework must wait + * on before reading, in case the buffer has not yet been filled by the HAL. + * + * The metadata may be provided multiple times for a single frame number. The + * framework must accumulate together the final result set by combining each + * partial result together into the total result set. + * + * If an input buffer is given in a request, the HAL must return it in one of + * the processCaptureResult calls, and the call may be to just return the + * input buffer, without metadata and output buffers; the sync fences must be + * handled the same way they are done for output buffers. + * + * Performance considerations: + * + * Applications receive these partial results immediately, so sending partial + * results is a highly recommended performance optimization to avoid the total + * pipeline latency before sending the results for what is known very early on + * in the pipeline. + * + * A typical use case might be calculating the AF state halfway through the + * pipeline; by sending the state back to the framework immediately, we get a + * 50% performance increase and perceived responsiveness of the auto-focus. + * + */ +struct CaptureResult { + /** + * The frame number is an incrementing integer set by the framework in the + * submitted request to uniquely identify this capture. It is also used to + * identify the request in asynchronous notifications sent to + * ICameraDevice3Callback::notify(). + */ + uint32_t frameNumber; + + /** + * The result metadata for this capture. This contains information about the + * final capture parameters, the state of the capture and post-processing + * hardware, the state of the 3A algorithms, if enabled, and the output of + * any enabled statistics units. + * + * If there was an error producing the result metadata, result must be an + * empty metadata buffer, and notify() must be called with + * ErrorCode::ERROR_RESULT. + * + * Multiple calls to processCaptureResult() with a given frameNumber + * may include (partial) result metadata. + * + * Partial metadata submitted must not include any metadata key returned + * in a previous partial result for a given frame. Each new partial result + * for that frame must also set a distinct partialResult value. + * + * If notify has been called with ErrorCode::ERROR_RESULT, all further + * partial results for that frame are ignored by the framework. + */ + CameraMetadata result; + + /** + * The completed output stream buffers for this capture. + * + * They may not yet be filled at the time the HAL calls + * processCaptureResult(); the framework must wait on the release sync + * fences provided by the HAL before reading the buffers. + * + * The StreamBuffer::buffer handle must be null for all returned buffers; + * the client must cache the handle and look it up via the combination of + * frame number and stream ID. + * + * The number of output buffers returned must be less than or equal to the + * matching capture request's count. If this is less than the buffer count + * in the capture request, at least one more call to processCaptureResult + * with the same frameNumber must be made, to return the remaining output + * buffers to the framework. This may only be zero if the structure includes + * valid result metadata or an input buffer is returned in this result. + * + * The HAL must set the stream buffer's release sync fence to a valid sync + * fd, or to null if the buffer has already been filled. + * + * If the HAL encounters an error while processing the buffer, and the + * buffer is not filled, the buffer's status field must be set to ERROR. If + * the HAL did not wait on the acquire fence before encountering the error, + * the acquire fence must be copied into the release fence, to allow the + * framework to wait on the fence before reusing the buffer. + * + * The acquire fence must be set to null for all output buffers. + * + * This vector may be empty; if so, at least one other processCaptureResult + * call must be made (or have been made) by the HAL to provide the filled + * output buffers. + * + * When processCaptureResult is called with a new buffer for a frame, + * all previous frames' buffers for that corresponding stream must have been + * already delivered (the fences need not have yet been signaled). + * + * Buffers for a frame may be sent to framework before the corresponding + * SHUTTER-notify call is made by the HAL. + * + * Performance considerations: + * + * Buffers delivered to the framework are not dispatched to the + * application layer until a start of exposure timestamp has been received + * via a SHUTTER notify() call. It is highly recommended to + * dispatch that call as early as possible. + */ + vec<StreamBuffer> outputBuffers; + + /** + * The handle for the input stream buffer for this capture, if any. + * + * It may not yet be consumed at the time the HAL calls + * processCaptureResult(); the framework must wait on the release sync fence + * provided by the HAL before reusing the buffer. + * + * The HAL must handle the sync fences the same way they are done for + * outputBuffers. + * + * Only one input buffer is allowed to be sent per request. Similarly to + * output buffers, the ordering of returned input buffers must be + * maintained by the HAL. + * + * Performance considerations: + * + * The input buffer should be returned as early as possible. If the HAL + * supports sync fences, it can call processCaptureResult to hand it back + * with sync fences being set appropriately. If the sync fences are not + * supported, the buffer can only be returned when it is consumed, which + * may take long time; the HAL may choose to copy this input buffer to make + * the buffer return sooner. + */ + StreamBuffer inputBuffer; + + /** + * In order to take advantage of partial results, the HAL must set the + * static metadata android.request.partialResultCount to the number of + * partial results it sends for each frame. + * + * Each new capture result with a partial result must set + * this field to a distinct inclusive value between + * 1 and android.request.partialResultCount. + * + * HALs not wishing to take advantage of this feature must not + * set an android.request.partialResultCount or partial_result to a value + * other than 1. + * + * This value must be set to 0 when a capture result contains buffers only + * and no metadata. + */ + uint32_t partialResult; + +};
diff --git a/camera/device/README.md b/camera/device/README.md new file mode 100644 index 0000000..6e5703a --- /dev/null +++ b/camera/device/README.md
@@ -0,0 +1,76 @@ +## Camera Device HAL ## +--- + +## Overview: ## + +The camera.device HAL interface is used by the Android camera service to operate +individual camera devices. Instances of camera.device HAL interface can be obtained +via one of the ICameraProvider::getCameraDeviceInterface_V<N>_x() methods, where N +is the major version of the camera device interface. + +Obtaining the device interface does not turn on the respective camera device; +each camera device interface has an actual open() method to begin an active +camera session. Without invoking open(), the interface can be used for querying +camera static information. + +More complete information about the Android camera HAL and subsystem can be found at +[source.android.com](http://source.android.com/devices/camera/index.html). + +## Version history: ## + +### ICameraDevice.hal@1.0: + +HIDL version of the legacy camera device HAL. Intended as a shim for devices +needing to use the deprecated pre-HIDL camera device HAL v1.0. + +May be used in HIDL passthrough mode for devices upgrading to the Android O +release; must be used in binderized mode for devices launching in the O release. + +It is strongly recommended to not use this interface for new devices, as new +devices may not use this interface starting with the Android P release, and all +support for ICameraDevice@1.0 will be removed with the Android R release. + +This HAL interface version only allows support at the LEGACY level for the +android.hardware.camera2 API. + +Subsidiary HALs: + +#### ICameraDevice1PreviewCallback.hal@1.0: + +Callback interface for obtaining, filling, and returning graphics buffers for +preview operation with the ICameraDevice@1.0 inteface. + +#### ICameraDevice1Callback.hal@1.0: + +Callback interface for sending events and data buffers from the HAL to the +camera service. + +### ICameraDevice.hal@3.2: + +HIDL version of the baseline camera device HAL, required for LIMITED or FULL +operation through the android.hardware.camera2 API. + +The main HAL contains methods for static queries about the device, similar to +the HALv3-specific sections of the legacy camera module HAL. Simply obtaining an +instance of the camera device interface does not turn on the camera device. + +May be used in passthrough mode for devices upgrading to the Android O release; +must be used in binderized mode for all new devices launching with Android O or +later. + +The open() method actually opens the camera device for use, returning a Session +interface for operating the active camera. It takes a Callback interface as an +argument. + +Subsidiary HALs: + +#### ICameraDevice3Session.hal@3.2: + +Closely matches the features and operation of the pre-HIDL camera device HAL +v3.2, containing methods for configuring an active camera device and submitting +capture requests to it. + +#### ICameraDevice3Callback.hal@3.2: + +Callback interface for sending completed captures and other asynchronous events +from tehe HAL to the client.
diff --git a/camera/metadata/3.2/Android.bp b/camera/metadata/3.2/Android.bp new file mode 100644 index 0000000..1e464d6 --- /dev/null +++ b/camera/metadata/3.2/Android.bp
@@ -0,0 +1,53 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.camera.metadata@3.2_hal", + srcs: [ + "types.hal", + ], +} + +genrule { + name: "android.hardware.camera.metadata@3.2_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.metadata@3.2", + srcs: [ + ":android.hardware.camera.metadata@3.2_hal", + ], + out: [ + "android/hardware/camera/metadata/3.2/types.cpp", + ], +} + +genrule { + name: "android.hardware.camera.metadata@3.2_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.metadata@3.2", + srcs: [ + ":android.hardware.camera.metadata@3.2_hal", + ], + out: [ + "android/hardware/camera/metadata/3.2/types.h", + ], +} + +cc_library_shared { + name: "android.hardware.camera.metadata@3.2", + generated_sources: ["android.hardware.camera.metadata@3.2_genc++"], + generated_headers: ["android.hardware.camera.metadata@3.2_genc++_headers"], + export_generated_headers: ["android.hardware.camera.metadata@3.2_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + ], +}
diff --git a/camera/metadata/3.2/Android.mk b/camera/metadata/3.2/Android.mk new file mode 100644 index 0000000..86cee91 --- /dev/null +++ b/camera/metadata/3.2/Android.mk
@@ -0,0 +1,2462 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.camera.metadata@3.2-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +# +# Build types.hal (CameraMetadataEnumAndroidBlackLevelLock) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidBlackLevelLock.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidBlackLevelLock + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidColorCorrectionAberrationMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidColorCorrectionAberrationMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidColorCorrectionAberrationMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidColorCorrectionMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidColorCorrectionMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidColorCorrectionMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeAntibandingMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeAntibandingMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeAntibandingMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeLock) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeLock.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeLock + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeLockAvailable) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeLockAvailable.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeLockAvailable + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAePrecaptureTrigger) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAePrecaptureTrigger.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAePrecaptureTrigger + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAfMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAfState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAfTrigger) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfTrigger.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfTrigger + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAwbLock) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbLock.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbLock + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAwbLockAvailable) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbLockAvailable.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbLockAvailable + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAwbMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAwbState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlCaptureIntent) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlCaptureIntent.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlCaptureIntent + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlEffectMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlEffectMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlEffectMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlEnableZsl) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlEnableZsl.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlEnableZsl + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlSceneMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlSceneMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlSceneMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlVideoStabilizationMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlVideoStabilizationMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlVideoStabilizationMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidDemosaicMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDemosaicMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDemosaicMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidDepthDepthIsExclusive) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDepthDepthIsExclusive.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDepthDepthIsExclusive + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidEdgeMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidEdgeMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidEdgeMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidFlashInfoAvailable) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashInfoAvailable.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashInfoAvailable + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidFlashMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidFlashState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidHotPixelMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidHotPixelMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidHotPixelMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidInfoSupportedHardwareLevel) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidInfoSupportedHardwareLevel.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidInfoSupportedHardwareLevel + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLedAvailableLeds) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLedAvailableLeds.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLedAvailableLeds + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLedTransmit) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLedTransmit.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLedTransmit + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLensFacing) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensFacing.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensFacing + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLensOpticalStabilizationMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensOpticalStabilizationMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensOpticalStabilizationMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLensState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidNoiseReductionMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidNoiseReductionMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidNoiseReductionMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidQuirksPartialResult) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidQuirksPartialResult.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidQuirksPartialResult + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidRequestAvailableCapabilities) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestAvailableCapabilities.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestAvailableCapabilities + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidRequestMetadataMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestMetadataMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestMetadataMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidRequestType) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidScalerAvailableFormats) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerAvailableFormats.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerAvailableFormats + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidScalerAvailableStreamConfigurations) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerAvailableStreamConfigurations.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerAvailableStreamConfigurations + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidScalerCroppingType) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerCroppingType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerCroppingType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorInfoColorFilterArrangement) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoColorFilterArrangement.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoColorFilterArrangement + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorInfoLensShadingApplied) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoLensShadingApplied.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoLensShadingApplied + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorInfoTimestampSource) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoTimestampSource.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoTimestampSource + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorReferenceIlluminant1) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorReferenceIlluminant1.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorReferenceIlluminant1 + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorTestPatternMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorTestPatternMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorTestPatternMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidShadingMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidShadingMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidShadingMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsFaceDetectMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsFaceDetectMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsFaceDetectMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsHistogramMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsHistogramMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsHistogramMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsHotPixelMapMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsHotPixelMapMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsHotPixelMapMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsLensShadingMapMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsLensShadingMapMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsLensShadingMapMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsSceneFlicker) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsSceneFlicker.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsSceneFlicker + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsSharpnessMapMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsSharpnessMapMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsSharpnessMapMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSyncFrameNumber) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSyncFrameNumber.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSyncFrameNumber + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSyncMaxLatency) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSyncMaxLatency.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSyncMaxLatency + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidTonemapMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidTonemapMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidTonemapMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidTonemapPresetCurve) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidTonemapPresetCurve.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidTonemapPresetCurve + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataSection) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataSection.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataSection + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataSectionStart) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataSectionStart.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataSectionStart + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataTag) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataTag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataTag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.camera.metadata@3.2-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +# +# Build types.hal (CameraMetadataEnumAndroidBlackLevelLock) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidBlackLevelLock.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidBlackLevelLock + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidColorCorrectionAberrationMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidColorCorrectionAberrationMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidColorCorrectionAberrationMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidColorCorrectionMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidColorCorrectionMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidColorCorrectionMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeAntibandingMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeAntibandingMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeAntibandingMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeLock) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeLock.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeLock + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeLockAvailable) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeLockAvailable.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeLockAvailable + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAePrecaptureTrigger) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAePrecaptureTrigger.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAePrecaptureTrigger + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAeState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAeState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAeState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAfMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAfState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAfTrigger) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAfTrigger.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAfTrigger + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAwbLock) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbLock.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbLock + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAwbLockAvailable) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbLockAvailable.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbLockAvailable + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAwbMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlAwbState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlAwbState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlAwbState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlCaptureIntent) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlCaptureIntent.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlCaptureIntent + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlEffectMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlEffectMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlEffectMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlEnableZsl) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlEnableZsl.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlEnableZsl + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlSceneMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlSceneMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlSceneMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidControlVideoStabilizationMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidControlVideoStabilizationMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidControlVideoStabilizationMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidDemosaicMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDemosaicMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDemosaicMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidDepthDepthIsExclusive) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidDepthDepthIsExclusive.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidDepthDepthIsExclusive + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidEdgeMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidEdgeMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidEdgeMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidFlashInfoAvailable) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashInfoAvailable.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashInfoAvailable + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidFlashMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidFlashState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidFlashState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidFlashState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidHotPixelMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidHotPixelMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidHotPixelMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidInfoSupportedHardwareLevel) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidInfoSupportedHardwareLevel.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidInfoSupportedHardwareLevel + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLedAvailableLeds) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLedAvailableLeds.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLedAvailableLeds + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLedTransmit) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLedTransmit.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLedTransmit + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLensFacing) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensFacing.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensFacing + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLensOpticalStabilizationMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensOpticalStabilizationMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensOpticalStabilizationMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidLensState) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidLensState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidLensState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidNoiseReductionMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidNoiseReductionMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidNoiseReductionMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidQuirksPartialResult) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidQuirksPartialResult.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidQuirksPartialResult + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidRequestAvailableCapabilities) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestAvailableCapabilities.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestAvailableCapabilities + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidRequestMetadataMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestMetadataMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestMetadataMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidRequestType) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidRequestType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidRequestType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidScalerAvailableFormats) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerAvailableFormats.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerAvailableFormats + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidScalerAvailableStreamConfigurations) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerAvailableStreamConfigurations.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerAvailableStreamConfigurations + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidScalerCroppingType) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidScalerCroppingType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidScalerCroppingType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorInfoColorFilterArrangement) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoColorFilterArrangement.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoColorFilterArrangement + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorInfoLensShadingApplied) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoLensShadingApplied.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoLensShadingApplied + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorInfoTimestampSource) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorInfoTimestampSource.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorInfoTimestampSource + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorReferenceIlluminant1) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorReferenceIlluminant1.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorReferenceIlluminant1 + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSensorTestPatternMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSensorTestPatternMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSensorTestPatternMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidShadingMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidShadingMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidShadingMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsFaceDetectMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsFaceDetectMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsFaceDetectMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsHistogramMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsHistogramMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsHistogramMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsHotPixelMapMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsHotPixelMapMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsHotPixelMapMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsLensShadingMapMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsLensShadingMapMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsLensShadingMapMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsSceneFlicker) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsSceneFlicker.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsSceneFlicker + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidStatisticsSharpnessMapMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidStatisticsSharpnessMapMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidStatisticsSharpnessMapMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSyncFrameNumber) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSyncFrameNumber.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSyncFrameNumber + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidSyncMaxLatency) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidSyncMaxLatency.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidSyncMaxLatency + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidTonemapMode) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidTonemapMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidTonemapMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataEnumAndroidTonemapPresetCurve) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataEnumAndroidTonemapPresetCurve.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataEnumAndroidTonemapPresetCurve + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataSection) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataSection.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataSection + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataSectionStart) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataSectionStart.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataSectionStart + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CameraMetadataTag) +# +GEN := $(intermediates)/android/hardware/camera/metadata/V3_2/CameraMetadataTag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.camera.metadata@3.2::types.CameraMetadataTag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/camera/metadata/3.2/docs.html b/camera/metadata/3.2/docs.html new file mode 100644 index 0000000..004ecae --- /dev/null +++ b/camera/metadata/3.2/docs.html
@@ -0,0 +1,27340 @@ +<!DOCTYPE html> +<html> +<!-- Copyright (C) 2012 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. +--> +<head> + <!-- automatically generated from html.mako. do NOT edit directly --> + <meta charset="utf-8" /> + <title>Android Camera HAL3.4 Properties</title> + <style type="text/css"> + body { background-color: #f7f7f7; font-family: Roboto, sans-serif;} + h1 { color: #333333; } + h2 { color: #333333; } + a:link { color: #258aaf; text-decoration: none} + a:hover { color: #459aaf; text-decoration: underline } + a:visited { color: #154a5f; text-decoration: none} + .section { color: #eeeeee; font-size: 1.5em; font-weight: bold; background-color: #888888; padding: 0.5em 0em 0.5em 0.5em; border-width: thick thin thin thin; border-color: #111111 #777777 #777777 #777777} + .kind { color: #eeeeee; font-size: 1.2em; font-weight: bold; padding-left: 1.5em; background-color: #aaaaaa } + .entry { background-color: #f0f0f0 } + .entry_cont { background-color: #f0f0f0 } + .entries_header { background-color: #dddddd; text-align: center} + + /* toc style */ + .toc_section_header { font-size:1.3em; } + .toc_kind_header { font-size:1.2em; } + .toc_deprecated { text-decoration:line-through; } + + /* table column sizes */ + table { border-collapse:collapse; table-layout: fixed; width: 100%; word-wrap: break-word } + td,th { border: 1px solid; border-color: #aaaaaa; padding-left: 0.5em; padding-right: 0.5em } + .th_name { width: 20% } + .th_units { width: 10% } + .th_tags { width: 5% } + .th_details { width: 25% } + .th_type { width: 20% } + .th_description { width: 20% } + .th_range { width: 10% } + td { font-size: 0.9em; } + + /* hide the first thead, we need it there only to enforce column sizes */ + .thead_dummy { visibility: hidden; } + + /* Entry flair */ + .entry_name { color: #333333; padding-left:1.0em; font-size:1.1em; font-family: monospace; vertical-align:top; } + .entry_name_deprecated { text-decoration:line-through; } + + /* Entry type flair */ + .entry_type_name { font-size:1.1em; color: #669900; font-weight: bold;} + .entry_type_name_enum:after { color: #669900; font-weight: bold; content:" (enum)" } + .entry_type_visibility { font-weight: bolder; padding-left:1em} + .entry_type_synthetic { font-weight: bolder; color: #996600; } + .entry_type_hwlevel { font-weight: bolder; color: #000066; } + .entry_type_deprecated { font-weight: bolder; color: #4D4D4D; } + .entry_type_enum_name { font-family: monospace; font-weight: bolder; } + .entry_type_enum_notes:before { content:" - " } + .entry_type_enum_notes>p:first-child { display:inline; } + .entry_type_enum_value:before { content:" = " } + .entry_type_enum_value { font-family: monospace; } + .entry ul { margin: 0 0 0 0; list-style-position: inside; padding-left: 0.5em; } + .entry ul li { padding: 0 0 0 0; margin: 0 0 0 0;} + .entry_range_deprecated { font-weight: bolder; } + + /* Entry tags flair */ + .entry_tags ul { list-style-type: none; } + + /* Entry details (full docs) flair */ + .entry_details_header { font-weight: bold; background-color: #dddddd; + text-align: center; font-size: 1.1em; margin-left: 0em; margin-right: 0em; } + + /* Entry spacer flair */ + .entry_spacer { background-color: transparent; border-style: none; height: 0.5em; } + + /* TODO: generate abbr element for each tag link? */ + /* TODO for each x.y.z try to link it to the entry */ + + </style> + + <style> + + { + /* broken... + supposedly there is a bug in chrome that it lays out tables before + it knows its being printed, so the page-break-* styles are ignored + */ + tr { page-break-after: always; page-break-inside: avoid; } + } + + </style> +</head> + + + +<body> + <h1>Android Camera HAL3.2 Properties</h1> + + + <h2>Table of Contents</h2> + <ul class="toc"> + <li><a href="#tag_index" class="toc_section_header">Tags</a></li> + <li> + <span class="toc_section_header"><a href="#section_colorCorrection">colorCorrection</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.colorCorrection.mode">android.colorCorrection.mode</a></li> + <li + ><a href="#controls_android.colorCorrection.transform">android.colorCorrection.transform</a></li> + <li + ><a href="#controls_android.colorCorrection.gains">android.colorCorrection.gains</a></li> + <li + ><a href="#controls_android.colorCorrection.aberrationMode">android.colorCorrection.aberrationMode</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.colorCorrection.mode">android.colorCorrection.mode</a></li> + <li + ><a href="#dynamic_android.colorCorrection.transform">android.colorCorrection.transform</a></li> + <li + ><a href="#dynamic_android.colorCorrection.gains">android.colorCorrection.gains</a></li> + <li + ><a href="#dynamic_android.colorCorrection.aberrationMode">android.colorCorrection.aberrationMode</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.colorCorrection.availableAberrationModes">android.colorCorrection.availableAberrationModes</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_control">control</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.control.aeAntibandingMode">android.control.aeAntibandingMode</a></li> + <li + ><a href="#controls_android.control.aeExposureCompensation">android.control.aeExposureCompensation</a></li> + <li + ><a href="#controls_android.control.aeLock">android.control.aeLock</a></li> + <li + ><a href="#controls_android.control.aeMode">android.control.aeMode</a></li> + <li + ><a href="#controls_android.control.aeRegions">android.control.aeRegions</a></li> + <li + ><a href="#controls_android.control.aeTargetFpsRange">android.control.aeTargetFpsRange</a></li> + <li + ><a href="#controls_android.control.aePrecaptureTrigger">android.control.aePrecaptureTrigger</a></li> + <li + ><a href="#controls_android.control.afMode">android.control.afMode</a></li> + <li + ><a href="#controls_android.control.afRegions">android.control.afRegions</a></li> + <li + ><a href="#controls_android.control.afTrigger">android.control.afTrigger</a></li> + <li + ><a href="#controls_android.control.awbLock">android.control.awbLock</a></li> + <li + ><a href="#controls_android.control.awbMode">android.control.awbMode</a></li> + <li + ><a href="#controls_android.control.awbRegions">android.control.awbRegions</a></li> + <li + ><a href="#controls_android.control.captureIntent">android.control.captureIntent</a></li> + <li + ><a href="#controls_android.control.effectMode">android.control.effectMode</a></li> + <li + ><a href="#controls_android.control.mode">android.control.mode</a></li> + <li + ><a href="#controls_android.control.sceneMode">android.control.sceneMode</a></li> + <li + ><a href="#controls_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a></li> + <li + ><a href="#controls_android.control.postRawSensitivityBoost">android.control.postRawSensitivityBoost</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.control.aeAvailableAntibandingModes">android.control.aeAvailableAntibandingModes</a></li> + <li + ><a href="#static_android.control.aeAvailableModes">android.control.aeAvailableModes</a></li> + <li + ><a href="#static_android.control.aeAvailableTargetFpsRanges">android.control.aeAvailableTargetFpsRanges</a></li> + <li + ><a href="#static_android.control.aeCompensationRange">android.control.aeCompensationRange</a></li> + <li + ><a href="#static_android.control.aeCompensationStep">android.control.aeCompensationStep</a></li> + <li + ><a href="#static_android.control.afAvailableModes">android.control.afAvailableModes</a></li> + <li + ><a href="#static_android.control.availableEffects">android.control.availableEffects</a></li> + <li + ><a href="#static_android.control.availableSceneModes">android.control.availableSceneModes</a></li> + <li + ><a href="#static_android.control.availableVideoStabilizationModes">android.control.availableVideoStabilizationModes</a></li> + <li + ><a href="#static_android.control.awbAvailableModes">android.control.awbAvailableModes</a></li> + <li + ><a href="#static_android.control.maxRegions">android.control.maxRegions</a></li> + <li + ><a href="#static_android.control.maxRegionsAe">android.control.maxRegionsAe</a></li> + <li + ><a href="#static_android.control.maxRegionsAwb">android.control.maxRegionsAwb</a></li> + <li + ><a href="#static_android.control.maxRegionsAf">android.control.maxRegionsAf</a></li> + <li + ><a href="#static_android.control.sceneModeOverrides">android.control.sceneModeOverrides</a></li> + <li + ><a href="#static_android.control.availableHighSpeedVideoConfigurations">android.control.availableHighSpeedVideoConfigurations</a></li> + <li + ><a href="#static_android.control.aeLockAvailable">android.control.aeLockAvailable</a></li> + <li + ><a href="#static_android.control.awbLockAvailable">android.control.awbLockAvailable</a></li> + <li + ><a href="#static_android.control.availableModes">android.control.availableModes</a></li> + <li + ><a href="#static_android.control.postRawSensitivityBoostRange">android.control.postRawSensitivityBoostRange</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + class="toc_deprecated" + ><a href="#dynamic_android.control.aePrecaptureId">android.control.aePrecaptureId</a></li> + <li + ><a href="#dynamic_android.control.aeAntibandingMode">android.control.aeAntibandingMode</a></li> + <li + ><a href="#dynamic_android.control.aeExposureCompensation">android.control.aeExposureCompensation</a></li> + <li + ><a href="#dynamic_android.control.aeLock">android.control.aeLock</a></li> + <li + ><a href="#dynamic_android.control.aeMode">android.control.aeMode</a></li> + <li + ><a href="#dynamic_android.control.aeRegions">android.control.aeRegions</a></li> + <li + ><a href="#dynamic_android.control.aeTargetFpsRange">android.control.aeTargetFpsRange</a></li> + <li + ><a href="#dynamic_android.control.aePrecaptureTrigger">android.control.aePrecaptureTrigger</a></li> + <li + ><a href="#dynamic_android.control.aeState">android.control.aeState</a></li> + <li + ><a href="#dynamic_android.control.afMode">android.control.afMode</a></li> + <li + ><a href="#dynamic_android.control.afRegions">android.control.afRegions</a></li> + <li + ><a href="#dynamic_android.control.afTrigger">android.control.afTrigger</a></li> + <li + ><a href="#dynamic_android.control.afState">android.control.afState</a></li> + <li + class="toc_deprecated" + ><a href="#dynamic_android.control.afTriggerId">android.control.afTriggerId</a></li> + <li + ><a href="#dynamic_android.control.awbLock">android.control.awbLock</a></li> + <li + ><a href="#dynamic_android.control.awbMode">android.control.awbMode</a></li> + <li + ><a href="#dynamic_android.control.awbRegions">android.control.awbRegions</a></li> + <li + ><a href="#dynamic_android.control.captureIntent">android.control.captureIntent</a></li> + <li + ><a href="#dynamic_android.control.awbState">android.control.awbState</a></li> + <li + ><a href="#dynamic_android.control.effectMode">android.control.effectMode</a></li> + <li + ><a href="#dynamic_android.control.mode">android.control.mode</a></li> + <li + ><a href="#dynamic_android.control.sceneMode">android.control.sceneMode</a></li> + <li + ><a href="#dynamic_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a></li> + <li + ><a href="#dynamic_android.control.postRawSensitivityBoost">android.control.postRawSensitivityBoost</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_demosaic">demosaic</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.demosaic.mode">android.demosaic.mode</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_edge">edge</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.edge.mode">android.edge.mode</a></li> + <li + ><a href="#controls_android.edge.strength">android.edge.strength</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.edge.availableEdgeModes">android.edge.availableEdgeModes</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.edge.mode">android.edge.mode</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_flash">flash</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.flash.firingPower">android.flash.firingPower</a></li> + <li + ><a href="#controls_android.flash.firingTime">android.flash.firingTime</a></li> + <li + ><a href="#controls_android.flash.mode">android.flash.mode</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + + <li + ><a href="#static_android.flash.info.available">android.flash.info.available</a></li> + <li + ><a href="#static_android.flash.info.chargeDuration">android.flash.info.chargeDuration</a></li> + + <li + ><a href="#static_android.flash.colorTemperature">android.flash.colorTemperature</a></li> + <li + ><a href="#static_android.flash.maxEnergy">android.flash.maxEnergy</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.flash.firingPower">android.flash.firingPower</a></li> + <li + ><a href="#dynamic_android.flash.firingTime">android.flash.firingTime</a></li> + <li + ><a href="#dynamic_android.flash.mode">android.flash.mode</a></li> + <li + ><a href="#dynamic_android.flash.state">android.flash.state</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_hotPixel">hotPixel</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.hotPixel.mode">android.hotPixel.mode</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.hotPixel.availableHotPixelModes">android.hotPixel.availableHotPixelModes</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.hotPixel.mode">android.hotPixel.mode</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_jpeg">jpeg</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.jpeg.gpsLocation">android.jpeg.gpsLocation</a></li> + <li + ><a href="#controls_android.jpeg.gpsCoordinates">android.jpeg.gpsCoordinates</a></li> + <li + ><a href="#controls_android.jpeg.gpsProcessingMethod">android.jpeg.gpsProcessingMethod</a></li> + <li + ><a href="#controls_android.jpeg.gpsTimestamp">android.jpeg.gpsTimestamp</a></li> + <li + ><a href="#controls_android.jpeg.orientation">android.jpeg.orientation</a></li> + <li + ><a href="#controls_android.jpeg.quality">android.jpeg.quality</a></li> + <li + ><a href="#controls_android.jpeg.thumbnailQuality">android.jpeg.thumbnailQuality</a></li> + <li + ><a href="#controls_android.jpeg.thumbnailSize">android.jpeg.thumbnailSize</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.jpeg.availableThumbnailSizes">android.jpeg.availableThumbnailSizes</a></li> + <li + ><a href="#static_android.jpeg.maxSize">android.jpeg.maxSize</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.jpeg.gpsLocation">android.jpeg.gpsLocation</a></li> + <li + ><a href="#dynamic_android.jpeg.gpsCoordinates">android.jpeg.gpsCoordinates</a></li> + <li + ><a href="#dynamic_android.jpeg.gpsProcessingMethod">android.jpeg.gpsProcessingMethod</a></li> + <li + ><a href="#dynamic_android.jpeg.gpsTimestamp">android.jpeg.gpsTimestamp</a></li> + <li + ><a href="#dynamic_android.jpeg.orientation">android.jpeg.orientation</a></li> + <li + ><a href="#dynamic_android.jpeg.quality">android.jpeg.quality</a></li> + <li + ><a href="#dynamic_android.jpeg.size">android.jpeg.size</a></li> + <li + ><a href="#dynamic_android.jpeg.thumbnailQuality">android.jpeg.thumbnailQuality</a></li> + <li + ><a href="#dynamic_android.jpeg.thumbnailSize">android.jpeg.thumbnailSize</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_lens">lens</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.lens.aperture">android.lens.aperture</a></li> + <li + ><a href="#controls_android.lens.filterDensity">android.lens.filterDensity</a></li> + <li + ><a href="#controls_android.lens.focalLength">android.lens.focalLength</a></li> + <li + ><a href="#controls_android.lens.focusDistance">android.lens.focusDistance</a></li> + <li + ><a href="#controls_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + + <li + ><a href="#static_android.lens.info.availableApertures">android.lens.info.availableApertures</a></li> + <li + ><a href="#static_android.lens.info.availableFilterDensities">android.lens.info.availableFilterDensities</a></li> + <li + ><a href="#static_android.lens.info.availableFocalLengths">android.lens.info.availableFocalLengths</a></li> + <li + ><a href="#static_android.lens.info.availableOpticalStabilization">android.lens.info.availableOpticalStabilization</a></li> + <li + ><a href="#static_android.lens.info.hyperfocalDistance">android.lens.info.hyperfocalDistance</a></li> + <li + ><a href="#static_android.lens.info.minimumFocusDistance">android.lens.info.minimumFocusDistance</a></li> + <li + ><a href="#static_android.lens.info.shadingMapSize">android.lens.info.shadingMapSize</a></li> + <li + ><a href="#static_android.lens.info.focusDistanceCalibration">android.lens.info.focusDistanceCalibration</a></li> + + <li + ><a href="#static_android.lens.facing">android.lens.facing</a></li> + <li + ><a href="#static_android.lens.poseRotation">android.lens.poseRotation</a></li> + <li + ><a href="#static_android.lens.poseTranslation">android.lens.poseTranslation</a></li> + <li + ><a href="#static_android.lens.intrinsicCalibration">android.lens.intrinsicCalibration</a></li> + <li + ><a href="#static_android.lens.radialDistortion">android.lens.radialDistortion</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.lens.aperture">android.lens.aperture</a></li> + <li + ><a href="#dynamic_android.lens.filterDensity">android.lens.filterDensity</a></li> + <li + ><a href="#dynamic_android.lens.focalLength">android.lens.focalLength</a></li> + <li + ><a href="#dynamic_android.lens.focusDistance">android.lens.focusDistance</a></li> + <li + ><a href="#dynamic_android.lens.focusRange">android.lens.focusRange</a></li> + <li + ><a href="#dynamic_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a></li> + <li + ><a href="#dynamic_android.lens.state">android.lens.state</a></li> + <li + ><a href="#dynamic_android.lens.poseRotation">android.lens.poseRotation</a></li> + <li + ><a href="#dynamic_android.lens.poseTranslation">android.lens.poseTranslation</a></li> + <li + ><a href="#dynamic_android.lens.intrinsicCalibration">android.lens.intrinsicCalibration</a></li> + <li + ><a href="#dynamic_android.lens.radialDistortion">android.lens.radialDistortion</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_noiseReduction">noiseReduction</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.noiseReduction.mode">android.noiseReduction.mode</a></li> + <li + ><a href="#controls_android.noiseReduction.strength">android.noiseReduction.strength</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.noiseReduction.availableNoiseReductionModes</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.noiseReduction.mode">android.noiseReduction.mode</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_quirks">quirks</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + class="toc_deprecated" + ><a href="#static_android.quirks.meteringCropRegion">android.quirks.meteringCropRegion</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.quirks.triggerAfWithAuto">android.quirks.triggerAfWithAuto</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.quirks.useZslFormat">android.quirks.useZslFormat</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.quirks.usePartialResult">android.quirks.usePartialResult</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + class="toc_deprecated" + ><a href="#dynamic_android.quirks.partialResult">android.quirks.partialResult</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_request">request</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + class="toc_deprecated" + ><a href="#controls_android.request.frameCount">android.request.frameCount</a></li> + <li + ><a href="#controls_android.request.id">android.request.id</a></li> + <li + class="toc_deprecated" + ><a href="#controls_android.request.inputStreams">android.request.inputStreams</a></li> + <li + ><a href="#controls_android.request.metadataMode">android.request.metadataMode</a></li> + <li + class="toc_deprecated" + ><a href="#controls_android.request.outputStreams">android.request.outputStreams</a></li> + <li + class="toc_deprecated" + ><a href="#controls_android.request.type">android.request.type</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.request.maxNumOutputStreams">android.request.maxNumOutputStreams</a></li> + <li + ><a href="#static_android.request.maxNumOutputRaw">android.request.maxNumOutputRaw</a></li> + <li + ><a href="#static_android.request.maxNumOutputProc">android.request.maxNumOutputProc</a></li> + <li + ><a href="#static_android.request.maxNumOutputProcStalling">android.request.maxNumOutputProcStalling</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.request.maxNumReprocessStreams">android.request.maxNumReprocessStreams</a></li> + <li + ><a href="#static_android.request.maxNumInputStreams">android.request.maxNumInputStreams</a></li> + <li + ><a href="#static_android.request.pipelineMaxDepth">android.request.pipelineMaxDepth</a></li> + <li + ><a href="#static_android.request.partialResultCount">android.request.partialResultCount</a></li> + <li + ><a href="#static_android.request.availableCapabilities">android.request.availableCapabilities</a></li> + <li + ><a href="#static_android.request.availableRequestKeys">android.request.availableRequestKeys</a></li> + <li + ><a href="#static_android.request.availableResultKeys">android.request.availableResultKeys</a></li> + <li + ><a href="#static_android.request.availableCharacteristicsKeys">android.request.availableCharacteristicsKeys</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + class="toc_deprecated" + ><a href="#dynamic_android.request.frameCount">android.request.frameCount</a></li> + <li + ><a href="#dynamic_android.request.id">android.request.id</a></li> + <li + ><a href="#dynamic_android.request.metadataMode">android.request.metadataMode</a></li> + <li + class="toc_deprecated" + ><a href="#dynamic_android.request.outputStreams">android.request.outputStreams</a></li> + <li + ><a href="#dynamic_android.request.pipelineDepth">android.request.pipelineDepth</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_scaler">scaler</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.scaler.cropRegion">android.scaler.cropRegion</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + class="toc_deprecated" + ><a href="#static_android.scaler.availableFormats">android.scaler.availableFormats</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.scaler.availableJpegMinDurations">android.scaler.availableJpegMinDurations</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.scaler.availableJpegSizes">android.scaler.availableJpegSizes</a></li> + <li + ><a href="#static_android.scaler.availableMaxDigitalZoom">android.scaler.availableMaxDigitalZoom</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.scaler.availableProcessedMinDurations">android.scaler.availableProcessedMinDurations</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.scaler.availableProcessedSizes">android.scaler.availableProcessedSizes</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.scaler.availableRawMinDurations">android.scaler.availableRawMinDurations</a></li> + <li + class="toc_deprecated" + ><a href="#static_android.scaler.availableRawSizes">android.scaler.availableRawSizes</a></li> + <li + ><a href="#static_android.scaler.availableInputOutputFormatsMap">android.scaler.availableInputOutputFormatsMap</a></li> + <li + ><a href="#static_android.scaler.availableStreamConfigurations">android.scaler.availableStreamConfigurations</a></li> + <li + ><a href="#static_android.scaler.availableMinFrameDurations">android.scaler.availableMinFrameDurations</a></li> + <li + ><a href="#static_android.scaler.availableStallDurations">android.scaler.availableStallDurations</a></li> + <li + ><a href="#static_android.scaler.streamConfigurationMap">android.scaler.streamConfigurationMap</a></li> + <li + ><a href="#static_android.scaler.croppingType">android.scaler.croppingType</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.scaler.cropRegion">android.scaler.cropRegion</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_sensor">sensor</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.sensor.exposureTime">android.sensor.exposureTime</a></li> + <li + ><a href="#controls_android.sensor.frameDuration">android.sensor.frameDuration</a></li> + <li + ><a href="#controls_android.sensor.sensitivity">android.sensor.sensitivity</a></li> + <li + ><a href="#controls_android.sensor.testPatternData">android.sensor.testPatternData</a></li> + <li + ><a href="#controls_android.sensor.testPatternMode">android.sensor.testPatternMode</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + + <li + ><a href="#static_android.sensor.info.activeArraySize">android.sensor.info.activeArraySize</a></li> + <li + ><a href="#static_android.sensor.info.sensitivityRange">android.sensor.info.sensitivityRange</a></li> + <li + ><a href="#static_android.sensor.info.colorFilterArrangement">android.sensor.info.colorFilterArrangement</a></li> + <li + ><a href="#static_android.sensor.info.exposureTimeRange">android.sensor.info.exposureTimeRange</a></li> + <li + ><a href="#static_android.sensor.info.maxFrameDuration">android.sensor.info.maxFrameDuration</a></li> + <li + ><a href="#static_android.sensor.info.physicalSize">android.sensor.info.physicalSize</a></li> + <li + ><a href="#static_android.sensor.info.pixelArraySize">android.sensor.info.pixelArraySize</a></li> + <li + ><a href="#static_android.sensor.info.whiteLevel">android.sensor.info.whiteLevel</a></li> + <li + ><a href="#static_android.sensor.info.timestampSource">android.sensor.info.timestampSource</a></li> + <li + ><a href="#static_android.sensor.info.lensShadingApplied">android.sensor.info.lensShadingApplied</a></li> + <li + ><a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.sensor.info.preCorrectionActiveArraySize</a></li> + + <li + ><a href="#static_android.sensor.referenceIlluminant1">android.sensor.referenceIlluminant1</a></li> + <li + ><a href="#static_android.sensor.referenceIlluminant2">android.sensor.referenceIlluminant2</a></li> + <li + ><a href="#static_android.sensor.calibrationTransform1">android.sensor.calibrationTransform1</a></li> + <li + ><a href="#static_android.sensor.calibrationTransform2">android.sensor.calibrationTransform2</a></li> + <li + ><a href="#static_android.sensor.colorTransform1">android.sensor.colorTransform1</a></li> + <li + ><a href="#static_android.sensor.colorTransform2">android.sensor.colorTransform2</a></li> + <li + ><a href="#static_android.sensor.forwardMatrix1">android.sensor.forwardMatrix1</a></li> + <li + ><a href="#static_android.sensor.forwardMatrix2">android.sensor.forwardMatrix2</a></li> + <li + ><a href="#static_android.sensor.baseGainFactor">android.sensor.baseGainFactor</a></li> + <li + ><a href="#static_android.sensor.blackLevelPattern">android.sensor.blackLevelPattern</a></li> + <li + ><a href="#static_android.sensor.maxAnalogSensitivity">android.sensor.maxAnalogSensitivity</a></li> + <li + ><a href="#static_android.sensor.orientation">android.sensor.orientation</a></li> + <li + ><a href="#static_android.sensor.profileHueSatMapDimensions">android.sensor.profileHueSatMapDimensions</a></li> + <li + ><a href="#static_android.sensor.availableTestPatternModes">android.sensor.availableTestPatternModes</a></li> + <li + ><a href="#static_android.sensor.opticalBlackRegions">android.sensor.opticalBlackRegions</a></li> + <li + ><a href="#static_android.sensor.opaqueRawSize">android.sensor.opaqueRawSize</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.sensor.exposureTime">android.sensor.exposureTime</a></li> + <li + ><a href="#dynamic_android.sensor.frameDuration">android.sensor.frameDuration</a></li> + <li + ><a href="#dynamic_android.sensor.sensitivity">android.sensor.sensitivity</a></li> + <li + ><a href="#dynamic_android.sensor.timestamp">android.sensor.timestamp</a></li> + <li + ><a href="#dynamic_android.sensor.temperature">android.sensor.temperature</a></li> + <li + ><a href="#dynamic_android.sensor.neutralColorPoint">android.sensor.neutralColorPoint</a></li> + <li + ><a href="#dynamic_android.sensor.noiseProfile">android.sensor.noiseProfile</a></li> + <li + ><a href="#dynamic_android.sensor.profileHueSatMap">android.sensor.profileHueSatMap</a></li> + <li + ><a href="#dynamic_android.sensor.profileToneCurve">android.sensor.profileToneCurve</a></li> + <li + ><a href="#dynamic_android.sensor.greenSplit">android.sensor.greenSplit</a></li> + <li + ><a href="#dynamic_android.sensor.testPatternData">android.sensor.testPatternData</a></li> + <li + ><a href="#dynamic_android.sensor.testPatternMode">android.sensor.testPatternMode</a></li> + <li + ><a href="#dynamic_android.sensor.rollingShutterSkew">android.sensor.rollingShutterSkew</a></li> + <li + ><a href="#dynamic_android.sensor.dynamicBlackLevel">android.sensor.dynamicBlackLevel</a></li> + <li + ><a href="#dynamic_android.sensor.dynamicWhiteLevel">android.sensor.dynamicWhiteLevel</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_shading">shading</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.shading.mode">android.shading.mode</a></li> + <li + ><a href="#controls_android.shading.strength">android.shading.strength</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.shading.mode">android.shading.mode</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.shading.availableModes">android.shading.availableModes</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_statistics">statistics</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.statistics.faceDetectMode">android.statistics.faceDetectMode</a></li> + <li + ><a href="#controls_android.statistics.histogramMode">android.statistics.histogramMode</a></li> + <li + ><a href="#controls_android.statistics.sharpnessMapMode">android.statistics.sharpnessMapMode</a></li> + <li + ><a href="#controls_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a></li> + <li + ><a href="#controls_android.statistics.lensShadingMapMode">android.statistics.lensShadingMapMode</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + + <li + ><a href="#static_android.statistics.info.availableFaceDetectModes">android.statistics.info.availableFaceDetectModes</a></li> + <li + ><a href="#static_android.statistics.info.histogramBucketCount">android.statistics.info.histogramBucketCount</a></li> + <li + ><a href="#static_android.statistics.info.maxFaceCount">android.statistics.info.maxFaceCount</a></li> + <li + ><a href="#static_android.statistics.info.maxHistogramCount">android.statistics.info.maxHistogramCount</a></li> + <li + ><a href="#static_android.statistics.info.maxSharpnessMapValue">android.statistics.info.maxSharpnessMapValue</a></li> + <li + ><a href="#static_android.statistics.info.sharpnessMapSize">android.statistics.info.sharpnessMapSize</a></li> + <li + ><a href="#static_android.statistics.info.availableHotPixelMapModes">android.statistics.info.availableHotPixelMapModes</a></li> + <li + ><a href="#static_android.statistics.info.availableLensShadingMapModes">android.statistics.info.availableLensShadingMapModes</a></li> + + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.statistics.faceDetectMode">android.statistics.faceDetectMode</a></li> + <li + ><a href="#dynamic_android.statistics.faceIds">android.statistics.faceIds</a></li> + <li + ><a href="#dynamic_android.statistics.faceLandmarks">android.statistics.faceLandmarks</a></li> + <li + ><a href="#dynamic_android.statistics.faceRectangles">android.statistics.faceRectangles</a></li> + <li + ><a href="#dynamic_android.statistics.faceScores">android.statistics.faceScores</a></li> + <li + ><a href="#dynamic_android.statistics.faces">android.statistics.faces</a></li> + <li + ><a href="#dynamic_android.statistics.histogram">android.statistics.histogram</a></li> + <li + ><a href="#dynamic_android.statistics.histogramMode">android.statistics.histogramMode</a></li> + <li + ><a href="#dynamic_android.statistics.sharpnessMap">android.statistics.sharpnessMap</a></li> + <li + ><a href="#dynamic_android.statistics.sharpnessMapMode">android.statistics.sharpnessMapMode</a></li> + <li + ><a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.statistics.lensShadingCorrectionMap</a></li> + <li + ><a href="#dynamic_android.statistics.lensShadingMap">android.statistics.lensShadingMap</a></li> + <li + class="toc_deprecated" + ><a href="#dynamic_android.statistics.predictedColorGains">android.statistics.predictedColorGains</a></li> + <li + class="toc_deprecated" + ><a href="#dynamic_android.statistics.predictedColorTransform">android.statistics.predictedColorTransform</a></li> + <li + ><a href="#dynamic_android.statistics.sceneFlicker">android.statistics.sceneFlicker</a></li> + <li + ><a href="#dynamic_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a></li> + <li + ><a href="#dynamic_android.statistics.hotPixelMap">android.statistics.hotPixelMap</a></li> + <li + ><a href="#dynamic_android.statistics.lensShadingMapMode">android.statistics.lensShadingMapMode</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_tonemap">tonemap</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.tonemap.curveBlue">android.tonemap.curveBlue</a></li> + <li + ><a href="#controls_android.tonemap.curveGreen">android.tonemap.curveGreen</a></li> + <li + ><a href="#controls_android.tonemap.curveRed">android.tonemap.curveRed</a></li> + <li + ><a href="#controls_android.tonemap.curve">android.tonemap.curve</a></li> + <li + ><a href="#controls_android.tonemap.mode">android.tonemap.mode</a></li> + <li + ><a href="#controls_android.tonemap.gamma">android.tonemap.gamma</a></li> + <li + ><a href="#controls_android.tonemap.presetCurve">android.tonemap.presetCurve</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.tonemap.maxCurvePoints">android.tonemap.maxCurvePoints</a></li> + <li + ><a href="#static_android.tonemap.availableToneMapModes">android.tonemap.availableToneMapModes</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.tonemap.curveBlue">android.tonemap.curveBlue</a></li> + <li + ><a href="#dynamic_android.tonemap.curveGreen">android.tonemap.curveGreen</a></li> + <li + ><a href="#dynamic_android.tonemap.curveRed">android.tonemap.curveRed</a></li> + <li + ><a href="#dynamic_android.tonemap.curve">android.tonemap.curve</a></li> + <li + ><a href="#dynamic_android.tonemap.mode">android.tonemap.mode</a></li> + <li + ><a href="#dynamic_android.tonemap.gamma">android.tonemap.gamma</a></li> + <li + ><a href="#dynamic_android.tonemap.presetCurve">android.tonemap.presetCurve</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_led">led</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.led.transmit">android.led.transmit</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.led.transmit">android.led.transmit</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.led.availableLeds">android.led.availableLeds</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_info">info</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.info.supportedHardwareLevel">android.info.supportedHardwareLevel</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_blackLevel">blackLevel</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.blackLevel.lock">android.blackLevel.lock</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.blackLevel.lock">android.blackLevel.lock</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_sync">sync</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.sync.frameNumber">android.sync.frameNumber</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.sync.maxLatency">android.sync.maxLatency</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_reprocess">reprocess</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">controls</span> + <ul class="toc_section"> + <li + ><a href="#controls_android.reprocess.effectiveExposureFactor">android.reprocess.effectiveExposureFactor</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">dynamic</span> + <ul class="toc_section"> + <li + ><a href="#dynamic_android.reprocess.effectiveExposureFactor">android.reprocess.effectiveExposureFactor</a></li> + </ul> + </li> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.reprocess.maxCaptureStall">android.reprocess.maxCaptureStall</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + <li> + <span class="toc_section_header"><a href="#section_depth">depth</a></span> + <ul class="toc_section"> + <li> + <span class="toc_kind_header">static</span> + <ul class="toc_section"> + <li + ><a href="#static_android.depth.maxDepthSamples">android.depth.maxDepthSamples</a></li> + <li + ><a href="#static_android.depth.availableDepthStreamConfigurations">android.depth.availableDepthStreamConfigurations</a></li> + <li + ><a href="#static_android.depth.availableDepthMinFrameDurations">android.depth.availableDepthMinFrameDurations</a></li> + <li + ><a href="#static_android.depth.availableDepthStallDurations">android.depth.availableDepthStallDurations</a></li> + <li + ><a href="#static_android.depth.depthIsExclusive">android.depth.depthIsExclusive</a></li> + </ul> + </li> + </ul> <!-- toc_section --> + </li> + </ul> + + + <h1>Properties</h1> + <table class="properties"> + + <thead class="thead_dummy"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> <!-- so that the first occurrence of thead is not + above the first occurrence of tr --> +<!-- <namespace name="android"> --> + <tr><td colspan="6" id="section_colorCorrection" class="section">colorCorrection</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.colorCorrection.mode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>color<wbr/>Correction.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">TRANSFORM_MATRIX</span> + <span class="entry_type_enum_notes"><p>Use the <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> matrix +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> to do color conversion.<wbr/></p> +<p>All advanced white balance adjustments (not specified +by our white balance pipeline) must be disabled.<wbr/></p> +<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then +TRANSFORM_<wbr/>MATRIX is ignored.<wbr/> The camera device will override +this value to either FAST or HIGH_<wbr/>QUALITY.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Color correction processing must not slow down +capture rate relative to sensor raw output.<wbr/></p> +<p>Advanced white balance adjustments above and beyond +the specified white balance pipeline may be applied.<wbr/></p> +<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then +the camera device uses the last frame's AWB values +(or defaults if AWB has never been run).<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>Color correction processing operates at improved +quality but the capture rate might be reduced (relative to sensor +raw output rate)</p> +<p>Advanced white balance adjustments above and beyond +the specified white balance pipeline may be applied.<wbr/></p> +<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then +the camera device uses the last frame's AWB values +(or defaults if AWB has never been run).<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The mode control selects how the image data is converted from the +sensor's native color into linear sRGB color.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When auto-white balance (AWB) is enabled with <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> this +control is overridden by the AWB routine.<wbr/> When AWB is disabled,<wbr/> the +application controls how the color mapping is performed.<wbr/></p> +<p>We define the expected processing pipeline below.<wbr/> For consistency +across devices,<wbr/> this is always the case with TRANSFORM_<wbr/>MATRIX.<wbr/></p> +<p>When either FULL or HIGH_<wbr/>QUALITY is used,<wbr/> the camera device may +do additional processing but <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and +<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> will still be provided by the +camera device (in the results) and be roughly correct.<wbr/></p> +<p>Switching to TRANSFORM_<wbr/>MATRIX and using the data provided from +FAST or HIGH_<wbr/>QUALITY will yield a picture with the same white point +as what was produced by the camera device in the earlier frame.<wbr/></p> +<p>The expected processing pipeline is as follows:</p> +<p><img alt="White balance processing pipeline" src="images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png"/></p> +<p>The white balance is encoded by two values,<wbr/> a 4-channel white-balance +gain vector (applied in the Bayer domain),<wbr/> and a 3x3 color transform +matrix (applied after demosaic).<wbr/></p> +<p>The 4-channel white-balance gains are defined as:</p> +<pre><code><a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> = [ R G_<wbr/>even G_<wbr/>odd B ] +</code></pre> +<p>where <code>G_<wbr/>even</code> is the gain for green pixels on even rows of the +output,<wbr/> and <code>G_<wbr/>odd</code> is the gain for green pixels on the odd rows.<wbr/> +These may be identical for a given camera device implementation; if +the camera device does not support a separate gain for even/<wbr/>odd green +channels,<wbr/> it will use the <code>G_<wbr/>even</code> value,<wbr/> and write <code>G_<wbr/>odd</code> equal to +<code>G_<wbr/>even</code> in the output result metadata.<wbr/></p> +<p>The matrices for color transforms are defined as a 9-entry vector:</p> +<pre><code><a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> = [ I0 I1 I2 I3 I4 I5 I6 I7 I8 ] +</code></pre> +<p>which define a transform from input sensor colors,<wbr/> <code>P_<wbr/>in = [ r g b ]</code>,<wbr/> +to output linear sRGB,<wbr/> <code>P_<wbr/>out = [ r' g' b' ]</code>,<wbr/></p> +<p>with colors as follows:</p> +<pre><code>r' = I0r + I1g + I2b +g' = I3r + I4g + I5b +b' = I6r + I7g + I8b +</code></pre> +<p>Both the input and output value ranges must match.<wbr/> Overflow/<wbr/>underflow +values are clipped to fit within the range.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if color correction control is available +on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/> +That is,<wbr/> if the highest quality implementation on the camera device does not slow down +capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY should generate the same output.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.colorCorrection.transform"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>color<wbr/>Correction.<wbr/>transform + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x 3 + </span> + <span class="entry_type_visibility"> [public as colorSpaceTransform]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">3x3 rational matrix in row-major order</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A color transform matrix to use to transform +from sensor RGB color space to output linear sRGB color space.<wbr/></p> + </td> + + <td class="entry_units"> + Unitless scale factors + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This matrix is either set by the camera device when the request +<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not TRANSFORM_<wbr/>MATRIX,<wbr/> or +directly by the application in the request when the +<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is TRANSFORM_<wbr/>MATRIX.<wbr/></p> +<p>In the latter case,<wbr/> the camera device may round the matrix to account +for precision issues; the final rounded matrix should be reported back +in this matrix result metadata.<wbr/> The transform should keep the magnitude +of the output color values within <code>[0,<wbr/> 1.<wbr/>0]</code> (assuming input color +values is within the normalized range <code>[0,<wbr/> 1.<wbr/>0]</code>),<wbr/> or clipping may occur.<wbr/></p> +<p>The valid range of each matrix element varies on different devices,<wbr/> but +values within [-1.<wbr/>5,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.colorCorrection.gains"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>color<wbr/>Correction.<wbr/>gains + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public as rggbChannelVector]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">A 1D array of floats for 4 color channel gains</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Gains applying to Bayer raw color channels for +white-balance.<wbr/></p> + </td> + + <td class="entry_units"> + Unitless gain factors + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>These per-channel gains are either set by the camera device +when the request <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not +TRANSFORM_<wbr/>MATRIX,<wbr/> or directly by the application in the +request when the <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is +TRANSFORM_<wbr/>MATRIX.<wbr/></p> +<p>The gains in the result metadata are the gains actually +applied by the camera device to the current frame.<wbr/></p> +<p>The valid range of gains varies on different devices,<wbr/> but gains +between [1.<wbr/>0,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/> Even if a given +device allows gains below 1.<wbr/>0,<wbr/> this is usually not recommended because +this can create color artifacts.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The 4-channel white-balance gains are defined in +the order of <code>[R G_<wbr/>even G_<wbr/>odd B]</code>,<wbr/> where <code>G_<wbr/>even</code> is the gain +for green pixels on even rows of the output,<wbr/> and <code>G_<wbr/>odd</code> +is the gain for green pixels on the odd rows.<wbr/></p> +<p>If a HAL does not support a separate gain for even/<wbr/>odd green +channels,<wbr/> it must use the <code>G_<wbr/>even</code> value,<wbr/> and write +<code>G_<wbr/>odd</code> equal to <code>G_<wbr/>even</code> in the output result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.colorCorrection.aberrationMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No aberration correction is applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Aberration correction will not slow down capture rate +relative to sensor raw output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>Aberration correction operates at improved quality but the capture rate might be +reduced (relative to sensor raw output rate)</p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Mode of operation for the chromatic aberration correction algorithm.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.colorCorrection.availableAberrationModes">android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Chromatic (color) aberration is caused by the fact that different wavelengths of light +can not focus on the same point after exiting from the lens.<wbr/> This metadata defines +the high level control of chromatic aberration correction algorithm,<wbr/> which aims to +minimize the chromatic artifacts that may occur along the object boundaries in an +image.<wbr/></p> +<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean that camera device determined aberration +correction will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device will +use the highest-quality aberration correction algorithms,<wbr/> even if it slows down +capture rate.<wbr/> FAST means the camera device will not slow down capture rate when +applying aberration correction.<wbr/></p> +<p>LEGACY devices will always be in FAST mode.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.colorCorrection.mode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>color<wbr/>Correction.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">TRANSFORM_MATRIX</span> + <span class="entry_type_enum_notes"><p>Use the <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> matrix +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> to do color conversion.<wbr/></p> +<p>All advanced white balance adjustments (not specified +by our white balance pipeline) must be disabled.<wbr/></p> +<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then +TRANSFORM_<wbr/>MATRIX is ignored.<wbr/> The camera device will override +this value to either FAST or HIGH_<wbr/>QUALITY.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Color correction processing must not slow down +capture rate relative to sensor raw output.<wbr/></p> +<p>Advanced white balance adjustments above and beyond +the specified white balance pipeline may be applied.<wbr/></p> +<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then +the camera device uses the last frame's AWB values +(or defaults if AWB has never been run).<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>Color correction processing operates at improved +quality but the capture rate might be reduced (relative to sensor +raw output rate)</p> +<p>Advanced white balance adjustments above and beyond +the specified white balance pipeline may be applied.<wbr/></p> +<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then +the camera device uses the last frame's AWB values +(or defaults if AWB has never been run).<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The mode control selects how the image data is converted from the +sensor's native color into linear sRGB color.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When auto-white balance (AWB) is enabled with <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> this +control is overridden by the AWB routine.<wbr/> When AWB is disabled,<wbr/> the +application controls how the color mapping is performed.<wbr/></p> +<p>We define the expected processing pipeline below.<wbr/> For consistency +across devices,<wbr/> this is always the case with TRANSFORM_<wbr/>MATRIX.<wbr/></p> +<p>When either FULL or HIGH_<wbr/>QUALITY is used,<wbr/> the camera device may +do additional processing but <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and +<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> will still be provided by the +camera device (in the results) and be roughly correct.<wbr/></p> +<p>Switching to TRANSFORM_<wbr/>MATRIX and using the data provided from +FAST or HIGH_<wbr/>QUALITY will yield a picture with the same white point +as what was produced by the camera device in the earlier frame.<wbr/></p> +<p>The expected processing pipeline is as follows:</p> +<p><img alt="White balance processing pipeline" src="images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png"/></p> +<p>The white balance is encoded by two values,<wbr/> a 4-channel white-balance +gain vector (applied in the Bayer domain),<wbr/> and a 3x3 color transform +matrix (applied after demosaic).<wbr/></p> +<p>The 4-channel white-balance gains are defined as:</p> +<pre><code><a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> = [ R G_<wbr/>even G_<wbr/>odd B ] +</code></pre> +<p>where <code>G_<wbr/>even</code> is the gain for green pixels on even rows of the +output,<wbr/> and <code>G_<wbr/>odd</code> is the gain for green pixels on the odd rows.<wbr/> +These may be identical for a given camera device implementation; if +the camera device does not support a separate gain for even/<wbr/>odd green +channels,<wbr/> it will use the <code>G_<wbr/>even</code> value,<wbr/> and write <code>G_<wbr/>odd</code> equal to +<code>G_<wbr/>even</code> in the output result metadata.<wbr/></p> +<p>The matrices for color transforms are defined as a 9-entry vector:</p> +<pre><code><a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> = [ I0 I1 I2 I3 I4 I5 I6 I7 I8 ] +</code></pre> +<p>which define a transform from input sensor colors,<wbr/> <code>P_<wbr/>in = [ r g b ]</code>,<wbr/> +to output linear sRGB,<wbr/> <code>P_<wbr/>out = [ r' g' b' ]</code>,<wbr/></p> +<p>with colors as follows:</p> +<pre><code>r' = I0r + I1g + I2b +g' = I3r + I4g + I5b +b' = I6r + I7g + I8b +</code></pre> +<p>Both the input and output value ranges must match.<wbr/> Overflow/<wbr/>underflow +values are clipped to fit within the range.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if color correction control is available +on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/> +That is,<wbr/> if the highest quality implementation on the camera device does not slow down +capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY should generate the same output.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.colorCorrection.transform"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>color<wbr/>Correction.<wbr/>transform + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x 3 + </span> + <span class="entry_type_visibility"> [public as colorSpaceTransform]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">3x3 rational matrix in row-major order</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A color transform matrix to use to transform +from sensor RGB color space to output linear sRGB color space.<wbr/></p> + </td> + + <td class="entry_units"> + Unitless scale factors + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This matrix is either set by the camera device when the request +<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not TRANSFORM_<wbr/>MATRIX,<wbr/> or +directly by the application in the request when the +<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is TRANSFORM_<wbr/>MATRIX.<wbr/></p> +<p>In the latter case,<wbr/> the camera device may round the matrix to account +for precision issues; the final rounded matrix should be reported back +in this matrix result metadata.<wbr/> The transform should keep the magnitude +of the output color values within <code>[0,<wbr/> 1.<wbr/>0]</code> (assuming input color +values is within the normalized range <code>[0,<wbr/> 1.<wbr/>0]</code>),<wbr/> or clipping may occur.<wbr/></p> +<p>The valid range of each matrix element varies on different devices,<wbr/> but +values within [-1.<wbr/>5,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.colorCorrection.gains"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>color<wbr/>Correction.<wbr/>gains + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public as rggbChannelVector]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">A 1D array of floats for 4 color channel gains</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Gains applying to Bayer raw color channels for +white-balance.<wbr/></p> + </td> + + <td class="entry_units"> + Unitless gain factors + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>These per-channel gains are either set by the camera device +when the request <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not +TRANSFORM_<wbr/>MATRIX,<wbr/> or directly by the application in the +request when the <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is +TRANSFORM_<wbr/>MATRIX.<wbr/></p> +<p>The gains in the result metadata are the gains actually +applied by the camera device to the current frame.<wbr/></p> +<p>The valid range of gains varies on different devices,<wbr/> but gains +between [1.<wbr/>0,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/> Even if a given +device allows gains below 1.<wbr/>0,<wbr/> this is usually not recommended because +this can create color artifacts.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The 4-channel white-balance gains are defined in +the order of <code>[R G_<wbr/>even G_<wbr/>odd B]</code>,<wbr/> where <code>G_<wbr/>even</code> is the gain +for green pixels on even rows of the output,<wbr/> and <code>G_<wbr/>odd</code> +is the gain for green pixels on the odd rows.<wbr/></p> +<p>If a HAL does not support a separate gain for even/<wbr/>odd green +channels,<wbr/> it must use the <code>G_<wbr/>even</code> value,<wbr/> and write +<code>G_<wbr/>odd</code> equal to <code>G_<wbr/>even</code> in the output result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.colorCorrection.aberrationMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No aberration correction is applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Aberration correction will not slow down capture rate +relative to sensor raw output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>Aberration correction operates at improved quality but the capture rate might be +reduced (relative to sensor raw output rate)</p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Mode of operation for the chromatic aberration correction algorithm.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.colorCorrection.availableAberrationModes">android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Chromatic (color) aberration is caused by the fact that different wavelengths of light +can not focus on the same point after exiting from the lens.<wbr/> This metadata defines +the high level control of chromatic aberration correction algorithm,<wbr/> which aims to +minimize the chromatic artifacts that may occur along the object boundaries in an +image.<wbr/></p> +<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean that camera device determined aberration +correction will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device will +use the highest-quality aberration correction algorithms,<wbr/> even if it slows down +capture rate.<wbr/> FAST means the camera device will not slow down capture rate when +applying aberration correction.<wbr/></p> +<p>LEGACY devices will always be in FAST mode.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.colorCorrection.availableAberrationModes"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of aberration correction modes for <a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a> that are +supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This key lists the valid modes for <a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a>.<wbr/> If no +aberration correction modes are available for a device,<wbr/> this list will solely include +OFF mode.<wbr/> All camera devices will support either OFF or FAST mode.<wbr/></p> +<p>Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always list +OFF mode.<wbr/> This includes all FULL level devices.<wbr/></p> +<p>LEGACY devices will always only support FAST mode.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if chromatic aberration control is available +on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/> +That is,<wbr/> if the highest quality implementation on the camera device does not slow down +capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_control" class="section">control</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.control.aeAntibandingMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>The camera device will not adjust exposure duration to +avoid banding problems.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">50HZ</span> + <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to +avoid banding problems with 50Hz illumination sources.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">60HZ</span> + <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to +avoid banding problems with 60Hz illumination +sources.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AUTO</span> + <span class="entry_type_enum_notes"><p>The camera device will automatically adapt its +antibanding routine to the current illumination +condition.<wbr/> This is the default mode if AUTO is +available on given camera device.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired setting for the camera device's auto-exposure +algorithm's antibanding compensation.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Some kinds of lighting fixtures,<wbr/> such as some fluorescent +lights,<wbr/> flicker at the rate of the power supply frequency +(60Hz or 50Hz,<wbr/> depending on country).<wbr/> While this is +typically not noticeable to a person,<wbr/> it can be visible to +a camera device.<wbr/> If a camera sets its exposure time to the +wrong value,<wbr/> the flicker may become visible in the +viewfinder as flicker or in a final captured image,<wbr/> as a +set of variable-brightness bands across the image.<wbr/></p> +<p>Therefore,<wbr/> the auto-exposure routines of camera devices +include antibanding routines that ensure that the chosen +exposure value will not cause such banding.<wbr/> The choice of +exposure time depends on the rate of flicker,<wbr/> which the +camera device can detect automatically,<wbr/> or the expected +rate can be selected by the application using this +control.<wbr/></p> +<p>A given camera device may not support all of the possible +options for the antibanding mode.<wbr/> The +<a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a> key contains +the available modes for a given camera device.<wbr/></p> +<p>AUTO mode is the default if it is available on given +camera device.<wbr/> When AUTO mode is not available,<wbr/> the +default will be either 50HZ or 60HZ,<wbr/> and both 50HZ +and 60HZ will be available.<wbr/></p> +<p>If manual exposure control is enabled (by setting +<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/> +then this setting has no effect,<wbr/> and the application must +ensure it selects exposure times that do not cause banding +issues.<wbr/> The <a href="#dynamic_android.statistics.sceneFlicker">android.<wbr/>statistics.<wbr/>scene<wbr/>Flicker</a> key can assist +the application in this.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For all capture request templates,<wbr/> this field must be set +to AUTO if AUTO mode is available.<wbr/> If AUTO is not available,<wbr/> +the default must be either 50HZ or 60HZ,<wbr/> and both 50HZ and +60HZ must be available.<wbr/></p> +<p>If manual exposure control is enabled (by setting +<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/> +then the exposure values provided by the application must not be +adjusted for antibanding.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.aeExposureCompensation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Adjustment to auto-exposure (AE) target image +brightness.<wbr/></p> + </td> + + <td class="entry_units"> + Compensation steps + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The adjustment is measured as a count of steps,<wbr/> with the +step size defined by <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> and the +allowed range by <a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a>.<wbr/></p> +<p>For example,<wbr/> if the exposure value (EV) step is 0.<wbr/>333,<wbr/> '6' +will mean an exposure compensation of +2 EV; -3 will mean an +exposure compensation of -1 EV.<wbr/> One EV represents a doubling +of image brightness.<wbr/> Note that this control will only be +effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF.<wbr/> This control +will take effect even when <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> <code>== true</code>.<wbr/></p> +<p>In the event of exposure compensation value being changed,<wbr/> camera device +may take several frames to reach the newly requested exposure target.<wbr/> +During that time,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> field will be in the SEARCHING +state.<wbr/> Once the new exposure target is reached,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> will +change from SEARCHING to either CONVERGED,<wbr/> LOCKED (if AE lock is enabled),<wbr/> or +FLASH_<wbr/>REQUIRED (if the scene is too dark for still capture).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.aeLock"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Lock + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Auto-exposure lock is disabled; the AE algorithm +is free to update its parameters.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Auto-exposure lock is enabled; the AE algorithm +must not update the exposure and sensitivity parameters +while the lock is active.<wbr/></p> +<p><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> setting changes +will still take effect while auto-exposure is locked.<wbr/></p> +<p>Some rare LEGACY devices may not support +this,<wbr/> in which case the value will always be overridden to OFF.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether auto-exposure (AE) is currently locked to its latest +calculated values.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to <code>true</code> (ON),<wbr/> the AE algorithm is locked to its latest parameters,<wbr/> +and will not change exposure settings until the lock is set to <code>false</code> (OFF).<wbr/></p> +<p>Note that even when AE is locked,<wbr/> the flash may be fired if +the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>AUTO_<wbr/>FLASH /<wbr/> +ON_<wbr/>ALWAYS_<wbr/>FLASH /<wbr/> ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE.<wbr/></p> +<p>When <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> is changed,<wbr/> even if the AE lock +is ON,<wbr/> the camera device will still adjust its exposure value.<wbr/></p> +<p>If AE precapture is triggered (see <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) +when AE is already locked,<wbr/> the camera device will not change the exposure time +(<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>) and sensitivity (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>) +parameters.<wbr/> The flash may be fired if the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> +is ON_<wbr/>AUTO_<wbr/>FLASH/<wbr/>ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE and the scene is too dark.<wbr/> If the +<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> the scene may become overexposed.<wbr/> +Similarly,<wbr/> AE precapture trigger CANCEL has no effect when AE is already locked.<wbr/></p> +<p>When an AE precapture sequence is triggered,<wbr/> AE unlock will not be able to unlock +the AE if AE is locked by the camera device internally during precapture metering +sequence In other words,<wbr/> submitting requests with AE unlock has no effect for an +ongoing precapture metering sequence.<wbr/> Otherwise,<wbr/> the precapture metering sequence +will never succeed in a sequence of preview requests where AE lock is always set +to <code>false</code>.<wbr/></p> +<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that +get locked do not necessarily correspond to the settings that were present in the +latest capture result received from the camera device,<wbr/> since additional captures +and AE updates may have occurred even before the result was sent out.<wbr/> If an +application is switching between automatic and manual control and wishes to eliminate +any flicker during the switch,<wbr/> the following procedure is recommended:</p> +<ol> +<li>Starting in auto-AE mode:</li> +<li>Lock AE</li> +<li>Wait for the first result to be output that has the AE locked</li> +<li>Copy exposure settings from that result into a request,<wbr/> set the request to manual AE</li> +<li>Submit the capture request,<wbr/> proceed to run manual AE as desired.<wbr/></li> +</ol> +<p>See <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE lock related state transition details.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.aeMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is disabled.<wbr/></p> +<p>The application-selected <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> +<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> and +<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are used by the camera +device,<wbr/> along with android.<wbr/>flash.<wbr/>* fields,<wbr/> if there's +a flash unit for this camera device.<wbr/></p> +<p>Note that auto-white balance (AWB) and auto-focus (AF) +behavior is device dependent when AE is in OFF mode.<wbr/> +To have consistent behavior across different devices,<wbr/> +it is recommended to either set AWB and AF to OFF mode +or lock AWB and AF before setting AE to OFF.<wbr/> +See <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a>,<wbr/> and <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> +for more details.<wbr/></p> +<p>LEGACY devices do not support the OFF mode and will +override attempts to use this value to ON.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is active,<wbr/> +with no flash control.<wbr/></p> +<p>The application's values for +<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> +<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and +<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are ignored.<wbr/> The +application has control over the various +android.<wbr/>flash.<wbr/>* fields.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON_AUTO_FLASH</span> + <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls +the camera's flash unit,<wbr/> firing it in low-light +conditions.<wbr/></p> +<p>The flash may be fired during a precapture sequence +(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and +may be fired for captures for which the +<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to +STILL_<wbr/>CAPTURE</p></span> + </li> + <li> + <span class="entry_type_enum_name">ON_ALWAYS_FLASH</span> + <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls +the camera's flash unit,<wbr/> always firing it for still +captures.<wbr/></p> +<p>The flash may be fired during a precapture sequence +(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and +will always be fired for captures for which the +<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to +STILL_<wbr/>CAPTURE</p></span> + </li> + <li> + <span class="entry_type_enum_name">ON_AUTO_FLASH_REDEYE</span> + <span class="entry_type_enum_notes"><p>Like ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> but with automatic red eye +reduction.<wbr/></p> +<p>If deemed necessary by the camera device,<wbr/> a red eye +reduction flash will fire during the precapture +sequence.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired mode for the camera device's +auto-exposure routine.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.aeAvailableModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is +AUTO.<wbr/></p> +<p>When set to any of the ON modes,<wbr/> the camera device's +auto-exposure routine is enabled,<wbr/> overriding the +application's selected exposure time,<wbr/> sensor sensitivity,<wbr/> +and frame duration (<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> +<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and +<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>).<wbr/> If one of the FLASH modes +is selected,<wbr/> the camera device's flash unit controls are +also overridden.<wbr/></p> +<p>The FLASH modes are only available if the camera device +has a flash unit (<a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> is <code>true</code>).<wbr/></p> +<p>If flash TORCH mode is desired,<wbr/> this field must be set to +ON or OFF,<wbr/> and <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> set to TORCH.<wbr/></p> +<p>When set to any of the ON modes,<wbr/> the values chosen by the +camera device auto-exposure routine for the overridden +fields for a given capture will be available in its +CaptureResult.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.aeRegions"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>ae<wbr/>Regions + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 5 x area_count + </span> + <span class="entry_type_visibility"> [public as meteringRectangle]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of metering areas to use for auto-exposure adjustment.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size + </td> + + <td class="entry_range"> + <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not available if <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a> is 0.<wbr/> +Otherwise will always be present.<wbr/></p> +<p>The maximum number of regions supported by the device is determined by the value +of <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a>.<wbr/></p> +<p>The coordinate system is based on the active pixel array,<wbr/> +with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and +(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/> +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the +bottom-right pixel in the active pixel array.<wbr/></p> +<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight +for every pixel in the area.<wbr/> This means that a large metering area +with the same weight as a smaller area will have more effect in +the metering result.<wbr/> Metering areas can partially overlap and the +camera device will add the weights in the overlap region.<wbr/></p> +<p>The weights are relative to weights of other exposure metering regions,<wbr/> so if only one +region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0 +weight is ignored.<wbr/></p> +<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the +camera device.<wbr/></p> +<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in +capture result metadata,<wbr/> the camera device will ignore the sections outside the crop +region and output only the intersection rectangle as the metering region in the result +metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and +not reported in the result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL level representation of MeteringRectangle[] is a +int[5 * area_<wbr/>count].<wbr/> +Every five elements represent a metering region of +(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/> +The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but +exclusive on xmax and ymax.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.aeTargetFpsRange"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as rangeInt]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Range over which the auto-exposure routine can +adjust the capture frame rate to maintain good +exposure.<wbr/></p> + </td> + + <td class="entry_units"> + Frames per second (FPS) + </td> + + <td class="entry_range"> + <p>Any of the entries in <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Only constrains auto-exposure (AE) algorithm,<wbr/> not +manual control of <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a> and +<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.aePrecaptureTrigger"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">IDLE</span> + <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">START</span> + <span class="entry_type_enum_notes"><p>The precapture metering sequence will be started +by the camera device.<wbr/></p> +<p>The exact effect of the precapture trigger depends on +the current AE mode and state.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CANCEL</span> + <span class="entry_type_enum_notes"><p>The camera device will cancel any currently active or completed +precapture metering sequence,<wbr/> the auto-exposure routine will return to its +initial state.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether the camera device will trigger a precapture +metering sequence when it processes this request.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry is normally set to IDLE,<wbr/> or is not +included at all in the request settings.<wbr/> When included and +set to START,<wbr/> the camera device will trigger the auto-exposure (AE) +precapture metering sequence.<wbr/></p> +<p>When set to CANCEL,<wbr/> the camera device will cancel any active +precapture metering trigger,<wbr/> and return to its initial AE state.<wbr/> +If a precapture metering sequence is already completed,<wbr/> and the camera +device has implicitly locked the AE for subsequent still capture,<wbr/> the +CANCEL trigger will unlock the AE and return to its initial AE state.<wbr/></p> +<p>The precapture sequence should be triggered before starting a +high-quality still capture for final metering decisions to +be made,<wbr/> and for firing pre-capture flash pulses to estimate +scene brightness and required final capture flash power,<wbr/> when +the flash is enabled.<wbr/></p> +<p>Normally,<wbr/> this entry should be set to START for only a +single request,<wbr/> and the application should wait until the +sequence completes before starting a new one.<wbr/></p> +<p>When a precapture metering sequence is finished,<wbr/> the camera device +may lock the auto-exposure routine internally to be able to accurately expose the +subsequent still capture image (<code><a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE</code>).<wbr/> +For this case,<wbr/> the AE may not resume normal scan if no subsequent still capture is +submitted.<wbr/> To ensure that the AE routine restarts normal scan,<wbr/> the application should +submit a request with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == true</code>,<wbr/> followed by a request +with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == false</code>,<wbr/> if the application decides not to submit a +still capture request after the precapture sequence completes.<wbr/> Alternatively,<wbr/> for +API level 23 or newer devices,<wbr/> the CANCEL can be used to unlock the camera device +internally locked AE if the application doesn't submit a still capture request after +the AE precapture trigger.<wbr/> Note that,<wbr/> the CANCEL was added in API level 23,<wbr/> and must not +be used in devices that have earlier API levels.<wbr/></p> +<p>The exact effect of auto-exposure (AE) precapture trigger +depends on the current AE mode and state; see +<a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE precapture state transition +details.<wbr/></p> +<p>On LEGACY-level devices,<wbr/> the precapture trigger is not supported; +capturing a high-resolution JPEG image will automatically trigger a +precapture sequence before the high-resolution capture,<wbr/> including +potentially firing a pre-capture flash.<wbr/></p> +<p>Using the precapture trigger and the auto-focus trigger <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> +simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between +the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a +focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous +trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and +changes to <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> indicating the start of the precapture sequence,<wbr/> for +example.<wbr/></p> +<p>If both the precapture and the auto-focus trigger are activated on the same request,<wbr/> then +the camera device will complete them in the optimal order for that device.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL must support triggering the AE precapture trigger while an AF trigger is active +(and vice versa),<wbr/> or at the same time as the AF trigger.<wbr/> It is acceptable for the HAL to +treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the +AE trigger.<wbr/> Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/> +to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.afMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>af<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>The auto-focus routine does not control the lens; +<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> is controlled by the +application.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AUTO</span> + <span class="entry_type_enum_notes"><p>Basic automatic focus mode.<wbr/></p> +<p>In this mode,<wbr/> the lens does not move unless +the autofocus trigger action is called.<wbr/> When that trigger +is activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to +the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/></p> +<p>Always supported if lens is not fixed focus.<wbr/></p> +<p>Use <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> to determine if lens +is fixed-focus.<wbr/></p> +<p>Triggering AF_<wbr/>CANCEL resets the lens position to default,<wbr/> +and sets the AF state to INACTIVE.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MACRO</span> + <span class="entry_type_enum_notes"><p>Close-up focusing mode.<wbr/></p> +<p>In this mode,<wbr/> the lens does not move unless the +autofocus trigger action is called.<wbr/> When that trigger is +activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to +the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/> This +mode is optimized for focusing on objects very close to +the camera.<wbr/></p> +<p>When that trigger is activated,<wbr/> AF will transition to +ACTIVE_<wbr/>SCAN,<wbr/> then to the outcome of the scan (FOCUSED or +NOT_<wbr/>FOCUSED).<wbr/> Triggering cancel AF resets the lens +position to default,<wbr/> and sets the AF state to +INACTIVE.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CONTINUOUS_VIDEO</span> + <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens +position continually to attempt to provide a +constantly-in-focus image stream.<wbr/></p> +<p>The focusing behavior should be suitable for good quality +video recording; typically this means slower focus +movement and no overshoots.<wbr/> When the AF trigger is not +involved,<wbr/> the AF algorithm should start in INACTIVE state,<wbr/> +and then transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED +states as appropriate.<wbr/> When the AF trigger is activated,<wbr/> +the algorithm should immediately transition into +AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the +lens position until a cancel AF trigger is received.<wbr/></p> +<p>Once cancel is received,<wbr/> the algorithm should transition +back to INACTIVE and resume passive scan.<wbr/> Note that this +behavior is not identical to CONTINUOUS_<wbr/>PICTURE,<wbr/> since an +ongoing PASSIVE_<wbr/>SCAN must immediately be +canceled.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CONTINUOUS_PICTURE</span> + <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens +position continually to attempt to provide a +constantly-in-focus image stream.<wbr/></p> +<p>The focusing behavior should be suitable for still image +capture; typically this means focusing as fast as +possible.<wbr/> When the AF trigger is not involved,<wbr/> the AF +algorithm should start in INACTIVE state,<wbr/> and then +transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED states as +appropriate as it attempts to maintain focus.<wbr/> When the AF +trigger is activated,<wbr/> the algorithm should finish its +PASSIVE_<wbr/>SCAN if active,<wbr/> and then transition into +AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the +lens position until a cancel AF trigger is received.<wbr/></p> +<p>When the AF cancel trigger is activated,<wbr/> the algorithm +should transition back to INACTIVE and then act as if it +has just been started.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">EDOF</span> + <span class="entry_type_enum_notes"><p>Extended depth of field (digital focus) mode.<wbr/></p> +<p>The camera device will produce images with an extended +depth of field automatically; no special focusing +operations need to be done before taking a picture.<wbr/></p> +<p>AF triggers are ignored,<wbr/> and the AF state will always be +INACTIVE.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether auto-focus (AF) is currently enabled,<wbr/> and what +mode it is set to.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.afAvailableModes">android.<wbr/>control.<wbr/>af<wbr/>Available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> = AUTO and the lens is not fixed focus +(i.<wbr/>e.<wbr/> <code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> > 0</code>).<wbr/> Also note that +when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/> the behavior of AF is device +dependent.<wbr/> It is recommended to lock AF by using <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> before +setting <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> to OFF,<wbr/> or set AF mode to OFF when AE is OFF.<wbr/></p> +<p>If the lens is controlled by the camera device auto-focus algorithm,<wbr/> +the camera device will report the current AF status in <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> +in result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When afMode is AUTO or MACRO,<wbr/> the lens must not move until an AF trigger is sent in a +request (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> <code>==</code> START).<wbr/> After an AF trigger,<wbr/> the afState will end +up with either FOCUSED_<wbr/>LOCKED or NOT_<wbr/>FOCUSED_<wbr/>LOCKED state (see +<a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> which indicates that the lens is +locked and will not move.<wbr/> If camera movement (e.<wbr/>g.<wbr/> tilting camera) causes the lens to move +after the lens is locked,<wbr/> the HAL must compensate this movement appropriately such that +the same focal plane remains in focus.<wbr/></p> +<p>When afMode is one of the continuous auto focus modes,<wbr/> the HAL is free to start a AF +scan whenever it's not locked.<wbr/> When the lens is locked after an AF trigger +(see <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> the HAL should maintain the +same lock behavior as above.<wbr/></p> +<p>When afMode is OFF,<wbr/> the application controls focus manually.<wbr/> The accuracy of the +focus distance control depends on the <a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a>.<wbr/> +However,<wbr/> the lens must not move regardless of the camera movement for any focus distance +manual control.<wbr/></p> +<p>To put this in concrete terms,<wbr/> if the camera has lens elements which may move based on +camera orientation or motion (e.<wbr/>g.<wbr/> due to gravity),<wbr/> then the HAL must drive the lens to +remain in a fixed position invariant to the camera's orientation or motion,<wbr/> for example,<wbr/> +by using accelerometer measurements in the lens control logic.<wbr/> This is a typical issue +that will arise on camera modules with open-loop VCMs.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.afRegions"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>af<wbr/>Regions + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 5 x area_count + </span> + <span class="entry_type_visibility"> [public as meteringRectangle]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of metering areas to use for auto-focus.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size + </td> + + <td class="entry_range"> + <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not available if <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a> is 0.<wbr/> +Otherwise will always be present.<wbr/></p> +<p>The maximum number of focus areas supported by the device is determined by the value +of <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a>.<wbr/></p> +<p>The coordinate system is based on the active pixel array,<wbr/> +with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and +(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/> +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the +bottom-right pixel in the active pixel array.<wbr/></p> +<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight +for every pixel in the area.<wbr/> This means that a large metering area +with the same weight as a smaller area will have more effect in +the metering result.<wbr/> Metering areas can partially overlap and the +camera device will add the weights in the overlap region.<wbr/></p> +<p>The weights are relative to weights of other metering regions,<wbr/> so if only one region +is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0 weight is +ignored.<wbr/></p> +<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the +camera device.<wbr/></p> +<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in +capture result metadata,<wbr/> the camera device will ignore the sections outside the crop +region and output only the intersection rectangle as the metering region in the result +metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and +not reported in the result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL level representation of MeteringRectangle[] is a +int[5 * area_<wbr/>count].<wbr/> +Every five elements represent a metering region of +(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/> +The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but +exclusive on xmax and ymax.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.afTrigger"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>af<wbr/>Trigger + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">IDLE</span> + <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">START</span> + <span class="entry_type_enum_notes"><p>Autofocus will trigger now.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CANCEL</span> + <span class="entry_type_enum_notes"><p>Autofocus will return to its initial +state,<wbr/> and cancel any currently active trigger.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether the camera device will trigger autofocus for this request.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry is normally set to IDLE,<wbr/> or is not +included at all in the request settings.<wbr/></p> +<p>When included and set to START,<wbr/> the camera device will trigger the +autofocus algorithm.<wbr/> If autofocus is disabled,<wbr/> this trigger has no effect.<wbr/></p> +<p>When set to CANCEL,<wbr/> the camera device will cancel any active trigger,<wbr/> +and return to its initial AF state.<wbr/></p> +<p>Generally,<wbr/> applications should set this entry to START or CANCEL for only a +single capture,<wbr/> and then return it to IDLE (or not set at all).<wbr/> Specifying +START for multiple captures in a row means restarting the AF operation over +and over again.<wbr/></p> +<p>See <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for what the trigger means for each AF mode.<wbr/></p> +<p>Using the autofocus trigger and the precapture trigger <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> +simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between +the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a +focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous +trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and +changes to <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>,<wbr/> for example.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL must support triggering the AF trigger while an AE precapture trigger is active +(and vice versa),<wbr/> or at the same time as the AE trigger.<wbr/> It is acceptable for the HAL to +treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the +AE trigger.<wbr/> Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/> +to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.awbLock"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>awb<wbr/>Lock + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Auto-white balance lock is disabled; the AWB +algorithm is free to update its parameters if in AUTO +mode.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Auto-white balance lock is enabled; the AWB +algorithm will not update its parameters while the lock +is active.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether auto-white balance (AWB) is currently locked to its +latest calculated values.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to <code>true</code> (ON),<wbr/> the AWB algorithm is locked to its latest parameters,<wbr/> +and will not change color balance settings until the lock is set to <code>false</code> (OFF).<wbr/></p> +<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that +get locked do not necessarily correspond to the settings that were present in the +latest capture result received from the camera device,<wbr/> since additional captures +and AWB updates may have occurred even before the result was sent out.<wbr/> If an +application is switching between automatic and manual control and wishes to eliminate +any flicker during the switch,<wbr/> the following procedure is recommended:</p> +<ol> +<li>Starting in auto-AWB mode:</li> +<li>Lock AWB</li> +<li>Wait for the first result to be output that has the AWB locked</li> +<li>Copy AWB settings from that result into a request,<wbr/> set the request to manual AWB</li> +<li>Submit the capture request,<wbr/> proceed to run manual AWB as desired.<wbr/></li> +</ol> +<p>Note that AWB lock is only meaningful when +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> is in the AUTO mode; in other modes,<wbr/> +AWB is already fixed to a specific setting.<wbr/></p> +<p>Some LEGACY devices may not support ON; the value is then overridden to OFF.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.awbMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>awb<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled.<wbr/></p> +<p>The application-selected color transform matrix +(<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>) and gains +(<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>) are used by the camera +device for manual white balance control.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AUTO</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is active.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">INCANDESCENT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses incandescent light as the assumed scene +illumination for white balance.<wbr/></p> +<p>While the exact white balance transforms are up to the +camera device,<wbr/> they will approximately match the CIE +standard illuminant A.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FLUORESCENT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses fluorescent light as the assumed scene +illumination for white balance.<wbr/></p> +<p>While the exact white balance transforms are up to the +camera device,<wbr/> they will approximately match the CIE +standard illuminant F2.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">WARM_FLUORESCENT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses warm fluorescent light as the assumed scene +illumination for white balance.<wbr/></p> +<p>While the exact white balance transforms are up to the +camera device,<wbr/> they will approximately match the CIE +standard illuminant F4.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">DAYLIGHT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses daylight light as the assumed scene +illumination for white balance.<wbr/></p> +<p>While the exact white balance transforms are up to the +camera device,<wbr/> they will approximately match the CIE +standard illuminant D65.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CLOUDY_DAYLIGHT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses cloudy daylight light as the assumed scene +illumination for white balance.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">TWILIGHT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses twilight light as the assumed scene +illumination for white balance.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SHADE</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses shade light as the assumed scene +illumination for white balance.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether auto-white balance (AWB) is currently setting the color +transform fields,<wbr/> and what its illumination target +is.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.awbAvailableModes">android.<wbr/>control.<wbr/>awb<wbr/>Available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is AUTO.<wbr/></p> +<p>When set to the ON mode,<wbr/> the camera device's auto-white balance +routine is enabled,<wbr/> overriding the application's selected +<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and +<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/> Note that when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> +is OFF,<wbr/> the behavior of AWB is device dependent.<wbr/> It is recommened to +also set AWB mode to OFF or lock AWB by using <a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> before +setting AE mode to OFF.<wbr/></p> +<p>When set to the OFF mode,<wbr/> the camera device's auto-white balance +routine is disabled.<wbr/> The application manually controls the white +balance by <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> +and <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/></p> +<p>When set to any other modes,<wbr/> the camera device's auto-white +balance routine is disabled.<wbr/> The camera device uses each +particular illumination target for white balance +adjustment.<wbr/> The application's values for +<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> +<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and +<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> are ignored.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.awbRegions"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>awb<wbr/>Regions + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 5 x area_count + </span> + <span class="entry_type_visibility"> [public as meteringRectangle]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of metering areas to use for auto-white-balance illuminant +estimation.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size + </td> + + <td class="entry_range"> + <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not available if <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a> is 0.<wbr/> +Otherwise will always be present.<wbr/></p> +<p>The maximum number of regions supported by the device is determined by the value +of <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a>.<wbr/></p> +<p>The coordinate system is based on the active pixel array,<wbr/> +with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and +(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/> +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the +bottom-right pixel in the active pixel array.<wbr/></p> +<p>The weight must range from 0 to 1000,<wbr/> and represents a weight +for every pixel in the area.<wbr/> This means that a large metering area +with the same weight as a smaller area will have more effect in +the metering result.<wbr/> Metering areas can partially overlap and the +camera device will add the weights in the overlap region.<wbr/></p> +<p>The weights are relative to weights of other white balance metering regions,<wbr/> so if +only one region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with +0 weight is ignored.<wbr/></p> +<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the +camera device.<wbr/></p> +<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in +capture result metadata,<wbr/> the camera device will ignore the sections outside the crop +region and output only the intersection rectangle as the metering region in the result +metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and +not reported in the result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL level representation of MeteringRectangle[] is a +int[5 * area_<wbr/>count].<wbr/> +Every five elements represent a metering region of +(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/> +The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but +exclusive on xmax and ymax.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.captureIntent"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>capture<wbr/>Intent + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">CUSTOM</span> + <span class="entry_type_enum_notes"><p>The goal of this request doesn't fall into the other +categories.<wbr/> The camera device will default to preview-like +behavior.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PREVIEW</span> + <span class="entry_type_enum_notes"><p>This request is for a preview-like use case.<wbr/></p> +<p>The precapture trigger may be used to start off a metering +w/<wbr/>flash sequence.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">STILL_CAPTURE</span> + <span class="entry_type_enum_notes"><p>This request is for a still capture-type +use case.<wbr/></p> +<p>If the flash unit is under automatic control,<wbr/> it may fire as needed.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">VIDEO_RECORD</span> + <span class="entry_type_enum_notes"><p>This request is for a video recording +use case.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">VIDEO_SNAPSHOT</span> + <span class="entry_type_enum_notes"><p>This request is for a video snapshot (still +image while recording video) use case.<wbr/></p> +<p>The camera device should take the highest-quality image +possible (given the other settings) without disrupting the +frame rate of video recording.<wbr/> </p></span> + </li> + <li> + <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span> + <span class="entry_type_enum_notes"><p>This request is for a ZSL usecase; the +application will stream full-resolution images and +reprocess one or several later for a final +capture.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MANUAL</span> + <span class="entry_type_enum_notes"><p>This request is for manual capture use case where +the applications want to directly control the capture parameters.<wbr/></p> +<p>For example,<wbr/> the application may wish to manually control +<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> etc.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Information to the camera device 3A (auto-exposure,<wbr/> +auto-focus,<wbr/> auto-white balance) routines about the purpose +of this capture,<wbr/> to help the camera device to decide optimal 3A +strategy.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control (except for MANUAL) is only effective if +<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> != OFF</code> and any 3A routine is active.<wbr/></p> +<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG will be supported if <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> +contains PRIVATE_<wbr/>REPROCESSING or YUV_<wbr/>REPROCESSING.<wbr/> MANUAL will be supported if +<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains MANUAL_<wbr/>SENSOR.<wbr/> Other intent values are +always supported.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.effectMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>effect<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No color effect will be applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MONO</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "monocolor" effect where the image is mapped into +a single color.<wbr/></p> +<p>This will typically be grayscale.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">NEGATIVE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "photo-negative" effect where the image's colors +are inverted.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SOLARIZE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "solarisation" effect (Sabattier effect) where the +image is wholly or partially reversed in +tone.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SEPIA</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "sepia" effect where the image is mapped into warm +gray,<wbr/> red,<wbr/> and brown tones.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">POSTERIZE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "posterization" effect where the image uses +discrete regions of tone rather than a continuous +gradient of tones.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">WHITEBOARD</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "whiteboard" effect where the image is typically displayed +as regions of white,<wbr/> with black or grey details.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">BLACKBOARD</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "blackboard" effect where the image is typically displayed +as regions of black,<wbr/> with white or grey details.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AQUA</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>An "aqua" effect where a blue hue is added to the image.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A special color effect to apply.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.availableEffects">android.<wbr/>control.<wbr/>available<wbr/>Effects</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When this mode is set,<wbr/> a color effect will be applied +to images produced by the camera device.<wbr/> The interpretation +and implementation of these color effects is left to the +implementor of the camera device,<wbr/> and should not be +depended on to be consistent (or present) across all +devices.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Full application control of pipeline.<wbr/></p> +<p>All control by the device's metering and focusing (3A) +routines is disabled,<wbr/> and no other settings in +android.<wbr/>control.<wbr/>* have any effect,<wbr/> except that +<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> may be used by the camera +device to select post-processing values for processing +blocks that do not allow for manual control,<wbr/> or are not +exposed by the camera API.<wbr/></p> +<p>However,<wbr/> the camera device's 3A routines may continue to +collect statistics and update their internal state so that +when control is switched to AUTO mode,<wbr/> good control values +can be immediately applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AUTO</span> + <span class="entry_type_enum_notes"><p>Use settings for each individual 3A routine.<wbr/></p> +<p>Manual control of capture parameters is disabled.<wbr/> All +controls in android.<wbr/>control.<wbr/>* besides sceneMode take +effect.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">USE_SCENE_MODE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Use a specific scene mode.<wbr/></p> +<p>Enabling this disables control.<wbr/>aeMode,<wbr/> control.<wbr/>awbMode and +control.<wbr/>afMode controls; the camera device will ignore +those settings while USE_<wbr/>SCENE_<wbr/>MODE is active (except for +FACE_<wbr/>PRIORITY scene mode).<wbr/> Other control entries are still active.<wbr/> +This setting can only be used if scene mode is supported (i.<wbr/>e.<wbr/> +<a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a> +contain some modes other than DISABLED).<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">OFF_KEEP_STATE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Same as OFF mode,<wbr/> except that this capture will not be +used by camera device background auto-exposure,<wbr/> auto-white balance and +auto-focus algorithms (3A) to update their statistics.<wbr/></p> +<p>Specifically,<wbr/> the 3A routines are locked to the last +values set from a request with AUTO,<wbr/> OFF,<wbr/> or +USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> and any statistics or state updates +collected from manual captures with OFF_<wbr/>KEEP_<wbr/>STATE will be +discarded by the camera device.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Overall mode of 3A (auto-exposure,<wbr/> auto-white-balance,<wbr/> auto-focus) control +routines.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.availableModes">android.<wbr/>control.<wbr/>available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is a top-level 3A control switch.<wbr/> When set to OFF,<wbr/> all 3A control +by the camera device is disabled.<wbr/> The application must set the fields for +capture parameters itself.<wbr/></p> +<p>When set to AUTO,<wbr/> the individual algorithm controls in +android.<wbr/>control.<wbr/>* are in effect,<wbr/> such as <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>.<wbr/></p> +<p>When set to USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> the individual controls in +android.<wbr/>control.<wbr/>* are mostly disabled,<wbr/> and the camera device implements +one of the scene mode settings (such as ACTION,<wbr/> SUNSET,<wbr/> or PARTY) +as it wishes.<wbr/> The camera device scene mode 3A settings are provided by +<a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">capture results</a>.<wbr/></p> +<p>When set to OFF_<wbr/>KEEP_<wbr/>STATE,<wbr/> it is similar to OFF mode,<wbr/> the only difference +is that this frame will not be used by camera device background 3A statistics +update,<wbr/> as if this frame is never captured.<wbr/> This mode can be used in the scenario +where the application doesn't want a 3A manual control capture to affect +the subsequent auto 3A capture results.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.sceneMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>scene<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">DISABLED</span> + <span class="entry_type_enum_value">0</span> + <span class="entry_type_enum_notes"><p>Indicates that no scene modes are set for a given capture request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FACE_PRIORITY</span> + <span class="entry_type_enum_notes"><p>If face detection support exists,<wbr/> use face +detection data for auto-focus,<wbr/> auto-white balance,<wbr/> and +auto-exposure routines.<wbr/></p> +<p>If face detection statistics are disabled +(i.<wbr/>e.<wbr/> <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> is set to OFF),<wbr/> +this should still operate correctly (but will not return +face detection statistics to the framework).<wbr/></p> +<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> +remain active when FACE_<wbr/>PRIORITY is set.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ACTION</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving objects.<wbr/></p> +<p>Similar to SPORTS.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PORTRAIT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for still photos of people.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">LANDSCAPE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for photos of distant macroscopic objects.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">NIGHT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for low-light settings.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">NIGHT_PORTRAIT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for still photos of people in low-light +settings.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">THEATRE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings where flash must +remain off.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">BEACH</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor beach settings.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SNOW</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor settings containing snow.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SUNSET</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for scenes of the setting sun.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">STEADYPHOTO</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized to avoid blurry photos due to small amounts of +device motion (for example: due to hand shake).<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FIREWORKS</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for nighttime photos of fireworks.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SPORTS</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving people.<wbr/></p> +<p>Similar to ACTION.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PARTY</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings with multiple moving +people.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CANDLELIGHT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for dim settings where the main light source +is a flame.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">BARCODE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for accurately capturing a photo of barcode +for use by camera applications that wish to read the +barcode value.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_SPEED_VIDEO</span> + <span class="entry_type_enum_deprecated">[deprecated]</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>This is deprecated,<wbr/> please use <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a> +and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a> +for high speed video recording.<wbr/></p> +<p>Optimized for high speed video recording (frame rate >=60fps) use case.<wbr/></p> +<p>The supported high speed video sizes and fps ranges are specified in +<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> To get desired +output frame rates,<wbr/> the application is only allowed to select video size +and fps range combinations listed in this static metadata.<wbr/> The fps range +can be control via <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a>.<wbr/></p> +<p>In this mode,<wbr/> the camera device will override aeMode,<wbr/> awbMode,<wbr/> and afMode to +ON,<wbr/> ON,<wbr/> and CONTINUOUS_<wbr/>VIDEO,<wbr/> respectively.<wbr/> All post-processing block mode +controls will be overridden to be FAST.<wbr/> Therefore,<wbr/> no manual control of capture +and post-processing parameters is possible.<wbr/> All other controls operate the +same as when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == AUTO.<wbr/> This means that all other +android.<wbr/>control.<wbr/>* fields continue to work,<wbr/> such as</p> +<ul> +<li><a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a></li> +<li><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a></li> +<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li> +<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li> +<li><a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></li> +<li><a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a></li> +<li><a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a></li> +<li><a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a></li> +<li><a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a></li> +<li><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a></li> +</ul> +<p>Outside of android.<wbr/>control.<wbr/>*,<wbr/> the following controls will work:</p> +<ul> +<li><a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> (automatic flash for still capture will not work since aeMode is ON)</li> +<li><a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> (if it is supported)</li> +<li><a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a></li> +<li><a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a></li> +</ul> +<p>For high speed recording use case,<wbr/> the actual maximum supported frame rate may +be lower than what camera can output,<wbr/> depending on the destination Surfaces for +the image data.<wbr/> For example,<wbr/> if the destination surface is from video encoder,<wbr/> +the application need check if the video encoder is capable of supporting the +high frame rate for a given video size,<wbr/> or it will end up with lower recording +frame rate.<wbr/> If the destination surface is from preview window,<wbr/> the preview frame +rate will be bounded by the screen refresh rate.<wbr/></p> +<p>The camera device will only support up to 2 output high speed streams +(processed non-stalling format defined in <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>) +in this mode.<wbr/> This control will be effective only if all of below conditions are true:</p> +<ul> +<li>The application created no more than maxNumHighSpeedStreams processed non-stalling +format output streams,<wbr/> where maxNumHighSpeedStreams is calculated as +min(2,<wbr/> <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>[Processed (but not-stalling)]).<wbr/></li> +<li>The stream sizes are selected from the sizes reported by +<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/></li> +<li>No processed non-stalling or raw streams are configured.<wbr/></li> +</ul> +<p>When above conditions are NOT satistied,<wbr/> the controls of this mode and +<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> will be ignored by the camera device,<wbr/> +the camera device will fall back to <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> <code>==</code> AUTO,<wbr/> +and the returned capture result metadata will give the fps range choosen +by the camera device.<wbr/></p> +<p>Switching into or out of this mode may trigger some camera ISP/<wbr/>sensor +reconfigurations,<wbr/> which may introduce extra latency.<wbr/> It is recommended that +the application avoids unnecessary scene mode switch as much as possible.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HDR</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Turn on a device-specific high dynamic range (HDR) mode.<wbr/></p> +<p>In this scene mode,<wbr/> the camera device captures images +that keep a larger range of scene illumination levels +visible in the final image.<wbr/> For example,<wbr/> when taking a +picture of a object in front of a bright window,<wbr/> both +the object and the scene through the window may be +visible when using HDR mode,<wbr/> while in normal AUTO mode,<wbr/> +one or the other may be poorly exposed.<wbr/> As a tradeoff,<wbr/> +HDR mode generally takes much longer to capture a single +image,<wbr/> has no user control,<wbr/> and may have other artifacts +depending on the HDR method used.<wbr/></p> +<p>Therefore,<wbr/> HDR captures operate at a much slower rate +than regular captures.<wbr/></p> +<p>In this mode,<wbr/> on LIMITED or FULL devices,<wbr/> when a request +is made with a <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> of +STILL_<wbr/>CAPTURE,<wbr/> the camera device will capture an image +using a high dynamic range capture technique.<wbr/> On LEGACY +devices,<wbr/> captures that target a JPEG-format output will +be captured with HDR,<wbr/> and the capture intent is not +relevant.<wbr/></p> +<p>The HDR capture may involve the device capturing a burst +of images internally and combining them into one,<wbr/> or it +may involve the device using specialized high dynamic +range capture hardware.<wbr/> In all cases,<wbr/> a single image is +produced in response to a capture request submitted +while in HDR mode.<wbr/></p> +<p>Since substantial post-processing is generally needed to +produce an HDR image,<wbr/> only YUV,<wbr/> PRIVATE,<wbr/> and JPEG +outputs are supported for LIMITED/<wbr/>FULL device HDR +captures,<wbr/> and only JPEG outputs are supported for LEGACY +HDR captures.<wbr/> Using a RAW output for HDR capture is not +supported.<wbr/></p> +<p>Some devices may also support always-on HDR,<wbr/> which +applies HDR processing at full frame rate.<wbr/> For these +devices,<wbr/> intents other than STILL_<wbr/>CAPTURE will also +produce an HDR output with no frame rate impact compared +to normal operation,<wbr/> though the quality may be lower +than for STILL_<wbr/>CAPTURE intents.<wbr/></p> +<p>If SCENE_<wbr/>MODE_<wbr/>HDR is used with unsupported output types +or capture intents,<wbr/> the images captured will be as if +the SCENE_<wbr/>MODE was not enabled at all.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FACE_PRIORITY_LOW_LIGHT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_hidden">[hidden]</span> + <span class="entry_type_enum_notes"><p>Same as FACE_<wbr/>PRIORITY scene mode,<wbr/> except that the camera +device will choose higher sensitivity values (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>) +under low light conditions.<wbr/></p> +<p>The camera device may be tuned to expose the images in a reduced +sensitivity range to produce the best quality images.<wbr/> For example,<wbr/> +if the <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> gives range of [100,<wbr/> 1600],<wbr/> +the camera device auto-exposure routine tuning process may limit the actual +exposure sensitivity range to [100,<wbr/> 1200] to ensure that the noise level isn't +exessive in order to preserve the image quality.<wbr/> Under this situation,<wbr/> the image under +low light may be under-exposed when the sensor max exposure time (bounded by the +<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of the +ON_<wbr/>* modes) and effective max sensitivity are reached.<wbr/> This scene mode allows the +camera device auto-exposure routine to increase the sensitivity up to the max +sensitivity specified by <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> when the scene is too +dark and the max exposure time is reached.<wbr/> The captured images may be noisier +compared with the images captured in normal FACE_<wbr/>PRIORITY mode; therefore,<wbr/> it is +recommended that the application only use this scene mode when it is capable of +reducing the noise level of the captured images.<wbr/></p> +<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> +remain active when FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT is set.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">DEVICE_CUSTOM_START</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_hidden">[hidden]</span> + <span class="entry_type_enum_value">100</span> + <span class="entry_type_enum_notes"><p>Scene mode values within the range of +<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific +customized scene modes.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">DEVICE_CUSTOM_END</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_hidden">[hidden]</span> + <span class="entry_type_enum_value">127</span> + <span class="entry_type_enum_notes"><p>Scene mode values within the range of +<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific +customized scene modes.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Control for which scene mode is currently active.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Scene modes are custom camera modes optimized for a certain set of conditions and +capture settings.<wbr/></p> +<p>This is the mode that that is active when +<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code>.<wbr/> Aside from FACE_<wbr/>PRIORITY,<wbr/> these modes will +disable <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> +while in use.<wbr/></p> +<p>The interpretation and implementation of these scene modes is left +to the implementor of the camera device.<wbr/> Their behavior will not be +consistent across all devices,<wbr/> and any given device may only implement +a subset of these modes.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL implementations that include scene modes are expected to provide +the per-scene settings to use for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> in +<a href="#static_android.control.sceneModeOverrides">android.<wbr/>control.<wbr/>scene<wbr/>Mode<wbr/>Overrides</a>.<wbr/></p> +<p>For HIGH_<wbr/>SPEED_<wbr/>VIDEO mode,<wbr/> if it is included in <a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>,<wbr/> +the HAL must list supported video size and fps range in +<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> For a given size,<wbr/> e.<wbr/>g.<wbr/> +1280x720,<wbr/> if the HAL has two different sensor configurations for normal streaming +mode and high speed streaming,<wbr/> when this scene mode is set/<wbr/>reset in a sequence of capture +requests,<wbr/> the HAL may have to switch between different sensor modes.<wbr/> +This mode is deprecated in HAL3.<wbr/>3,<wbr/> to support high speed video recording,<wbr/> please implement +<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a> and CONSTRAINED_<wbr/>HIGH_<wbr/>SPEED_<wbr/>VIDEO +capbility defined in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.videoStabilizationMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Video stabilization is disabled.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Video stabilization is enabled.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether video stabilization is +active.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Video stabilization automatically warps images from +the camera in order to stabilize motion between consecutive frames.<wbr/></p> +<p>If enabled,<wbr/> video stabilization can modify the +<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> to keep the video stream stabilized.<wbr/></p> +<p>Switching between different video stabilization modes may take several +frames to initialize,<wbr/> the camera device will report the current mode +in capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/> +the video stabilization modes in the first several capture results may +still be "OFF",<wbr/> and it will become "ON" when the initialization is +done.<wbr/></p> +<p>In addition,<wbr/> not all recording sizes or frame rates may be supported for +stabilization by a device that reports stabilization support.<wbr/> It is guaranteed +that an output targeting a MediaRecorder or MediaCodec will be stabilized if +the recording resolution is less than or equal to 1920 x 1080 (width less than +or equal to 1920,<wbr/> height less than or equal to 1080),<wbr/> and the recording +frame rate is less than or equal to 30fps.<wbr/> At other sizes,<wbr/> the CaptureResult +<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a> field will return +OFF if the recording output is not stabilized,<wbr/> or if there are no output +Surface types that can be stabilized.<wbr/></p> +<p>If a camera device supports both this mode and OIS +(<a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may +produce undesirable interaction,<wbr/> so it is recommended not to enable +both at the same time.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.control.postRawSensitivityBoost"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The amount of additional sensitivity boost applied to output images +after RAW sensor data is captured.<wbr/></p> + </td> + + <td class="entry_units"> + ISO arithmetic units,<wbr/> the same as android.<wbr/>sensor.<wbr/>sensitivity + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.postRawSensitivityBoostRange">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost<wbr/>Range</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Some camera devices support additional digital sensitivity boosting in the +camera processing pipeline after sensor RAW image is captured.<wbr/> +Such a boost will be applied to YUV/<wbr/>JPEG format output images but will not +have effect on RAW output formats like RAW_<wbr/>SENSOR,<wbr/> RAW10,<wbr/> RAW12 or RAW_<wbr/>OPAQUE.<wbr/></p> +<p>This key will be <code>null</code> for devices that do not support any RAW format +outputs.<wbr/> For devices that do support RAW format outputs,<wbr/> this key will always +present,<wbr/> and if a device does not support post RAW sensitivity boost,<wbr/> it will +list <code>100</code> in this key.<wbr/></p> +<p>If the camera device cannot apply the exact boost requested,<wbr/> it will reduce the +boost to the nearest supported value.<wbr/> +The final boost value used will be available in the output capture result.<wbr/></p> +<p>For devices that support post RAW sensitivity boost,<wbr/> the YUV/<wbr/>JPEG output images +of such device will have the total sensitivity of +<code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> * <a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> /<wbr/> 100</code> +The sensitivity of RAW format images will always be <code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></code></p> +<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to +OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.control.aeAvailableAntibandingModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of auto-exposure antibanding modes for <a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> that are +supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not all of the auto-exposure anti-banding modes may be +supported by a given camera device.<wbr/> This field lists the +valid anti-banding modes that the application may request +for this camera device with the +<a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> control.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.aeAvailableModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of auto-exposure modes for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> that are supported by this camera +device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not all the auto-exposure modes may be supported by a +given camera device,<wbr/> especially if no flash unit is +available.<wbr/> This entry lists the valid modes for +<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> for this camera device.<wbr/></p> +<p>All camera devices support ON,<wbr/> and all camera devices with flash +units support ON_<wbr/>AUTO_<wbr/>FLASH and ON_<wbr/>ALWAYS_<wbr/>FLASH.<wbr/></p> +<p>FULL mode camera devices always support OFF mode,<wbr/> +which enables application control of camera exposure time,<wbr/> +sensitivity,<wbr/> and frame duration.<wbr/></p> +<p>LEGACY mode camera devices never support OFF mode.<wbr/> +LIMITED mode devices support OFF if they support the MANUAL_<wbr/>SENSOR +capability.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.aeAvailableTargetFpsRanges"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 x n + </span> + <span class="entry_type_visibility"> [public as rangeInt]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">list of pairs of frame rates</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of frame rate ranges for <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> supported by +this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + Frames per second (FPS) + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For devices at the LEGACY level or above:</p> +<ul> +<li> +<p>For constant-framerate recording,<wbr/> for each normal +<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a>,<wbr/> that is,<wbr/> a +<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a> that has +<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#quality">quality</a> in +the range [<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_LOW">QUALITY_<wbr/>LOW</a>,<wbr/> +<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_2160P">QUALITY_<wbr/>2160P</a>],<wbr/> if the profile is +supported by the device and has +<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#videoFrameRate">videoFrameRate</a> <code>x</code>,<wbr/> this list will +always include (<code>x</code>,<wbr/><code>x</code>).<wbr/></p> +</li> +<li> +<p>Also,<wbr/> a camera device must either not support any +<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a>,<wbr/> +or support at least one +normal <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a> that has +<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#videoFrameRate">videoFrameRate</a> <code>x</code> >= 24.<wbr/></p> +</li> +</ul> +<p>For devices at the LIMITED level or above:</p> +<ul> +<li>For YUV_<wbr/>420_<wbr/>888 burst capture use case,<wbr/> this list will always include (<code>min</code>,<wbr/> <code>max</code>) +and (<code>max</code>,<wbr/> <code>max</code>) where <code>min</code> <= 15 and <code>max</code> = the maximum output frame rate of the +maximum YUV_<wbr/>420_<wbr/>888 output size.<wbr/></li> +</ul> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.aeCompensationRange"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as rangeInt]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Maximum and minimum exposure compensation values for +<a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a>,<wbr/> in counts of <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a>,<wbr/> +that are supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Range [0,<wbr/>0] indicates that exposure compensation is not supported.<wbr/></p> +<p>For LIMITED and FULL devices,<wbr/> range must follow below requirements if exposure +compensation is supported (<code>range != [0,<wbr/> 0]</code>):</p> +<p><code>Min.<wbr/>exposure compensation * <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> <= -2 EV</code></p> +<p><code>Max.<wbr/>exposure compensation * <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> >= 2 EV</code></p> +<p>LEGACY devices may support a smaller range than this.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.aeCompensationStep"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Smallest step by which the exposure compensation +can be changed.<wbr/></p> + </td> + + <td class="entry_units"> + Exposure Value (EV) + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is the unit for <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a>.<wbr/> For example,<wbr/> if this key has +a value of <code>1/<wbr/>2</code>,<wbr/> then a setting of <code>-2</code> for <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> means +that the target EV offset for the auto-exposure routine is -1 EV.<wbr/></p> +<p>One unit of EV compensation changes the brightness of the captured image by a factor +of two.<wbr/> +1 EV doubles the image brightness,<wbr/> while -1 EV halves the image brightness.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This must be less than or equal to 1/<wbr/>2.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.afAvailableModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>af<wbr/>Available<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">List of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of auto-focus (AF) modes for <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> that are +supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not all the auto-focus modes may be supported by a +given camera device.<wbr/> This entry lists the valid modes for +<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> for this camera device.<wbr/></p> +<p>All LIMITED and FULL mode camera devices will support OFF mode,<wbr/> and all +camera devices with adjustable focuser units +(<code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> > 0</code>) will support AUTO mode.<wbr/></p> +<p>LEGACY devices will support OFF mode only if they support +focusing to infinity (by also setting <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> to +<code>0.<wbr/>0f</code>).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.availableEffects"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>available<wbr/>Effects + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">List of enums (android.<wbr/>control.<wbr/>effect<wbr/>Mode).<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of color effects for <a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a> that are supported by this camera +device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This list contains the color effect modes that can be applied to +images produced by the camera device.<wbr/> +Implementations are not expected to be consistent across all devices.<wbr/> +If no color effect modes are available for a device,<wbr/> this will only list +OFF.<wbr/></p> +<p>A color effect will only be applied if +<a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> != OFF.<wbr/> OFF is always included in this list.<wbr/></p> +<p>This control has no effect on the operation of other control routines such +as auto-exposure,<wbr/> white balance,<wbr/> or focus.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.availableSceneModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">List of enums (android.<wbr/>control.<wbr/>scene<wbr/>Mode).<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of scene modes for <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> that are supported by this camera +device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This list contains scene modes that can be set for the camera device.<wbr/> +Only scene modes that have been fully implemented for the +camera device may be included here.<wbr/> Implementations are not expected +to be consistent across all devices.<wbr/></p> +<p>If no scene modes are supported by the camera device,<wbr/> this +will be set to DISABLED.<wbr/> Otherwise DISABLED will not be listed.<wbr/></p> +<p>FACE_<wbr/>PRIORITY is always listed if face detection is +supported (i.<wbr/>e.<wbr/><code><a href="#static_android.statistics.info.maxFaceCount">android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Face<wbr/>Count</a> > +0</code>).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.availableVideoStabilizationModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>available<wbr/>Video<wbr/>Stabilization<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">List of enums.<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of video stabilization modes for <a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a> +that are supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>OFF will always be listed.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.awbAvailableModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>awb<wbr/>Available<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">List of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of auto-white-balance modes for <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> that are supported by this +camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not all the auto-white-balance modes may be supported by a +given camera device.<wbr/> This entry lists the valid modes for +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> for this camera device.<wbr/></p> +<p>All camera devices will support ON mode.<wbr/></p> +<p>Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always support OFF +mode,<wbr/> which enables application control of white balance,<wbr/> by using +<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>(<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> must be set to TRANSFORM_<wbr/>MATRIX).<wbr/> This includes all FULL +mode camera devices.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.maxRegions"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>control.<wbr/>max<wbr/>Regions + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of the maximum number of regions that can be used for metering in +auto-exposure (AE),<wbr/> auto-white balance (AWB),<wbr/> and auto-focus (AF); +this corresponds to the the maximum number of elements in +<a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a>,<wbr/> <a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a>,<wbr/> +and <a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a>.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Value must be >= 0 for each element.<wbr/> For full-capability devices +this value must be >= 1 for AE and AF.<wbr/> The order of the elements is: +<code>(AE,<wbr/> AWB,<wbr/> AF)</code>.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.maxRegionsAe"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [java_public]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum number of metering regions that can be used by the auto-exposure (AE) +routine.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Value will be >= 0.<wbr/> For FULL-capability devices,<wbr/> this +value will be >= 1.<wbr/></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This corresponds to the the maximum allowed number of elements in +<a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry is private to the framework.<wbr/> Fill in +maxRegions to have this entry be automatically populated.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.maxRegionsAwb"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [java_public]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum number of metering regions that can be used by the auto-white balance (AWB) +routine.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Value will be >= 0.<wbr/></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This corresponds to the the maximum allowed number of elements in +<a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry is private to the framework.<wbr/> Fill in +maxRegions to have this entry be automatically populated.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.maxRegionsAf"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [java_public]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum number of metering regions that can be used by the auto-focus (AF) routine.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Value will be >= 0.<wbr/> For FULL-capability devices,<wbr/> this +value will be >= 1.<wbr/></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This corresponds to the the maximum allowed number of elements in +<a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry is private to the framework.<wbr/> Fill in +maxRegions to have this entry be automatically populated.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.sceneModeOverrides"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>scene<wbr/>Mode<wbr/>Overrides + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x length(availableSceneModes) + </span> + <span class="entry_type_visibility"> [system]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Ordered list of auto-exposure,<wbr/> auto-white balance,<wbr/> and auto-focus +settings to use with each available scene mode.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>For each available scene mode,<wbr/> the list must contain three +entries containing the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> values used +by the camera device.<wbr/> The entry order is <code>(aeMode,<wbr/> awbMode,<wbr/> afMode)</code> +where aeMode has the lowest index position.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When a scene mode is enabled,<wbr/> the camera device is expected +to override <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> +and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> with its preferred settings for +that scene mode.<wbr/></p> +<p>The order of this list matches that of availableSceneModes,<wbr/> +with 3 entries for each mode.<wbr/> The overrides listed +for FACE_<wbr/>PRIORITY and FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT (if supported) are ignored,<wbr/> +since for that mode the application-set <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> values are +used instead,<wbr/> matching the behavior when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> +is set to AUTO.<wbr/> It is recommended that the FACE_<wbr/>PRIORITY and +FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT (if supported) overrides should be set to 0.<wbr/></p> +<p>For example,<wbr/> if availableSceneModes contains +<code>(FACE_<wbr/>PRIORITY,<wbr/> ACTION,<wbr/> NIGHT)</code>,<wbr/> then the camera framework +expects sceneModeOverrides to have 9 entries formatted like: +<code>(0,<wbr/> 0,<wbr/> 0,<wbr/> ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> AUTO,<wbr/> CONTINUOUS_<wbr/>PICTURE,<wbr/> +ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> INCANDESCENT,<wbr/> AUTO)</code>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>To maintain backward compatibility,<wbr/> this list will be made available +in the static metadata of the camera service.<wbr/> The camera service will +use these values to set <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> when using a scene +mode other than FACE_<wbr/>PRIORITY and FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT (if supported).<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.availableHighSpeedVideoConfigurations"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 5 x n + </span> + <span class="entry_type_visibility"> [hidden as highSpeedVideoConfiguration]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of available high speed video size,<wbr/> fps range and max batch size configurations +supported by the camera device,<wbr/> in the format of (width,<wbr/> height,<wbr/> fps_<wbr/>min,<wbr/> fps_<wbr/>max,<wbr/> batch_<wbr/>size_<wbr/>max).<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>For each configuration,<wbr/> the fps_<wbr/>max >= 120fps.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When CONSTRAINED_<wbr/>HIGH_<wbr/>SPEED_<wbr/>VIDEO is supported in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>,<wbr/> +this metadata will list the supported high speed video size,<wbr/> fps range and max batch size +configurations.<wbr/> All the sizes listed in this configuration will be a subset of the sizes +reported by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">StreamConfigurationMap#getOutputSizes</a> +for processed non-stalling formats.<wbr/></p> +<p>For the high speed video use case,<wbr/> the application must +select the video size and fps range from this metadata to configure the recording and +preview streams and setup the recording requests.<wbr/> For example,<wbr/> if the application intends +to do high speed recording,<wbr/> it can select the maximum size reported by this metadata to +configure output streams.<wbr/> Once the size is selected,<wbr/> application can filter this metadata +by selected size and get the supported fps ranges,<wbr/> and use these fps ranges to setup the +recording requests.<wbr/> Note that for the use case of multiple output streams,<wbr/> application +must select one unique size from this metadata to use (e.<wbr/>g.,<wbr/> preview and recording streams +must have the same size).<wbr/> Otherwise,<wbr/> the high speed capture session creation will fail.<wbr/></p> +<p>The min and max fps will be multiple times of 30fps.<wbr/></p> +<p>High speed video streaming extends significant performance pressue to camera hardware,<wbr/> +to achieve efficient high speed streaming,<wbr/> the camera device may have to aggregate +multiple frames together and send to camera device for processing where the request +controls are same for all the frames in this batch.<wbr/> Max batch size indicates +the max possible number of frames the camera device will group together for this high +speed stream configuration.<wbr/> This max batch size will be used to generate a high speed +recording request list by +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>.<wbr/> +The max batch size for each configuration will satisfy below conditions:</p> +<ul> +<li>Each max batch size will be a divisor of its corresponding fps_<wbr/>max /<wbr/> 30.<wbr/> For example,<wbr/> +if max_<wbr/>fps is 300,<wbr/> max batch size will only be 1,<wbr/> 2,<wbr/> 5,<wbr/> or 10.<wbr/></li> +<li>The camera device may choose smaller internal batch size for each configuration,<wbr/> but +the actual batch size will be a divisor of max batch size.<wbr/> For example,<wbr/> if the max batch +size is 8,<wbr/> the actual batch size used by camera device will only be 1,<wbr/> 2,<wbr/> 4,<wbr/> or 8.<wbr/></li> +<li>The max batch size in each configuration entry must be no larger than 32.<wbr/></li> +</ul> +<p>The camera device doesn't have to support batch mode to achieve high speed video recording,<wbr/> +in such case,<wbr/> batch_<wbr/>size_<wbr/>max will be reported as 1 in each configuration entry.<wbr/></p> +<p>This fps ranges in this configuration list can only be used to create requests +that are submitted to a high speed camera capture session created by +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>.<wbr/> +The fps ranges reported in this metadata must not be used to setup capture requests for +normal capture session,<wbr/> or it will cause request error.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>All the sizes listed in this configuration will be a subset of the sizes reported by +<a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> for processed non-stalling output formats.<wbr/> +Note that for all high speed video configurations,<wbr/> HAL must be able to support a minimum +of two streams,<wbr/> though the application might choose to configure just one stream.<wbr/></p> +<p>The HAL may support multiple sensor modes for high speed outputs,<wbr/> for example,<wbr/> 120fps +sensor mode and 120fps recording,<wbr/> 240fps sensor mode for 240fps recording.<wbr/> The application +usually starts preview first,<wbr/> then starts recording.<wbr/> To avoid sensor mode switch caused +stutter when starting recording as much as possible,<wbr/> the application may want to ensure +the same sensor mode is used for preview and recording.<wbr/> Therefore,<wbr/> The HAL must advertise +the variable fps range [30,<wbr/> fps_<wbr/>max] for each fixed fps range in this configuration list.<wbr/> +For example,<wbr/> if the HAL advertises [120,<wbr/> 120] and [240,<wbr/> 240],<wbr/> the HAL must also advertise +[30,<wbr/> 120] and [30,<wbr/> 240] for each configuration.<wbr/> In doing so,<wbr/> if the application intends to +do 120fps recording,<wbr/> it can select [30,<wbr/> 120] to start preview,<wbr/> and [120,<wbr/> 120] to start +recording.<wbr/> For these variable fps ranges,<wbr/> it's up to the HAL to decide the actual fps +values that are suitable for smooth preview streaming.<wbr/> If the HAL sees different max_<wbr/>fps +values that fall into different sensor modes in a sequence of requests,<wbr/> the HAL must +switch the sensor mode as quick as possible to minimize the mode switch caused stutter.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.aeLockAvailable"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Lock<wbr/>Available + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">FALSE</span> + </li> + <li> + <span class="entry_type_enum_name">TRUE</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether the camera device supports <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Devices with MANUAL_<wbr/>SENSOR capability or BURST_<wbr/>CAPTURE capability will always +list <code>true</code>.<wbr/> This includes FULL devices.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.awbLockAvailable"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>awb<wbr/>Lock<wbr/>Available + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">FALSE</span> + </li> + <li> + <span class="entry_type_enum_name">TRUE</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether the camera device supports <a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Devices with MANUAL_<wbr/>POST_<wbr/>PROCESSING capability or BURST_<wbr/>CAPTURE capability will +always list <code>true</code>.<wbr/> This includes FULL devices.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.availableModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>available<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">List of enums (android.<wbr/>control.<wbr/>mode).<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of control modes for <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> that are supported by this camera +device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This list contains control modes that can be set for the camera device.<wbr/> +LEGACY mode devices will always support AUTO mode.<wbr/> LIMITED and FULL +devices will always support OFF,<wbr/> AUTO modes.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.control.postRawSensitivityBoostRange"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost<wbr/>Range + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as rangeInt]</span> + + + + + <div class="entry_type_notes">Range of supported post RAW sensitivitiy boosts</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Range of boosts for <a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> supported +by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + ISO arithmetic units,<wbr/> the same as android.<wbr/>sensor.<wbr/>sensitivity + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Devices support post RAW sensitivity boost will advertise +<a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> key for controling +post RAW sensitivity boost.<wbr/></p> +<p>This key will be <code>null</code> for devices that do not support any RAW format +outputs.<wbr/> For devices that do support RAW format outputs,<wbr/> this key will always +present,<wbr/> and if a device does not support post RAW sensitivity boost,<wbr/> it will +list <code>(100,<wbr/> 100)</code> in this key.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This key is added in HAL3.<wbr/>4.<wbr/> For HAL3.<wbr/>3 or earlier devices,<wbr/> camera framework will +generate this key as <code>(100,<wbr/> 100)</code> if device supports any of RAW output formats.<wbr/> +All HAL3.<wbr/>4 and above devices should list this key if device supports any of RAW +output formats.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.control.aePrecaptureId"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Id + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The ID sent with the latest +CAMERA2_<wbr/>TRIGGER_<wbr/>PRECAPTURE_<wbr/>METERING call</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Must be 0 if no +CAMERA2_<wbr/>TRIGGER_<wbr/>PRECAPTURE_<wbr/>METERING trigger received yet +by HAL.<wbr/> Always updated even if AE algorithm ignores the +trigger</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.aeAntibandingMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>The camera device will not adjust exposure duration to +avoid banding problems.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">50HZ</span> + <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to +avoid banding problems with 50Hz illumination sources.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">60HZ</span> + <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to +avoid banding problems with 60Hz illumination +sources.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AUTO</span> + <span class="entry_type_enum_notes"><p>The camera device will automatically adapt its +antibanding routine to the current illumination +condition.<wbr/> This is the default mode if AUTO is +available on given camera device.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired setting for the camera device's auto-exposure +algorithm's antibanding compensation.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Some kinds of lighting fixtures,<wbr/> such as some fluorescent +lights,<wbr/> flicker at the rate of the power supply frequency +(60Hz or 50Hz,<wbr/> depending on country).<wbr/> While this is +typically not noticeable to a person,<wbr/> it can be visible to +a camera device.<wbr/> If a camera sets its exposure time to the +wrong value,<wbr/> the flicker may become visible in the +viewfinder as flicker or in a final captured image,<wbr/> as a +set of variable-brightness bands across the image.<wbr/></p> +<p>Therefore,<wbr/> the auto-exposure routines of camera devices +include antibanding routines that ensure that the chosen +exposure value will not cause such banding.<wbr/> The choice of +exposure time depends on the rate of flicker,<wbr/> which the +camera device can detect automatically,<wbr/> or the expected +rate can be selected by the application using this +control.<wbr/></p> +<p>A given camera device may not support all of the possible +options for the antibanding mode.<wbr/> The +<a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a> key contains +the available modes for a given camera device.<wbr/></p> +<p>AUTO mode is the default if it is available on given +camera device.<wbr/> When AUTO mode is not available,<wbr/> the +default will be either 50HZ or 60HZ,<wbr/> and both 50HZ +and 60HZ will be available.<wbr/></p> +<p>If manual exposure control is enabled (by setting +<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/> +then this setting has no effect,<wbr/> and the application must +ensure it selects exposure times that do not cause banding +issues.<wbr/> The <a href="#dynamic_android.statistics.sceneFlicker">android.<wbr/>statistics.<wbr/>scene<wbr/>Flicker</a> key can assist +the application in this.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For all capture request templates,<wbr/> this field must be set +to AUTO if AUTO mode is available.<wbr/> If AUTO is not available,<wbr/> +the default must be either 50HZ or 60HZ,<wbr/> and both 50HZ and +60HZ must be available.<wbr/></p> +<p>If manual exposure control is enabled (by setting +<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/> +then the exposure values provided by the application must not be +adjusted for antibanding.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.aeExposureCompensation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Adjustment to auto-exposure (AE) target image +brightness.<wbr/></p> + </td> + + <td class="entry_units"> + Compensation steps + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The adjustment is measured as a count of steps,<wbr/> with the +step size defined by <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> and the +allowed range by <a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a>.<wbr/></p> +<p>For example,<wbr/> if the exposure value (EV) step is 0.<wbr/>333,<wbr/> '6' +will mean an exposure compensation of +2 EV; -3 will mean an +exposure compensation of -1 EV.<wbr/> One EV represents a doubling +of image brightness.<wbr/> Note that this control will only be +effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF.<wbr/> This control +will take effect even when <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> <code>== true</code>.<wbr/></p> +<p>In the event of exposure compensation value being changed,<wbr/> camera device +may take several frames to reach the newly requested exposure target.<wbr/> +During that time,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> field will be in the SEARCHING +state.<wbr/> Once the new exposure target is reached,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> will +change from SEARCHING to either CONVERGED,<wbr/> LOCKED (if AE lock is enabled),<wbr/> or +FLASH_<wbr/>REQUIRED (if the scene is too dark for still capture).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.aeLock"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Lock + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Auto-exposure lock is disabled; the AE algorithm +is free to update its parameters.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Auto-exposure lock is enabled; the AE algorithm +must not update the exposure and sensitivity parameters +while the lock is active.<wbr/></p> +<p><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> setting changes +will still take effect while auto-exposure is locked.<wbr/></p> +<p>Some rare LEGACY devices may not support +this,<wbr/> in which case the value will always be overridden to OFF.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether auto-exposure (AE) is currently locked to its latest +calculated values.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to <code>true</code> (ON),<wbr/> the AE algorithm is locked to its latest parameters,<wbr/> +and will not change exposure settings until the lock is set to <code>false</code> (OFF).<wbr/></p> +<p>Note that even when AE is locked,<wbr/> the flash may be fired if +the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>AUTO_<wbr/>FLASH /<wbr/> +ON_<wbr/>ALWAYS_<wbr/>FLASH /<wbr/> ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE.<wbr/></p> +<p>When <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> is changed,<wbr/> even if the AE lock +is ON,<wbr/> the camera device will still adjust its exposure value.<wbr/></p> +<p>If AE precapture is triggered (see <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) +when AE is already locked,<wbr/> the camera device will not change the exposure time +(<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>) and sensitivity (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>) +parameters.<wbr/> The flash may be fired if the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> +is ON_<wbr/>AUTO_<wbr/>FLASH/<wbr/>ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE and the scene is too dark.<wbr/> If the +<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> the scene may become overexposed.<wbr/> +Similarly,<wbr/> AE precapture trigger CANCEL has no effect when AE is already locked.<wbr/></p> +<p>When an AE precapture sequence is triggered,<wbr/> AE unlock will not be able to unlock +the AE if AE is locked by the camera device internally during precapture metering +sequence In other words,<wbr/> submitting requests with AE unlock has no effect for an +ongoing precapture metering sequence.<wbr/> Otherwise,<wbr/> the precapture metering sequence +will never succeed in a sequence of preview requests where AE lock is always set +to <code>false</code>.<wbr/></p> +<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that +get locked do not necessarily correspond to the settings that were present in the +latest capture result received from the camera device,<wbr/> since additional captures +and AE updates may have occurred even before the result was sent out.<wbr/> If an +application is switching between automatic and manual control and wishes to eliminate +any flicker during the switch,<wbr/> the following procedure is recommended:</p> +<ol> +<li>Starting in auto-AE mode:</li> +<li>Lock AE</li> +<li>Wait for the first result to be output that has the AE locked</li> +<li>Copy exposure settings from that result into a request,<wbr/> set the request to manual AE</li> +<li>Submit the capture request,<wbr/> proceed to run manual AE as desired.<wbr/></li> +</ol> +<p>See <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE lock related state transition details.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.aeMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is disabled.<wbr/></p> +<p>The application-selected <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> +<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> and +<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are used by the camera +device,<wbr/> along with android.<wbr/>flash.<wbr/>* fields,<wbr/> if there's +a flash unit for this camera device.<wbr/></p> +<p>Note that auto-white balance (AWB) and auto-focus (AF) +behavior is device dependent when AE is in OFF mode.<wbr/> +To have consistent behavior across different devices,<wbr/> +it is recommended to either set AWB and AF to OFF mode +or lock AWB and AF before setting AE to OFF.<wbr/> +See <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a>,<wbr/> and <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> +for more details.<wbr/></p> +<p>LEGACY devices do not support the OFF mode and will +override attempts to use this value to ON.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is active,<wbr/> +with no flash control.<wbr/></p> +<p>The application's values for +<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> +<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and +<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are ignored.<wbr/> The +application has control over the various +android.<wbr/>flash.<wbr/>* fields.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON_AUTO_FLASH</span> + <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls +the camera's flash unit,<wbr/> firing it in low-light +conditions.<wbr/></p> +<p>The flash may be fired during a precapture sequence +(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and +may be fired for captures for which the +<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to +STILL_<wbr/>CAPTURE</p></span> + </li> + <li> + <span class="entry_type_enum_name">ON_ALWAYS_FLASH</span> + <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls +the camera's flash unit,<wbr/> always firing it for still +captures.<wbr/></p> +<p>The flash may be fired during a precapture sequence +(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and +will always be fired for captures for which the +<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to +STILL_<wbr/>CAPTURE</p></span> + </li> + <li> + <span class="entry_type_enum_name">ON_AUTO_FLASH_REDEYE</span> + <span class="entry_type_enum_notes"><p>Like ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> but with automatic red eye +reduction.<wbr/></p> +<p>If deemed necessary by the camera device,<wbr/> a red eye +reduction flash will fire during the precapture +sequence.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired mode for the camera device's +auto-exposure routine.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.aeAvailableModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is +AUTO.<wbr/></p> +<p>When set to any of the ON modes,<wbr/> the camera device's +auto-exposure routine is enabled,<wbr/> overriding the +application's selected exposure time,<wbr/> sensor sensitivity,<wbr/> +and frame duration (<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> +<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and +<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>).<wbr/> If one of the FLASH modes +is selected,<wbr/> the camera device's flash unit controls are +also overridden.<wbr/></p> +<p>The FLASH modes are only available if the camera device +has a flash unit (<a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> is <code>true</code>).<wbr/></p> +<p>If flash TORCH mode is desired,<wbr/> this field must be set to +ON or OFF,<wbr/> and <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> set to TORCH.<wbr/></p> +<p>When set to any of the ON modes,<wbr/> the values chosen by the +camera device auto-exposure routine for the overridden +fields for a given capture will be available in its +CaptureResult.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.aeRegions"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>ae<wbr/>Regions + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 5 x area_count + </span> + <span class="entry_type_visibility"> [public as meteringRectangle]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of metering areas to use for auto-exposure adjustment.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size + </td> + + <td class="entry_range"> + <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not available if <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a> is 0.<wbr/> +Otherwise will always be present.<wbr/></p> +<p>The maximum number of regions supported by the device is determined by the value +of <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a>.<wbr/></p> +<p>The coordinate system is based on the active pixel array,<wbr/> +with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and +(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/> +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the +bottom-right pixel in the active pixel array.<wbr/></p> +<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight +for every pixel in the area.<wbr/> This means that a large metering area +with the same weight as a smaller area will have more effect in +the metering result.<wbr/> Metering areas can partially overlap and the +camera device will add the weights in the overlap region.<wbr/></p> +<p>The weights are relative to weights of other exposure metering regions,<wbr/> so if only one +region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0 +weight is ignored.<wbr/></p> +<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the +camera device.<wbr/></p> +<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in +capture result metadata,<wbr/> the camera device will ignore the sections outside the crop +region and output only the intersection rectangle as the metering region in the result +metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and +not reported in the result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL level representation of MeteringRectangle[] is a +int[5 * area_<wbr/>count].<wbr/> +Every five elements represent a metering region of +(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/> +The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but +exclusive on xmax and ymax.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.aeTargetFpsRange"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as rangeInt]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Range over which the auto-exposure routine can +adjust the capture frame rate to maintain good +exposure.<wbr/></p> + </td> + + <td class="entry_units"> + Frames per second (FPS) + </td> + + <td class="entry_range"> + <p>Any of the entries in <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Only constrains auto-exposure (AE) algorithm,<wbr/> not +manual control of <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a> and +<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.aePrecaptureTrigger"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">IDLE</span> + <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">START</span> + <span class="entry_type_enum_notes"><p>The precapture metering sequence will be started +by the camera device.<wbr/></p> +<p>The exact effect of the precapture trigger depends on +the current AE mode and state.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CANCEL</span> + <span class="entry_type_enum_notes"><p>The camera device will cancel any currently active or completed +precapture metering sequence,<wbr/> the auto-exposure routine will return to its +initial state.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether the camera device will trigger a precapture +metering sequence when it processes this request.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry is normally set to IDLE,<wbr/> or is not +included at all in the request settings.<wbr/> When included and +set to START,<wbr/> the camera device will trigger the auto-exposure (AE) +precapture metering sequence.<wbr/></p> +<p>When set to CANCEL,<wbr/> the camera device will cancel any active +precapture metering trigger,<wbr/> and return to its initial AE state.<wbr/> +If a precapture metering sequence is already completed,<wbr/> and the camera +device has implicitly locked the AE for subsequent still capture,<wbr/> the +CANCEL trigger will unlock the AE and return to its initial AE state.<wbr/></p> +<p>The precapture sequence should be triggered before starting a +high-quality still capture for final metering decisions to +be made,<wbr/> and for firing pre-capture flash pulses to estimate +scene brightness and required final capture flash power,<wbr/> when +the flash is enabled.<wbr/></p> +<p>Normally,<wbr/> this entry should be set to START for only a +single request,<wbr/> and the application should wait until the +sequence completes before starting a new one.<wbr/></p> +<p>When a precapture metering sequence is finished,<wbr/> the camera device +may lock the auto-exposure routine internally to be able to accurately expose the +subsequent still capture image (<code><a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE</code>).<wbr/> +For this case,<wbr/> the AE may not resume normal scan if no subsequent still capture is +submitted.<wbr/> To ensure that the AE routine restarts normal scan,<wbr/> the application should +submit a request with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == true</code>,<wbr/> followed by a request +with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == false</code>,<wbr/> if the application decides not to submit a +still capture request after the precapture sequence completes.<wbr/> Alternatively,<wbr/> for +API level 23 or newer devices,<wbr/> the CANCEL can be used to unlock the camera device +internally locked AE if the application doesn't submit a still capture request after +the AE precapture trigger.<wbr/> Note that,<wbr/> the CANCEL was added in API level 23,<wbr/> and must not +be used in devices that have earlier API levels.<wbr/></p> +<p>The exact effect of auto-exposure (AE) precapture trigger +depends on the current AE mode and state; see +<a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE precapture state transition +details.<wbr/></p> +<p>On LEGACY-level devices,<wbr/> the precapture trigger is not supported; +capturing a high-resolution JPEG image will automatically trigger a +precapture sequence before the high-resolution capture,<wbr/> including +potentially firing a pre-capture flash.<wbr/></p> +<p>Using the precapture trigger and the auto-focus trigger <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> +simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between +the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a +focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous +trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and +changes to <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> indicating the start of the precapture sequence,<wbr/> for +example.<wbr/></p> +<p>If both the precapture and the auto-focus trigger are activated on the same request,<wbr/> then +the camera device will complete them in the optimal order for that device.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL must support triggering the AE precapture trigger while an AF trigger is active +(and vice versa),<wbr/> or at the same time as the AF trigger.<wbr/> It is acceptable for the HAL to +treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the +AE trigger.<wbr/> Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/> +to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.aeState"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>ae<wbr/>State + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">INACTIVE</span> + <span class="entry_type_enum_notes"><p>AE is off or recently reset.<wbr/></p> +<p>When a camera device is opened,<wbr/> it starts in +this state.<wbr/> This is a transient state,<wbr/> the camera device may skip reporting +this state in capture result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SEARCHING</span> + <span class="entry_type_enum_notes"><p>AE doesn't yet have a good set of control values +for the current scene.<wbr/></p> +<p>This is a transient state,<wbr/> the camera device may skip +reporting this state in capture result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CONVERGED</span> + <span class="entry_type_enum_notes"><p>AE has a good set of control values for the +current scene.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">LOCKED</span> + <span class="entry_type_enum_notes"><p>AE has been locked.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FLASH_REQUIRED</span> + <span class="entry_type_enum_notes"><p>AE has a good set of control values,<wbr/> but flash +needs to be fired for good quality still +capture.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PRECAPTURE</span> + <span class="entry_type_enum_notes"><p>AE has been asked to do a precapture sequence +and is currently executing it.<wbr/></p> +<p>Precapture can be triggered through setting +<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> to START.<wbr/> Currently +active and completed (if it causes camera device internal AE lock) precapture +metering sequence can be canceled through setting +<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> to CANCEL.<wbr/></p> +<p>Once PRECAPTURE completes,<wbr/> AE will transition to CONVERGED +or FLASH_<wbr/>REQUIRED as appropriate.<wbr/> This is a transient +state,<wbr/> the camera device may skip reporting this state in +capture result.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Current state of the auto-exposure (AE) algorithm.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Switching between or enabling AE modes (<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>) always +resets the AE state to INACTIVE.<wbr/> Similarly,<wbr/> switching between <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>,<wbr/> +or <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> if <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code> resets all +the algorithm states to INACTIVE.<wbr/></p> +<p>The camera device can do several state transitions between two results,<wbr/> if it is +allowed by the state transition table.<wbr/> For example: INACTIVE may never actually be +seen in a result.<wbr/></p> +<p>The state in the result is the state for this image (in sync with this image): if +AE state becomes CONVERGED,<wbr/> then the image data associated with this result should +be good to use.<wbr/></p> +<p>Below are state transition tables for different AE modes.<wbr/></p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center"></td> +<td align="center">INACTIVE</td> +<td align="center">Camera device auto exposure algorithm is disabled</td> +</tr> +</tbody> +</table> +<p>When <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is AE_<wbr/>MODE_<wbr/>ON_<wbr/>*:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center">Camera device initiates AE scan</td> +<td align="center">SEARCHING</td> +<td align="center">Values changing</td> +</tr> +<tr> +<td align="center">INACTIVE</td> +<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td> +<td align="center">LOCKED</td> +<td align="center">Values locked</td> +</tr> +<tr> +<td align="center">SEARCHING</td> +<td align="center">Camera device finishes AE scan</td> +<td align="center">CONVERGED</td> +<td align="center">Good values,<wbr/> not changing</td> +</tr> +<tr> +<td align="center">SEARCHING</td> +<td align="center">Camera device finishes AE scan</td> +<td align="center">FLASH_<wbr/>REQUIRED</td> +<td align="center">Converged but too dark w/<wbr/>o flash</td> +</tr> +<tr> +<td align="center">SEARCHING</td> +<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td> +<td align="center">LOCKED</td> +<td align="center">Values locked</td> +</tr> +<tr> +<td align="center">CONVERGED</td> +<td align="center">Camera device initiates AE scan</td> +<td align="center">SEARCHING</td> +<td align="center">Values changing</td> +</tr> +<tr> +<td align="center">CONVERGED</td> +<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td> +<td align="center">LOCKED</td> +<td align="center">Values locked</td> +</tr> +<tr> +<td align="center">FLASH_<wbr/>REQUIRED</td> +<td align="center">Camera device initiates AE scan</td> +<td align="center">SEARCHING</td> +<td align="center">Values changing</td> +</tr> +<tr> +<td align="center">FLASH_<wbr/>REQUIRED</td> +<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td> +<td align="center">LOCKED</td> +<td align="center">Values locked</td> +</tr> +<tr> +<td align="center">LOCKED</td> +<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td> +<td align="center">SEARCHING</td> +<td align="center">Values not good after unlock</td> +</tr> +<tr> +<td align="center">LOCKED</td> +<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td> +<td align="center">CONVERGED</td> +<td align="center">Values good after unlock</td> +</tr> +<tr> +<td align="center">LOCKED</td> +<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td> +<td align="center">FLASH_<wbr/>REQUIRED</td> +<td align="center">Exposure good,<wbr/> but too dark</td> +</tr> +<tr> +<td align="center">PRECAPTURE</td> +<td align="center">Sequence done.<wbr/> <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td> +<td align="center">CONVERGED</td> +<td align="center">Ready for high-quality capture</td> +</tr> +<tr> +<td align="center">PRECAPTURE</td> +<td align="center">Sequence done.<wbr/> <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td> +<td align="center">LOCKED</td> +<td align="center">Ready for high-quality capture</td> +</tr> +<tr> +<td align="center">LOCKED</td> +<td align="center">aeLock is ON and aePrecaptureTrigger is START</td> +<td align="center">LOCKED</td> +<td align="center">Precapture trigger is ignored when AE is already locked</td> +</tr> +<tr> +<td align="center">LOCKED</td> +<td align="center">aeLock is ON and aePrecaptureTrigger is CANCEL</td> +<td align="center">LOCKED</td> +<td align="center">Precapture trigger is ignored when AE is already locked</td> +</tr> +<tr> +<td align="center">Any state (excluding LOCKED)</td> +<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is START</td> +<td align="center">PRECAPTURE</td> +<td align="center">Start AE precapture metering sequence</td> +</tr> +<tr> +<td align="center">Any state (excluding LOCKED)</td> +<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Currently active precapture metering sequence is canceled</td> +</tr> +</tbody> +</table> +<p>For the above table,<wbr/> the camera device may skip reporting any state changes that happen +without application intervention (i.<wbr/>e.<wbr/> mode switch,<wbr/> trigger,<wbr/> locking).<wbr/> Any state that +can be skipped in that manner is called a transient state.<wbr/></p> +<p>For example,<wbr/> for above AE modes (AE_<wbr/>MODE_<wbr/>ON_<wbr/>*),<wbr/> in addition to the state transitions +listed in above table,<wbr/> it is also legal for the camera device to skip one or more +transient states between two results.<wbr/> See below table for examples:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center">Camera device finished AE scan</td> +<td align="center">CONVERGED</td> +<td align="center">Values are already good,<wbr/> transient states are skipped by camera device.<wbr/></td> +</tr> +<tr> +<td align="center">Any state (excluding LOCKED)</td> +<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is START,<wbr/> sequence done</td> +<td align="center">FLASH_<wbr/>REQUIRED</td> +<td align="center">Converged but too dark w/<wbr/>o flash after a precapture sequence,<wbr/> transient states are skipped by camera device.<wbr/></td> +</tr> +<tr> +<td align="center">Any state (excluding LOCKED)</td> +<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is START,<wbr/> sequence done</td> +<td align="center">CONVERGED</td> +<td align="center">Converged after a precapture sequence,<wbr/> transient states are skipped by camera device.<wbr/></td> +</tr> +<tr> +<td align="center">Any state (excluding LOCKED)</td> +<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is CANCEL,<wbr/> converged</td> +<td align="center">FLASH_<wbr/>REQUIRED</td> +<td align="center">Converged but too dark w/<wbr/>o flash after a precapture sequence is canceled,<wbr/> transient states are skipped by camera device.<wbr/></td> +</tr> +<tr> +<td align="center">Any state (excluding LOCKED)</td> +<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is CANCEL,<wbr/> converged</td> +<td align="center">CONVERGED</td> +<td align="center">Converged after a precapture sequenceis canceled,<wbr/> transient states are skipped by camera device.<wbr/></td> +</tr> +<tr> +<td align="center">CONVERGED</td> +<td align="center">Camera device finished AE scan</td> +<td align="center">FLASH_<wbr/>REQUIRED</td> +<td align="center">Converged but too dark w/<wbr/>o flash after a new scan,<wbr/> transient states are skipped by camera device.<wbr/></td> +</tr> +<tr> +<td align="center">FLASH_<wbr/>REQUIRED</td> +<td align="center">Camera device finished AE scan</td> +<td align="center">CONVERGED</td> +<td align="center">Converged after a new scan,<wbr/> transient states are skipped by camera device.<wbr/></td> +</tr> +</tbody> +</table> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.afMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>af<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>The auto-focus routine does not control the lens; +<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> is controlled by the +application.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AUTO</span> + <span class="entry_type_enum_notes"><p>Basic automatic focus mode.<wbr/></p> +<p>In this mode,<wbr/> the lens does not move unless +the autofocus trigger action is called.<wbr/> When that trigger +is activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to +the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/></p> +<p>Always supported if lens is not fixed focus.<wbr/></p> +<p>Use <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> to determine if lens +is fixed-focus.<wbr/></p> +<p>Triggering AF_<wbr/>CANCEL resets the lens position to default,<wbr/> +and sets the AF state to INACTIVE.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MACRO</span> + <span class="entry_type_enum_notes"><p>Close-up focusing mode.<wbr/></p> +<p>In this mode,<wbr/> the lens does not move unless the +autofocus trigger action is called.<wbr/> When that trigger is +activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to +the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/> This +mode is optimized for focusing on objects very close to +the camera.<wbr/></p> +<p>When that trigger is activated,<wbr/> AF will transition to +ACTIVE_<wbr/>SCAN,<wbr/> then to the outcome of the scan (FOCUSED or +NOT_<wbr/>FOCUSED).<wbr/> Triggering cancel AF resets the lens +position to default,<wbr/> and sets the AF state to +INACTIVE.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CONTINUOUS_VIDEO</span> + <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens +position continually to attempt to provide a +constantly-in-focus image stream.<wbr/></p> +<p>The focusing behavior should be suitable for good quality +video recording; typically this means slower focus +movement and no overshoots.<wbr/> When the AF trigger is not +involved,<wbr/> the AF algorithm should start in INACTIVE state,<wbr/> +and then transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED +states as appropriate.<wbr/> When the AF trigger is activated,<wbr/> +the algorithm should immediately transition into +AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the +lens position until a cancel AF trigger is received.<wbr/></p> +<p>Once cancel is received,<wbr/> the algorithm should transition +back to INACTIVE and resume passive scan.<wbr/> Note that this +behavior is not identical to CONTINUOUS_<wbr/>PICTURE,<wbr/> since an +ongoing PASSIVE_<wbr/>SCAN must immediately be +canceled.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CONTINUOUS_PICTURE</span> + <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens +position continually to attempt to provide a +constantly-in-focus image stream.<wbr/></p> +<p>The focusing behavior should be suitable for still image +capture; typically this means focusing as fast as +possible.<wbr/> When the AF trigger is not involved,<wbr/> the AF +algorithm should start in INACTIVE state,<wbr/> and then +transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED states as +appropriate as it attempts to maintain focus.<wbr/> When the AF +trigger is activated,<wbr/> the algorithm should finish its +PASSIVE_<wbr/>SCAN if active,<wbr/> and then transition into +AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the +lens position until a cancel AF trigger is received.<wbr/></p> +<p>When the AF cancel trigger is activated,<wbr/> the algorithm +should transition back to INACTIVE and then act as if it +has just been started.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">EDOF</span> + <span class="entry_type_enum_notes"><p>Extended depth of field (digital focus) mode.<wbr/></p> +<p>The camera device will produce images with an extended +depth of field automatically; no special focusing +operations need to be done before taking a picture.<wbr/></p> +<p>AF triggers are ignored,<wbr/> and the AF state will always be +INACTIVE.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether auto-focus (AF) is currently enabled,<wbr/> and what +mode it is set to.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.afAvailableModes">android.<wbr/>control.<wbr/>af<wbr/>Available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> = AUTO and the lens is not fixed focus +(i.<wbr/>e.<wbr/> <code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> > 0</code>).<wbr/> Also note that +when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/> the behavior of AF is device +dependent.<wbr/> It is recommended to lock AF by using <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> before +setting <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> to OFF,<wbr/> or set AF mode to OFF when AE is OFF.<wbr/></p> +<p>If the lens is controlled by the camera device auto-focus algorithm,<wbr/> +the camera device will report the current AF status in <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> +in result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When afMode is AUTO or MACRO,<wbr/> the lens must not move until an AF trigger is sent in a +request (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> <code>==</code> START).<wbr/> After an AF trigger,<wbr/> the afState will end +up with either FOCUSED_<wbr/>LOCKED or NOT_<wbr/>FOCUSED_<wbr/>LOCKED state (see +<a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> which indicates that the lens is +locked and will not move.<wbr/> If camera movement (e.<wbr/>g.<wbr/> tilting camera) causes the lens to move +after the lens is locked,<wbr/> the HAL must compensate this movement appropriately such that +the same focal plane remains in focus.<wbr/></p> +<p>When afMode is one of the continuous auto focus modes,<wbr/> the HAL is free to start a AF +scan whenever it's not locked.<wbr/> When the lens is locked after an AF trigger +(see <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> the HAL should maintain the +same lock behavior as above.<wbr/></p> +<p>When afMode is OFF,<wbr/> the application controls focus manually.<wbr/> The accuracy of the +focus distance control depends on the <a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a>.<wbr/> +However,<wbr/> the lens must not move regardless of the camera movement for any focus distance +manual control.<wbr/></p> +<p>To put this in concrete terms,<wbr/> if the camera has lens elements which may move based on +camera orientation or motion (e.<wbr/>g.<wbr/> due to gravity),<wbr/> then the HAL must drive the lens to +remain in a fixed position invariant to the camera's orientation or motion,<wbr/> for example,<wbr/> +by using accelerometer measurements in the lens control logic.<wbr/> This is a typical issue +that will arise on camera modules with open-loop VCMs.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.afRegions"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>af<wbr/>Regions + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 5 x area_count + </span> + <span class="entry_type_visibility"> [public as meteringRectangle]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of metering areas to use for auto-focus.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size + </td> + + <td class="entry_range"> + <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not available if <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a> is 0.<wbr/> +Otherwise will always be present.<wbr/></p> +<p>The maximum number of focus areas supported by the device is determined by the value +of <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a>.<wbr/></p> +<p>The coordinate system is based on the active pixel array,<wbr/> +with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and +(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/> +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the +bottom-right pixel in the active pixel array.<wbr/></p> +<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight +for every pixel in the area.<wbr/> This means that a large metering area +with the same weight as a smaller area will have more effect in +the metering result.<wbr/> Metering areas can partially overlap and the +camera device will add the weights in the overlap region.<wbr/></p> +<p>The weights are relative to weights of other metering regions,<wbr/> so if only one region +is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0 weight is +ignored.<wbr/></p> +<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the +camera device.<wbr/></p> +<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in +capture result metadata,<wbr/> the camera device will ignore the sections outside the crop +region and output only the intersection rectangle as the metering region in the result +metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and +not reported in the result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL level representation of MeteringRectangle[] is a +int[5 * area_<wbr/>count].<wbr/> +Every five elements represent a metering region of +(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/> +The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but +exclusive on xmax and ymax.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.afTrigger"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>af<wbr/>Trigger + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">IDLE</span> + <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">START</span> + <span class="entry_type_enum_notes"><p>Autofocus will trigger now.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CANCEL</span> + <span class="entry_type_enum_notes"><p>Autofocus will return to its initial +state,<wbr/> and cancel any currently active trigger.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether the camera device will trigger autofocus for this request.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry is normally set to IDLE,<wbr/> or is not +included at all in the request settings.<wbr/></p> +<p>When included and set to START,<wbr/> the camera device will trigger the +autofocus algorithm.<wbr/> If autofocus is disabled,<wbr/> this trigger has no effect.<wbr/></p> +<p>When set to CANCEL,<wbr/> the camera device will cancel any active trigger,<wbr/> +and return to its initial AF state.<wbr/></p> +<p>Generally,<wbr/> applications should set this entry to START or CANCEL for only a +single capture,<wbr/> and then return it to IDLE (or not set at all).<wbr/> Specifying +START for multiple captures in a row means restarting the AF operation over +and over again.<wbr/></p> +<p>See <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for what the trigger means for each AF mode.<wbr/></p> +<p>Using the autofocus trigger and the precapture trigger <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> +simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between +the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a +focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous +trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and +changes to <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>,<wbr/> for example.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL must support triggering the AF trigger while an AE precapture trigger is active +(and vice versa),<wbr/> or at the same time as the AE trigger.<wbr/> It is acceptable for the HAL to +treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the +AE trigger.<wbr/> Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/> +to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.afState"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>af<wbr/>State + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">INACTIVE</span> + <span class="entry_type_enum_notes"><p>AF is off or has not yet tried to scan/<wbr/>been asked +to scan.<wbr/></p> +<p>When a camera device is opened,<wbr/> it starts in this +state.<wbr/> This is a transient state,<wbr/> the camera device may +skip reporting this state in capture +result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PASSIVE_SCAN</span> + <span class="entry_type_enum_notes"><p>AF is currently performing an AF scan initiated the +camera device in a continuous autofocus mode.<wbr/></p> +<p>Only used by CONTINUOUS_<wbr/>* AF modes.<wbr/> This is a transient +state,<wbr/> the camera device may skip reporting this state in +capture result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PASSIVE_FOCUSED</span> + <span class="entry_type_enum_notes"><p>AF currently believes it is in focus,<wbr/> but may +restart scanning at any time.<wbr/></p> +<p>Only used by CONTINUOUS_<wbr/>* AF modes.<wbr/> This is a transient +state,<wbr/> the camera device may skip reporting this state in +capture result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ACTIVE_SCAN</span> + <span class="entry_type_enum_notes"><p>AF is performing an AF scan because it was +triggered by AF trigger.<wbr/></p> +<p>Only used by AUTO or MACRO AF modes.<wbr/> This is a transient +state,<wbr/> the camera device may skip reporting this state in +capture result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FOCUSED_LOCKED</span> + <span class="entry_type_enum_notes"><p>AF believes it is focused correctly and has locked +focus.<wbr/></p> +<p>This state is reached only after an explicit START AF trigger has been +sent (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>),<wbr/> when good focus has been obtained.<wbr/></p> +<p>The lens will remain stationary until the AF mode (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>) is changed or +a new AF trigger is sent to the camera device (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>).<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">NOT_FOCUSED_LOCKED</span> + <span class="entry_type_enum_notes"><p>AF has failed to focus successfully and has locked +focus.<wbr/></p> +<p>This state is reached only after an explicit START AF trigger has been +sent (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>),<wbr/> when good focus cannot be obtained.<wbr/></p> +<p>The lens will remain stationary until the AF mode (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>) is changed or +a new AF trigger is sent to the camera device (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>).<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PASSIVE_UNFOCUSED</span> + <span class="entry_type_enum_notes"><p>AF finished a passive scan without finding focus,<wbr/> +and may restart scanning at any time.<wbr/></p> +<p>Only used by CONTINUOUS_<wbr/>* AF modes.<wbr/> This is a transient state,<wbr/> the camera +device may skip reporting this state in capture result.<wbr/></p> +<p>LEGACY camera devices do not support this state.<wbr/> When a passive +scan has finished,<wbr/> it will always go to PASSIVE_<wbr/>FOCUSED.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Current state of auto-focus (AF) algorithm.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Switching between or enabling AF modes (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>) always +resets the AF state to INACTIVE.<wbr/> Similarly,<wbr/> switching between <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>,<wbr/> +or <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> if <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code> resets all +the algorithm states to INACTIVE.<wbr/></p> +<p>The camera device can do several state transitions between two results,<wbr/> if it is +allowed by the state transition table.<wbr/> For example: INACTIVE may never actually be +seen in a result.<wbr/></p> +<p>The state in the result is the state for this image (in sync with this image): if +AF state becomes FOCUSED,<wbr/> then the image data associated with this result should +be sharp.<wbr/></p> +<p>Below are state transition tables for different AF modes.<wbr/></p> +<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>OFF or AF_<wbr/>MODE_<wbr/>EDOF:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center"></td> +<td align="center">INACTIVE</td> +<td align="center">Never changes</td> +</tr> +</tbody> +</table> +<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>AUTO or AF_<wbr/>MODE_<wbr/>MACRO:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">ACTIVE_<wbr/>SCAN</td> +<td align="center">Start AF sweep,<wbr/> Lens now moving</td> +</tr> +<tr> +<td align="center">ACTIVE_<wbr/>SCAN</td> +<td align="center">AF sweep done</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">Focused,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">ACTIVE_<wbr/>SCAN</td> +<td align="center">AF sweep done</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">Not focused,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">ACTIVE_<wbr/>SCAN</td> +<td align="center">AF_<wbr/>CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Cancel/<wbr/>reset AF,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Cancel/<wbr/>reset AF</td> +</tr> +<tr> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">ACTIVE_<wbr/>SCAN</td> +<td align="center">Start new sweep,<wbr/> Lens now moving</td> +</tr> +<tr> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Cancel/<wbr/>reset AF</td> +</tr> +<tr> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">ACTIVE_<wbr/>SCAN</td> +<td align="center">Start new sweep,<wbr/> Lens now moving</td> +</tr> +<tr> +<td align="center">Any state</td> +<td align="center">Mode change</td> +<td align="center">INACTIVE</td> +<td align="center"></td> +</tr> +</tbody> +</table> +<p>For the above table,<wbr/> the camera device may skip reporting any state changes that happen +without application intervention (i.<wbr/>e.<wbr/> mode switch,<wbr/> trigger,<wbr/> locking).<wbr/> Any state that +can be skipped in that manner is called a transient state.<wbr/></p> +<p>For example,<wbr/> for these AF modes (AF_<wbr/>MODE_<wbr/>AUTO and AF_<wbr/>MODE_<wbr/>MACRO),<wbr/> in addition to the +state transitions listed in above table,<wbr/> it is also legal for the camera device to skip +one or more transient states between two results.<wbr/> See below table for examples:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">Focus is already good or good after a scan,<wbr/> lens is now locked.<wbr/></td> +</tr> +<tr> +<td align="center">INACTIVE</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">Focus failed after a scan,<wbr/> lens is now locked.<wbr/></td> +</tr> +<tr> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">Focus is already good or good after a scan,<wbr/> lens is now locked.<wbr/></td> +</tr> +<tr> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">Focus is good after a scan,<wbr/> lens is not locked.<wbr/></td> +</tr> +</tbody> +</table> +<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>CONTINUOUS_<wbr/>VIDEO:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center">Camera device initiates new scan</td> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Start AF scan,<wbr/> Lens now moving</td> +</tr> +<tr> +<td align="center">INACTIVE</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF state query,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Camera device completes current scan</td> +<td align="center">PASSIVE_<wbr/>FOCUSED</td> +<td align="center">End AF scan,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Camera device fails current scan</td> +<td align="center">PASSIVE_<wbr/>UNFOCUSED</td> +<td align="center">End AF scan,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">Immediate transition,<wbr/> if focus is good.<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">Immediate transition,<wbr/> if focus is bad.<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">AF_<wbr/>CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Reset lens position,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>FOCUSED</td> +<td align="center">Camera device initiates new scan</td> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Start AF scan,<wbr/> Lens now moving</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>UNFOCUSED</td> +<td align="center">Camera device initiates new scan</td> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Start AF scan,<wbr/> Lens now moving</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>FOCUSED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">Immediate transition,<wbr/> lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>UNFOCUSED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">Immediate transition,<wbr/> lens now locked</td> +</tr> +<tr> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">No effect</td> +</tr> +<tr> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Restart AF scan</td> +</tr> +<tr> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">No effect</td> +</tr> +<tr> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Restart AF scan</td> +</tr> +</tbody> +</table> +<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>CONTINUOUS_<wbr/>PICTURE:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center">Camera device initiates new scan</td> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Start AF scan,<wbr/> Lens now moving</td> +</tr> +<tr> +<td align="center">INACTIVE</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF state query,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Camera device completes current scan</td> +<td align="center">PASSIVE_<wbr/>FOCUSED</td> +<td align="center">End AF scan,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Camera device fails current scan</td> +<td align="center">PASSIVE_<wbr/>UNFOCUSED</td> +<td align="center">End AF scan,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">Eventual transition once the focus is good.<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">Eventual transition if cannot find focus.<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">AF_<wbr/>CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Reset lens position,<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>FOCUSED</td> +<td align="center">Camera device initiates new scan</td> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Start AF scan,<wbr/> Lens now moving</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>UNFOCUSED</td> +<td align="center">Camera device initiates new scan</td> +<td align="center">PASSIVE_<wbr/>SCAN</td> +<td align="center">Start AF scan,<wbr/> Lens now moving</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>FOCUSED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">Immediate trans.<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">PASSIVE_<wbr/>UNFOCUSED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">Immediate trans.<wbr/> Lens now locked</td> +</tr> +<tr> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">No effect</td> +</tr> +<tr> +<td align="center">FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Restart AF scan</td> +</tr> +<tr> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>TRIGGER</td> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">No effect</td> +</tr> +<tr> +<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td> +<td align="center">AF_<wbr/>CANCEL</td> +<td align="center">INACTIVE</td> +<td align="center">Restart AF scan</td> +</tr> +</tbody> +</table> +<p>When switch between AF_<wbr/>MODE_<wbr/>CONTINUOUS_<wbr/>* (CAF modes) and AF_<wbr/>MODE_<wbr/>AUTO/<wbr/>AF_<wbr/>MODE_<wbr/>MACRO +(AUTO modes),<wbr/> the initial INACTIVE or PASSIVE_<wbr/>SCAN states may be skipped by the +camera device.<wbr/> When a trigger is included in a mode switch request,<wbr/> the trigger +will be evaluated in the context of the new mode in the request.<wbr/> +See below table for examples:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">any state</td> +<td align="center">CAF-->AUTO mode switch</td> +<td align="center">INACTIVE</td> +<td align="center">Mode switch without trigger,<wbr/> initial state must be INACTIVE</td> +</tr> +<tr> +<td align="center">any state</td> +<td align="center">CAF-->AUTO mode switch with AF_<wbr/>TRIGGER</td> +<td align="center">trigger-reachable states from INACTIVE</td> +<td align="center">Mode switch with trigger,<wbr/> INACTIVE is skipped</td> +</tr> +<tr> +<td align="center">any state</td> +<td align="center">AUTO-->CAF mode switch</td> +<td align="center">passively reachable states from INACTIVE</td> +<td align="center">Mode switch without trigger,<wbr/> passive transient state is skipped</td> +</tr> +</tbody> +</table> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.afTriggerId"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>control.<wbr/>af<wbr/>Trigger<wbr/>Id + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The ID sent with the latest +CAMERA2_<wbr/>TRIGGER_<wbr/>AUTOFOCUS call</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Must be 0 if no CAMERA2_<wbr/>TRIGGER_<wbr/>AUTOFOCUS trigger +received yet by HAL.<wbr/> Always updated even if AF algorithm +ignores the trigger</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.awbLock"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>awb<wbr/>Lock + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Auto-white balance lock is disabled; the AWB +algorithm is free to update its parameters if in AUTO +mode.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Auto-white balance lock is enabled; the AWB +algorithm will not update its parameters while the lock +is active.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether auto-white balance (AWB) is currently locked to its +latest calculated values.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to <code>true</code> (ON),<wbr/> the AWB algorithm is locked to its latest parameters,<wbr/> +and will not change color balance settings until the lock is set to <code>false</code> (OFF).<wbr/></p> +<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that +get locked do not necessarily correspond to the settings that were present in the +latest capture result received from the camera device,<wbr/> since additional captures +and AWB updates may have occurred even before the result was sent out.<wbr/> If an +application is switching between automatic and manual control and wishes to eliminate +any flicker during the switch,<wbr/> the following procedure is recommended:</p> +<ol> +<li>Starting in auto-AWB mode:</li> +<li>Lock AWB</li> +<li>Wait for the first result to be output that has the AWB locked</li> +<li>Copy AWB settings from that result into a request,<wbr/> set the request to manual AWB</li> +<li>Submit the capture request,<wbr/> proceed to run manual AWB as desired.<wbr/></li> +</ol> +<p>Note that AWB lock is only meaningful when +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> is in the AUTO mode; in other modes,<wbr/> +AWB is already fixed to a specific setting.<wbr/></p> +<p>Some LEGACY devices may not support ON; the value is then overridden to OFF.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.awbMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>awb<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled.<wbr/></p> +<p>The application-selected color transform matrix +(<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>) and gains +(<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>) are used by the camera +device for manual white balance control.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AUTO</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is active.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">INCANDESCENT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses incandescent light as the assumed scene +illumination for white balance.<wbr/></p> +<p>While the exact white balance transforms are up to the +camera device,<wbr/> they will approximately match the CIE +standard illuminant A.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FLUORESCENT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses fluorescent light as the assumed scene +illumination for white balance.<wbr/></p> +<p>While the exact white balance transforms are up to the +camera device,<wbr/> they will approximately match the CIE +standard illuminant F2.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">WARM_FLUORESCENT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses warm fluorescent light as the assumed scene +illumination for white balance.<wbr/></p> +<p>While the exact white balance transforms are up to the +camera device,<wbr/> they will approximately match the CIE +standard illuminant F4.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">DAYLIGHT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses daylight light as the assumed scene +illumination for white balance.<wbr/></p> +<p>While the exact white balance transforms are up to the +camera device,<wbr/> they will approximately match the CIE +standard illuminant D65.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CLOUDY_DAYLIGHT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses cloudy daylight light as the assumed scene +illumination for white balance.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">TWILIGHT</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses twilight light as the assumed scene +illumination for white balance.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SHADE</span> + <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled; +the camera device uses shade light as the assumed scene +illumination for white balance.<wbr/></p> +<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> +and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/> +For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the +values used by the camera device for the transform and gains +will be available in the capture result for this request.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether auto-white balance (AWB) is currently setting the color +transform fields,<wbr/> and what its illumination target +is.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.awbAvailableModes">android.<wbr/>control.<wbr/>awb<wbr/>Available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is AUTO.<wbr/></p> +<p>When set to the ON mode,<wbr/> the camera device's auto-white balance +routine is enabled,<wbr/> overriding the application's selected +<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and +<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/> Note that when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> +is OFF,<wbr/> the behavior of AWB is device dependent.<wbr/> It is recommened to +also set AWB mode to OFF or lock AWB by using <a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> before +setting AE mode to OFF.<wbr/></p> +<p>When set to the OFF mode,<wbr/> the camera device's auto-white balance +routine is disabled.<wbr/> The application manually controls the white +balance by <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> +and <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/></p> +<p>When set to any other modes,<wbr/> the camera device's auto-white +balance routine is disabled.<wbr/> The camera device uses each +particular illumination target for white balance +adjustment.<wbr/> The application's values for +<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> +<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and +<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> are ignored.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.awbRegions"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>awb<wbr/>Regions + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 5 x area_count + </span> + <span class="entry_type_visibility"> [public as meteringRectangle]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of metering areas to use for auto-white-balance illuminant +estimation.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size + </td> + + <td class="entry_range"> + <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Not available if <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a> is 0.<wbr/> +Otherwise will always be present.<wbr/></p> +<p>The maximum number of regions supported by the device is determined by the value +of <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a>.<wbr/></p> +<p>The coordinate system is based on the active pixel array,<wbr/> +with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and +(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/> +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the +bottom-right pixel in the active pixel array.<wbr/></p> +<p>The weight must range from 0 to 1000,<wbr/> and represents a weight +for every pixel in the area.<wbr/> This means that a large metering area +with the same weight as a smaller area will have more effect in +the metering result.<wbr/> Metering areas can partially overlap and the +camera device will add the weights in the overlap region.<wbr/></p> +<p>The weights are relative to weights of other white balance metering regions,<wbr/> so if +only one region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with +0 weight is ignored.<wbr/></p> +<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the +camera device.<wbr/></p> +<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in +capture result metadata,<wbr/> the camera device will ignore the sections outside the crop +region and output only the intersection rectangle as the metering region in the result +metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and +not reported in the result metadata.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL level representation of MeteringRectangle[] is a +int[5 * area_<wbr/>count].<wbr/> +Every five elements represent a metering region of +(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/> +The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but +exclusive on xmax and ymax.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.captureIntent"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>capture<wbr/>Intent + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">CUSTOM</span> + <span class="entry_type_enum_notes"><p>The goal of this request doesn't fall into the other +categories.<wbr/> The camera device will default to preview-like +behavior.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PREVIEW</span> + <span class="entry_type_enum_notes"><p>This request is for a preview-like use case.<wbr/></p> +<p>The precapture trigger may be used to start off a metering +w/<wbr/>flash sequence.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">STILL_CAPTURE</span> + <span class="entry_type_enum_notes"><p>This request is for a still capture-type +use case.<wbr/></p> +<p>If the flash unit is under automatic control,<wbr/> it may fire as needed.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">VIDEO_RECORD</span> + <span class="entry_type_enum_notes"><p>This request is for a video recording +use case.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">VIDEO_SNAPSHOT</span> + <span class="entry_type_enum_notes"><p>This request is for a video snapshot (still +image while recording video) use case.<wbr/></p> +<p>The camera device should take the highest-quality image +possible (given the other settings) without disrupting the +frame rate of video recording.<wbr/> </p></span> + </li> + <li> + <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span> + <span class="entry_type_enum_notes"><p>This request is for a ZSL usecase; the +application will stream full-resolution images and +reprocess one or several later for a final +capture.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MANUAL</span> + <span class="entry_type_enum_notes"><p>This request is for manual capture use case where +the applications want to directly control the capture parameters.<wbr/></p> +<p>For example,<wbr/> the application may wish to manually control +<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> etc.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Information to the camera device 3A (auto-exposure,<wbr/> +auto-focus,<wbr/> auto-white balance) routines about the purpose +of this capture,<wbr/> to help the camera device to decide optimal 3A +strategy.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control (except for MANUAL) is only effective if +<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> != OFF</code> and any 3A routine is active.<wbr/></p> +<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG will be supported if <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> +contains PRIVATE_<wbr/>REPROCESSING or YUV_<wbr/>REPROCESSING.<wbr/> MANUAL will be supported if +<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains MANUAL_<wbr/>SENSOR.<wbr/> Other intent values are +always supported.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.awbState"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>awb<wbr/>State + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">INACTIVE</span> + <span class="entry_type_enum_notes"><p>AWB is not in auto mode,<wbr/> or has not yet started metering.<wbr/></p> +<p>When a camera device is opened,<wbr/> it starts in this +state.<wbr/> This is a transient state,<wbr/> the camera device may +skip reporting this state in capture +result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SEARCHING</span> + <span class="entry_type_enum_notes"><p>AWB doesn't yet have a good set of control +values for the current scene.<wbr/></p> +<p>This is a transient state,<wbr/> the camera device +may skip reporting this state in capture result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CONVERGED</span> + <span class="entry_type_enum_notes"><p>AWB has a good set of control values for the +current scene.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">LOCKED</span> + <span class="entry_type_enum_notes"><p>AWB has been locked.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Current state of auto-white balance (AWB) algorithm.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Switching between or enabling AWB modes (<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>) always +resets the AWB state to INACTIVE.<wbr/> Similarly,<wbr/> switching between <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>,<wbr/> +or <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> if <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code> resets all +the algorithm states to INACTIVE.<wbr/></p> +<p>The camera device can do several state transitions between two results,<wbr/> if it is +allowed by the state transition table.<wbr/> So INACTIVE may never actually be seen in +a result.<wbr/></p> +<p>The state in the result is the state for this image (in sync with this image): if +AWB state becomes CONVERGED,<wbr/> then the image data associated with this result should +be good to use.<wbr/></p> +<p>Below are state transition tables for different AWB modes.<wbr/></p> +<p>When <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != AWB_<wbr/>MODE_<wbr/>AUTO</code>:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center"></td> +<td align="center">INACTIVE</td> +<td align="center">Camera device auto white balance algorithm is disabled</td> +</tr> +</tbody> +</table> +<p>When <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> is AWB_<wbr/>MODE_<wbr/>AUTO:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center">Camera device initiates AWB scan</td> +<td align="center">SEARCHING</td> +<td align="center">Values changing</td> +</tr> +<tr> +<td align="center">INACTIVE</td> +<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is ON</td> +<td align="center">LOCKED</td> +<td align="center">Values locked</td> +</tr> +<tr> +<td align="center">SEARCHING</td> +<td align="center">Camera device finishes AWB scan</td> +<td align="center">CONVERGED</td> +<td align="center">Good values,<wbr/> not changing</td> +</tr> +<tr> +<td align="center">SEARCHING</td> +<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is ON</td> +<td align="center">LOCKED</td> +<td align="center">Values locked</td> +</tr> +<tr> +<td align="center">CONVERGED</td> +<td align="center">Camera device initiates AWB scan</td> +<td align="center">SEARCHING</td> +<td align="center">Values changing</td> +</tr> +<tr> +<td align="center">CONVERGED</td> +<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is ON</td> +<td align="center">LOCKED</td> +<td align="center">Values locked</td> +</tr> +<tr> +<td align="center">LOCKED</td> +<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is OFF</td> +<td align="center">SEARCHING</td> +<td align="center">Values not good after unlock</td> +</tr> +</tbody> +</table> +<p>For the above table,<wbr/> the camera device may skip reporting any state changes that happen +without application intervention (i.<wbr/>e.<wbr/> mode switch,<wbr/> trigger,<wbr/> locking).<wbr/> Any state that +can be skipped in that manner is called a transient state.<wbr/></p> +<p>For example,<wbr/> for this AWB mode (AWB_<wbr/>MODE_<wbr/>AUTO),<wbr/> in addition to the state transitions +listed in above table,<wbr/> it is also legal for the camera device to skip one or more +transient states between two results.<wbr/> See below table for examples:</p> +<table> +<thead> +<tr> +<th align="center">State</th> +<th align="center">Transition Cause</th> +<th align="center">New State</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">INACTIVE</td> +<td align="center">Camera device finished AWB scan</td> +<td align="center">CONVERGED</td> +<td align="center">Values are already good,<wbr/> transient states are skipped by camera device.<wbr/></td> +</tr> +<tr> +<td align="center">LOCKED</td> +<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is OFF</td> +<td align="center">CONVERGED</td> +<td align="center">Values good after unlock,<wbr/> transient states are skipped by camera device.<wbr/></td> +</tr> +</tbody> +</table> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.effectMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>effect<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No color effect will be applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MONO</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "monocolor" effect where the image is mapped into +a single color.<wbr/></p> +<p>This will typically be grayscale.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">NEGATIVE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "photo-negative" effect where the image's colors +are inverted.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SOLARIZE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "solarisation" effect (Sabattier effect) where the +image is wholly or partially reversed in +tone.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SEPIA</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "sepia" effect where the image is mapped into warm +gray,<wbr/> red,<wbr/> and brown tones.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">POSTERIZE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "posterization" effect where the image uses +discrete regions of tone rather than a continuous +gradient of tones.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">WHITEBOARD</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "whiteboard" effect where the image is typically displayed +as regions of white,<wbr/> with black or grey details.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">BLACKBOARD</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>A "blackboard" effect where the image is typically displayed +as regions of black,<wbr/> with white or grey details.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AQUA</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>An "aqua" effect where a blue hue is added to the image.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A special color effect to apply.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.availableEffects">android.<wbr/>control.<wbr/>available<wbr/>Effects</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When this mode is set,<wbr/> a color effect will be applied +to images produced by the camera device.<wbr/> The interpretation +and implementation of these color effects is left to the +implementor of the camera device,<wbr/> and should not be +depended on to be consistent (or present) across all +devices.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Full application control of pipeline.<wbr/></p> +<p>All control by the device's metering and focusing (3A) +routines is disabled,<wbr/> and no other settings in +android.<wbr/>control.<wbr/>* have any effect,<wbr/> except that +<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> may be used by the camera +device to select post-processing values for processing +blocks that do not allow for manual control,<wbr/> or are not +exposed by the camera API.<wbr/></p> +<p>However,<wbr/> the camera device's 3A routines may continue to +collect statistics and update their internal state so that +when control is switched to AUTO mode,<wbr/> good control values +can be immediately applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">AUTO</span> + <span class="entry_type_enum_notes"><p>Use settings for each individual 3A routine.<wbr/></p> +<p>Manual control of capture parameters is disabled.<wbr/> All +controls in android.<wbr/>control.<wbr/>* besides sceneMode take +effect.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">USE_SCENE_MODE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Use a specific scene mode.<wbr/></p> +<p>Enabling this disables control.<wbr/>aeMode,<wbr/> control.<wbr/>awbMode and +control.<wbr/>afMode controls; the camera device will ignore +those settings while USE_<wbr/>SCENE_<wbr/>MODE is active (except for +FACE_<wbr/>PRIORITY scene mode).<wbr/> Other control entries are still active.<wbr/> +This setting can only be used if scene mode is supported (i.<wbr/>e.<wbr/> +<a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a> +contain some modes other than DISABLED).<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">OFF_KEEP_STATE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Same as OFF mode,<wbr/> except that this capture will not be +used by camera device background auto-exposure,<wbr/> auto-white balance and +auto-focus algorithms (3A) to update their statistics.<wbr/></p> +<p>Specifically,<wbr/> the 3A routines are locked to the last +values set from a request with AUTO,<wbr/> OFF,<wbr/> or +USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> and any statistics or state updates +collected from manual captures with OFF_<wbr/>KEEP_<wbr/>STATE will be +discarded by the camera device.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Overall mode of 3A (auto-exposure,<wbr/> auto-white-balance,<wbr/> auto-focus) control +routines.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.availableModes">android.<wbr/>control.<wbr/>available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is a top-level 3A control switch.<wbr/> When set to OFF,<wbr/> all 3A control +by the camera device is disabled.<wbr/> The application must set the fields for +capture parameters itself.<wbr/></p> +<p>When set to AUTO,<wbr/> the individual algorithm controls in +android.<wbr/>control.<wbr/>* are in effect,<wbr/> such as <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>.<wbr/></p> +<p>When set to USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> the individual controls in +android.<wbr/>control.<wbr/>* are mostly disabled,<wbr/> and the camera device implements +one of the scene mode settings (such as ACTION,<wbr/> SUNSET,<wbr/> or PARTY) +as it wishes.<wbr/> The camera device scene mode 3A settings are provided by +<a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">capture results</a>.<wbr/></p> +<p>When set to OFF_<wbr/>KEEP_<wbr/>STATE,<wbr/> it is similar to OFF mode,<wbr/> the only difference +is that this frame will not be used by camera device background 3A statistics +update,<wbr/> as if this frame is never captured.<wbr/> This mode can be used in the scenario +where the application doesn't want a 3A manual control capture to affect +the subsequent auto 3A capture results.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.sceneMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>control.<wbr/>scene<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">DISABLED</span> + <span class="entry_type_enum_value">0</span> + <span class="entry_type_enum_notes"><p>Indicates that no scene modes are set for a given capture request.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FACE_PRIORITY</span> + <span class="entry_type_enum_notes"><p>If face detection support exists,<wbr/> use face +detection data for auto-focus,<wbr/> auto-white balance,<wbr/> and +auto-exposure routines.<wbr/></p> +<p>If face detection statistics are disabled +(i.<wbr/>e.<wbr/> <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> is set to OFF),<wbr/> +this should still operate correctly (but will not return +face detection statistics to the framework).<wbr/></p> +<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> +remain active when FACE_<wbr/>PRIORITY is set.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ACTION</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving objects.<wbr/></p> +<p>Similar to SPORTS.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PORTRAIT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for still photos of people.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">LANDSCAPE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for photos of distant macroscopic objects.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">NIGHT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for low-light settings.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">NIGHT_PORTRAIT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for still photos of people in low-light +settings.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">THEATRE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings where flash must +remain off.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">BEACH</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor beach settings.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SNOW</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor settings containing snow.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SUNSET</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for scenes of the setting sun.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">STEADYPHOTO</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized to avoid blurry photos due to small amounts of +device motion (for example: due to hand shake).<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FIREWORKS</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for nighttime photos of fireworks.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SPORTS</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving people.<wbr/></p> +<p>Similar to ACTION.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PARTY</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings with multiple moving +people.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CANDLELIGHT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for dim settings where the main light source +is a flame.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">BARCODE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optimized for accurately capturing a photo of barcode +for use by camera applications that wish to read the +barcode value.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_SPEED_VIDEO</span> + <span class="entry_type_enum_deprecated">[deprecated]</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>This is deprecated,<wbr/> please use <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a> +and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a> +for high speed video recording.<wbr/></p> +<p>Optimized for high speed video recording (frame rate >=60fps) use case.<wbr/></p> +<p>The supported high speed video sizes and fps ranges are specified in +<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> To get desired +output frame rates,<wbr/> the application is only allowed to select video size +and fps range combinations listed in this static metadata.<wbr/> The fps range +can be control via <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a>.<wbr/></p> +<p>In this mode,<wbr/> the camera device will override aeMode,<wbr/> awbMode,<wbr/> and afMode to +ON,<wbr/> ON,<wbr/> and CONTINUOUS_<wbr/>VIDEO,<wbr/> respectively.<wbr/> All post-processing block mode +controls will be overridden to be FAST.<wbr/> Therefore,<wbr/> no manual control of capture +and post-processing parameters is possible.<wbr/> All other controls operate the +same as when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == AUTO.<wbr/> This means that all other +android.<wbr/>control.<wbr/>* fields continue to work,<wbr/> such as</p> +<ul> +<li><a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a></li> +<li><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a></li> +<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li> +<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li> +<li><a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></li> +<li><a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a></li> +<li><a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a></li> +<li><a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a></li> +<li><a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a></li> +<li><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a></li> +</ul> +<p>Outside of android.<wbr/>control.<wbr/>*,<wbr/> the following controls will work:</p> +<ul> +<li><a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> (automatic flash for still capture will not work since aeMode is ON)</li> +<li><a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> (if it is supported)</li> +<li><a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a></li> +<li><a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a></li> +</ul> +<p>For high speed recording use case,<wbr/> the actual maximum supported frame rate may +be lower than what camera can output,<wbr/> depending on the destination Surfaces for +the image data.<wbr/> For example,<wbr/> if the destination surface is from video encoder,<wbr/> +the application need check if the video encoder is capable of supporting the +high frame rate for a given video size,<wbr/> or it will end up with lower recording +frame rate.<wbr/> If the destination surface is from preview window,<wbr/> the preview frame +rate will be bounded by the screen refresh rate.<wbr/></p> +<p>The camera device will only support up to 2 output high speed streams +(processed non-stalling format defined in <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>) +in this mode.<wbr/> This control will be effective only if all of below conditions are true:</p> +<ul> +<li>The application created no more than maxNumHighSpeedStreams processed non-stalling +format output streams,<wbr/> where maxNumHighSpeedStreams is calculated as +min(2,<wbr/> <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>[Processed (but not-stalling)]).<wbr/></li> +<li>The stream sizes are selected from the sizes reported by +<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/></li> +<li>No processed non-stalling or raw streams are configured.<wbr/></li> +</ul> +<p>When above conditions are NOT satistied,<wbr/> the controls of this mode and +<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> will be ignored by the camera device,<wbr/> +the camera device will fall back to <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> <code>==</code> AUTO,<wbr/> +and the returned capture result metadata will give the fps range choosen +by the camera device.<wbr/></p> +<p>Switching into or out of this mode may trigger some camera ISP/<wbr/>sensor +reconfigurations,<wbr/> which may introduce extra latency.<wbr/> It is recommended that +the application avoids unnecessary scene mode switch as much as possible.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HDR</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Turn on a device-specific high dynamic range (HDR) mode.<wbr/></p> +<p>In this scene mode,<wbr/> the camera device captures images +that keep a larger range of scene illumination levels +visible in the final image.<wbr/> For example,<wbr/> when taking a +picture of a object in front of a bright window,<wbr/> both +the object and the scene through the window may be +visible when using HDR mode,<wbr/> while in normal AUTO mode,<wbr/> +one or the other may be poorly exposed.<wbr/> As a tradeoff,<wbr/> +HDR mode generally takes much longer to capture a single +image,<wbr/> has no user control,<wbr/> and may have other artifacts +depending on the HDR method used.<wbr/></p> +<p>Therefore,<wbr/> HDR captures operate at a much slower rate +than regular captures.<wbr/></p> +<p>In this mode,<wbr/> on LIMITED or FULL devices,<wbr/> when a request +is made with a <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> of +STILL_<wbr/>CAPTURE,<wbr/> the camera device will capture an image +using a high dynamic range capture technique.<wbr/> On LEGACY +devices,<wbr/> captures that target a JPEG-format output will +be captured with HDR,<wbr/> and the capture intent is not +relevant.<wbr/></p> +<p>The HDR capture may involve the device capturing a burst +of images internally and combining them into one,<wbr/> or it +may involve the device using specialized high dynamic +range capture hardware.<wbr/> In all cases,<wbr/> a single image is +produced in response to a capture request submitted +while in HDR mode.<wbr/></p> +<p>Since substantial post-processing is generally needed to +produce an HDR image,<wbr/> only YUV,<wbr/> PRIVATE,<wbr/> and JPEG +outputs are supported for LIMITED/<wbr/>FULL device HDR +captures,<wbr/> and only JPEG outputs are supported for LEGACY +HDR captures.<wbr/> Using a RAW output for HDR capture is not +supported.<wbr/></p> +<p>Some devices may also support always-on HDR,<wbr/> which +applies HDR processing at full frame rate.<wbr/> For these +devices,<wbr/> intents other than STILL_<wbr/>CAPTURE will also +produce an HDR output with no frame rate impact compared +to normal operation,<wbr/> though the quality may be lower +than for STILL_<wbr/>CAPTURE intents.<wbr/></p> +<p>If SCENE_<wbr/>MODE_<wbr/>HDR is used with unsupported output types +or capture intents,<wbr/> the images captured will be as if +the SCENE_<wbr/>MODE was not enabled at all.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FACE_PRIORITY_LOW_LIGHT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_hidden">[hidden]</span> + <span class="entry_type_enum_notes"><p>Same as FACE_<wbr/>PRIORITY scene mode,<wbr/> except that the camera +device will choose higher sensitivity values (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>) +under low light conditions.<wbr/></p> +<p>The camera device may be tuned to expose the images in a reduced +sensitivity range to produce the best quality images.<wbr/> For example,<wbr/> +if the <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> gives range of [100,<wbr/> 1600],<wbr/> +the camera device auto-exposure routine tuning process may limit the actual +exposure sensitivity range to [100,<wbr/> 1200] to ensure that the noise level isn't +exessive in order to preserve the image quality.<wbr/> Under this situation,<wbr/> the image under +low light may be under-exposed when the sensor max exposure time (bounded by the +<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of the +ON_<wbr/>* modes) and effective max sensitivity are reached.<wbr/> This scene mode allows the +camera device auto-exposure routine to increase the sensitivity up to the max +sensitivity specified by <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> when the scene is too +dark and the max exposure time is reached.<wbr/> The captured images may be noisier +compared with the images captured in normal FACE_<wbr/>PRIORITY mode; therefore,<wbr/> it is +recommended that the application only use this scene mode when it is capable of +reducing the noise level of the captured images.<wbr/></p> +<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> +remain active when FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT is set.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">DEVICE_CUSTOM_START</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_hidden">[hidden]</span> + <span class="entry_type_enum_value">100</span> + <span class="entry_type_enum_notes"><p>Scene mode values within the range of +<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific +customized scene modes.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">DEVICE_CUSTOM_END</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_hidden">[hidden]</span> + <span class="entry_type_enum_value">127</span> + <span class="entry_type_enum_notes"><p>Scene mode values within the range of +<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific +customized scene modes.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Control for which scene mode is currently active.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Scene modes are custom camera modes optimized for a certain set of conditions and +capture settings.<wbr/></p> +<p>This is the mode that that is active when +<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code>.<wbr/> Aside from FACE_<wbr/>PRIORITY,<wbr/> these modes will +disable <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> +while in use.<wbr/></p> +<p>The interpretation and implementation of these scene modes is left +to the implementor of the camera device.<wbr/> Their behavior will not be +consistent across all devices,<wbr/> and any given device may only implement +a subset of these modes.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL implementations that include scene modes are expected to provide +the per-scene settings to use for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> in +<a href="#static_android.control.sceneModeOverrides">android.<wbr/>control.<wbr/>scene<wbr/>Mode<wbr/>Overrides</a>.<wbr/></p> +<p>For HIGH_<wbr/>SPEED_<wbr/>VIDEO mode,<wbr/> if it is included in <a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>,<wbr/> +the HAL must list supported video size and fps range in +<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> For a given size,<wbr/> e.<wbr/>g.<wbr/> +1280x720,<wbr/> if the HAL has two different sensor configurations for normal streaming +mode and high speed streaming,<wbr/> when this scene mode is set/<wbr/>reset in a sequence of capture +requests,<wbr/> the HAL may have to switch between different sensor modes.<wbr/> +This mode is deprecated in HAL3.<wbr/>3,<wbr/> to support high speed video recording,<wbr/> please implement +<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a> and CONSTRAINED_<wbr/>HIGH_<wbr/>SPEED_<wbr/>VIDEO +capbility defined in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.videoStabilizationMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Video stabilization is disabled.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Video stabilization is enabled.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether video stabilization is +active.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Video stabilization automatically warps images from +the camera in order to stabilize motion between consecutive frames.<wbr/></p> +<p>If enabled,<wbr/> video stabilization can modify the +<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> to keep the video stream stabilized.<wbr/></p> +<p>Switching between different video stabilization modes may take several +frames to initialize,<wbr/> the camera device will report the current mode +in capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/> +the video stabilization modes in the first several capture results may +still be "OFF",<wbr/> and it will become "ON" when the initialization is +done.<wbr/></p> +<p>In addition,<wbr/> not all recording sizes or frame rates may be supported for +stabilization by a device that reports stabilization support.<wbr/> It is guaranteed +that an output targeting a MediaRecorder or MediaCodec will be stabilized if +the recording resolution is less than or equal to 1920 x 1080 (width less than +or equal to 1920,<wbr/> height less than or equal to 1080),<wbr/> and the recording +frame rate is less than or equal to 30fps.<wbr/> At other sizes,<wbr/> the CaptureResult +<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a> field will return +OFF if the recording output is not stabilized,<wbr/> or if there are no output +Surface types that can be stabilized.<wbr/></p> +<p>If a camera device supports both this mode and OIS +(<a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may +produce undesirable interaction,<wbr/> so it is recommended not to enable +both at the same time.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.control.postRawSensitivityBoost"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The amount of additional sensitivity boost applied to output images +after RAW sensor data is captured.<wbr/></p> + </td> + + <td class="entry_units"> + ISO arithmetic units,<wbr/> the same as android.<wbr/>sensor.<wbr/>sensitivity + </td> + + <td class="entry_range"> + <p><a href="#static_android.control.postRawSensitivityBoostRange">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost<wbr/>Range</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Some camera devices support additional digital sensitivity boosting in the +camera processing pipeline after sensor RAW image is captured.<wbr/> +Such a boost will be applied to YUV/<wbr/>JPEG format output images but will not +have effect on RAW output formats like RAW_<wbr/>SENSOR,<wbr/> RAW10,<wbr/> RAW12 or RAW_<wbr/>OPAQUE.<wbr/></p> +<p>This key will be <code>null</code> for devices that do not support any RAW format +outputs.<wbr/> For devices that do support RAW format outputs,<wbr/> this key will always +present,<wbr/> and if a device does not support post RAW sensitivity boost,<wbr/> it will +list <code>100</code> in this key.<wbr/></p> +<p>If the camera device cannot apply the exact boost requested,<wbr/> it will reduce the +boost to the nearest supported value.<wbr/> +The final boost value used will be available in the output capture result.<wbr/></p> +<p>For devices that support post RAW sensitivity boost,<wbr/> the YUV/<wbr/>JPEG output images +of such device will have the total sensitivity of +<code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> * <a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> /<wbr/> 100</code> +The sensitivity of RAW format images will always be <code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></code></p> +<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to +OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_demosaic" class="section">demosaic</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.demosaic.mode"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>demosaic.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Minimal or no slowdown of frame rate compared to +Bayer RAW output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>Improved processing quality but the frame rate might be slowed down +relative to raw output.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Controls the quality of the demosaicing +processing.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_edge" class="section">edge</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.edge.mode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>edge.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No edge enhancement is applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Apply edge enhancement at a quality level that does not slow down frame rate +relative to sensor output.<wbr/> It may be the same as OFF if edge enhancement will +slow down frame rate relative to sensor.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>Apply high-quality edge enhancement,<wbr/> at a cost of possibly reduced output frame rate.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Edge enhancement is applied at different levels for different output streams,<wbr/> +based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have +edge enhancement applied,<wbr/> while higher-resolution streams have no edge enhancement +applied.<wbr/> The level of edge enhancement for low-resolution streams is tuned so that +frame rate is not impacted,<wbr/> and the quality is equal to or better than FAST (since it +is only applied to lower-resolution outputs,<wbr/> quality may improve from FAST).<wbr/></p> +<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode +with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures +high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is +produced via reprocessing when a user takes a picture.<wbr/> For such a use case,<wbr/> the +high-resolution buffers must not have edge enhancement applied to maximize efficiency of +preview and to avoid double-applying enhancement when reprocessed,<wbr/> while low-resolution +buffers (used for recording or preview,<wbr/> generally) need edge enhancement applied for +reasonable preview quality.<wbr/></p> +<p>This mode is guaranteed to be supported by devices that support either the +YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities +(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will +be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operation mode for edge +enhancement.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Edge enhancement improves sharpness and details in the captured image.<wbr/> OFF means +no enhancement will be applied by the camera device.<wbr/></p> +<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined enhancement +will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the +camera device will use the highest-quality enhancement algorithms,<wbr/> +even if it slows down capture rate.<wbr/> FAST means the camera device will +not slow down capture rate when applying edge enhancement.<wbr/> FAST may be the same as OFF if +edge enhancement will slow down capture rate.<wbr/> Every output stream will have a similar +amount of enhancement applied.<wbr/></p> +<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular +buffer of high-resolution images during preview and reprocess image(s) from that buffer +into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies +edge enhancement to low-resolution streams (below maximum recording resolution) to +maximize preview quality,<wbr/> but does not apply edge enhancement to high-resolution streams,<wbr/> +since those will be reprocessed later if necessary.<wbr/></p> +<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera +device will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV-domain edge enhancement,<wbr/> respectively.<wbr/> +The camera device may adjust its internal edge enhancement parameters for best +image quality based on the <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a>,<wbr/> if it is set.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to +adjust the internal edge enhancement reduction parameters appropriately to get the best +quality images.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.edge.strength"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>edge.<wbr/>strength + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Control the amount of edge enhancement +applied to the images</p> + </td> + + <td class="entry_units"> + 1-10; 10 is maximum sharpening + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.edge.availableEdgeModes"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of edge enhancement modes for <a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a> that are supported by this camera +device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Full-capability camera devices must always support OFF; camera devices that support +YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING will list ZERO_<wbr/>SHUTTER_<wbr/>LAG; all devices will +list FAST.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if edge enhancement control is available +on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/> +That is,<wbr/> if the highest quality implementation on the camera device does not slow down +capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.edge.mode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>edge.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No edge enhancement is applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Apply edge enhancement at a quality level that does not slow down frame rate +relative to sensor output.<wbr/> It may be the same as OFF if edge enhancement will +slow down frame rate relative to sensor.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>Apply high-quality edge enhancement,<wbr/> at a cost of possibly reduced output frame rate.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Edge enhancement is applied at different levels for different output streams,<wbr/> +based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have +edge enhancement applied,<wbr/> while higher-resolution streams have no edge enhancement +applied.<wbr/> The level of edge enhancement for low-resolution streams is tuned so that +frame rate is not impacted,<wbr/> and the quality is equal to or better than FAST (since it +is only applied to lower-resolution outputs,<wbr/> quality may improve from FAST).<wbr/></p> +<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode +with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures +high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is +produced via reprocessing when a user takes a picture.<wbr/> For such a use case,<wbr/> the +high-resolution buffers must not have edge enhancement applied to maximize efficiency of +preview and to avoid double-applying enhancement when reprocessed,<wbr/> while low-resolution +buffers (used for recording or preview,<wbr/> generally) need edge enhancement applied for +reasonable preview quality.<wbr/></p> +<p>This mode is guaranteed to be supported by devices that support either the +YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities +(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will +be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operation mode for edge +enhancement.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Edge enhancement improves sharpness and details in the captured image.<wbr/> OFF means +no enhancement will be applied by the camera device.<wbr/></p> +<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined enhancement +will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the +camera device will use the highest-quality enhancement algorithms,<wbr/> +even if it slows down capture rate.<wbr/> FAST means the camera device will +not slow down capture rate when applying edge enhancement.<wbr/> FAST may be the same as OFF if +edge enhancement will slow down capture rate.<wbr/> Every output stream will have a similar +amount of enhancement applied.<wbr/></p> +<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular +buffer of high-resolution images during preview and reprocess image(s) from that buffer +into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies +edge enhancement to low-resolution streams (below maximum recording resolution) to +maximize preview quality,<wbr/> but does not apply edge enhancement to high-resolution streams,<wbr/> +since those will be reprocessed later if necessary.<wbr/></p> +<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera +device will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV-domain edge enhancement,<wbr/> respectively.<wbr/> +The camera device may adjust its internal edge enhancement parameters for best +image quality based on the <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a>,<wbr/> if it is set.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to +adjust the internal edge enhancement reduction parameters appropriately to get the best +quality images.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_flash" class="section">flash</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.flash.firingPower"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>flash.<wbr/>firing<wbr/>Power + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Power for flash firing/<wbr/>torch</p> + </td> + + <td class="entry_units"> + 10 is max power; 0 is no flash.<wbr/> Linear + </td> + + <td class="entry_range"> + <p>0 - 10</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Power for snapshot may use a different scale than +for torch mode.<wbr/> Only one entry for torch mode will be +used</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.flash.firingTime"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>flash.<wbr/>firing<wbr/>Time + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Firing time of flash relative to start of +exposure</p> + </td> + + <td class="entry_units"> + nanoseconds + </td> + + <td class="entry_range"> + <p>0-(exposure time-flash duration)</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Clamped to (0,<wbr/> exposure time - flash +duration).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.flash.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>flash.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Do not fire the flash for this capture.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SINGLE</span> + <span class="entry_type_enum_notes"><p>If the flash is available and charged,<wbr/> fire flash +for this capture.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">TORCH</span> + <span class="entry_type_enum_notes"><p>Transition flash to continuously on.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired mode for for the camera device's flash control.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control is only effective when flash unit is available +(<code><a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> == true</code>).<wbr/></p> +<p>When this control is used,<wbr/> the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> must be set to ON or OFF.<wbr/> +Otherwise,<wbr/> the camera device auto-exposure related flash control (ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> +ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> or ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE) will override this control.<wbr/></p> +<p>When set to OFF,<wbr/> the camera device will not fire flash for this capture.<wbr/></p> +<p>When set to SINGLE,<wbr/> the camera device will fire flash regardless of the camera +device's auto-exposure routine's result.<wbr/> When used in still capture case,<wbr/> this +control should be used along with auto-exposure (AE) precapture metering sequence +(<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>),<wbr/> otherwise,<wbr/> the image may be incorrectly exposed.<wbr/></p> +<p>When set to TORCH,<wbr/> the flash will be on continuously.<wbr/> This mode can be used +for use cases such as preview,<wbr/> auto-focus assist,<wbr/> still capture,<wbr/> or video recording.<wbr/></p> +<p>The flash status will be reported by <a href="#dynamic_android.flash.state">android.<wbr/>flash.<wbr/>state</a> in the capture result metadata.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + + + <tr class="entry" id="static_android.flash.info.available"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>flash.<wbr/>info.<wbr/>available + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">FALSE</span> + </li> + <li> + <span class="entry_type_enum_name">TRUE</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether this camera device has a +flash unit.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Will be <code>false</code> if no flash is available.<wbr/></p> +<p>If there is no flash unit,<wbr/> none of the flash controls do +anything.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.flash.info.chargeDuration"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>flash.<wbr/>info.<wbr/>charge<wbr/>Duration + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Time taken before flash can fire +again</p> + </td> + + <td class="entry_units"> + nanoseconds + </td> + + <td class="entry_range"> + <p>0-1e9</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>1 second too long/<wbr/>too short for recharge? Should +this be power-dependent?</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + + + <tr class="entry" id="static_android.flash.colorTemperature"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>flash.<wbr/>color<wbr/>Temperature + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The x,<wbr/>y whitepoint of the +flash</p> + </td> + + <td class="entry_units"> + pair of floats + </td> + + <td class="entry_range"> + <p>0-1 for both</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.flash.maxEnergy"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>flash.<wbr/>max<wbr/>Energy + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Max energy output of the flash for a full +power single flash</p> + </td> + + <td class="entry_units"> + lumen-seconds + </td> + + <td class="entry_range"> + <p>>= 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.flash.firingPower"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>flash.<wbr/>firing<wbr/>Power + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Power for flash firing/<wbr/>torch</p> + </td> + + <td class="entry_units"> + 10 is max power; 0 is no flash.<wbr/> Linear + </td> + + <td class="entry_range"> + <p>0 - 10</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Power for snapshot may use a different scale than +for torch mode.<wbr/> Only one entry for torch mode will be +used</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.flash.firingTime"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>flash.<wbr/>firing<wbr/>Time + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Firing time of flash relative to start of +exposure</p> + </td> + + <td class="entry_units"> + nanoseconds + </td> + + <td class="entry_range"> + <p>0-(exposure time-flash duration)</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Clamped to (0,<wbr/> exposure time - flash +duration).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.flash.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>flash.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Do not fire the flash for this capture.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SINGLE</span> + <span class="entry_type_enum_notes"><p>If the flash is available and charged,<wbr/> fire flash +for this capture.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">TORCH</span> + <span class="entry_type_enum_notes"><p>Transition flash to continuously on.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired mode for for the camera device's flash control.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control is only effective when flash unit is available +(<code><a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> == true</code>).<wbr/></p> +<p>When this control is used,<wbr/> the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> must be set to ON or OFF.<wbr/> +Otherwise,<wbr/> the camera device auto-exposure related flash control (ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> +ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> or ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE) will override this control.<wbr/></p> +<p>When set to OFF,<wbr/> the camera device will not fire flash for this capture.<wbr/></p> +<p>When set to SINGLE,<wbr/> the camera device will fire flash regardless of the camera +device's auto-exposure routine's result.<wbr/> When used in still capture case,<wbr/> this +control should be used along with auto-exposure (AE) precapture metering sequence +(<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>),<wbr/> otherwise,<wbr/> the image may be incorrectly exposed.<wbr/></p> +<p>When set to TORCH,<wbr/> the flash will be on continuously.<wbr/> This mode can be used +for use cases such as preview,<wbr/> auto-focus assist,<wbr/> still capture,<wbr/> or video recording.<wbr/></p> +<p>The flash status will be reported by <a href="#dynamic_android.flash.state">android.<wbr/>flash.<wbr/>state</a> in the capture result metadata.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.flash.state"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>flash.<wbr/>state + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">UNAVAILABLE</span> + <span class="entry_type_enum_notes"><p>No flash on camera.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CHARGING</span> + <span class="entry_type_enum_notes"><p>Flash is charging and cannot be fired.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">READY</span> + <span class="entry_type_enum_notes"><p>Flash is ready to fire.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FIRED</span> + <span class="entry_type_enum_notes"><p>Flash fired for this capture.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PARTIAL</span> + <span class="entry_type_enum_notes"><p>Flash partially illuminated this frame.<wbr/></p> +<p>This is usually due to the next or previous frame having +the flash fire,<wbr/> and the flash spilling into this capture +due to hardware limitations.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Current state of the flash +unit.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When the camera device doesn't have flash unit +(i.<wbr/>e.<wbr/> <code><a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> == false</code>),<wbr/> this state will always be UNAVAILABLE.<wbr/> +Other states indicate the current flash status.<wbr/></p> +<p>In certain conditions,<wbr/> this will be available on LEGACY devices:</p> +<ul> +<li>Flash-less cameras always return UNAVAILABLE.<wbr/></li> +<li>Using <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>==</code> ON_<wbr/>ALWAYS_<wbr/>FLASH + will always return FIRED.<wbr/></li> +<li>Using <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> <code>==</code> TORCH + will always return FIRED.<wbr/></li> +</ul> +<p>In all other conditions the state will not be available on +LEGACY devices (i.<wbr/>e.<wbr/> it will be <code>null</code>).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_hotPixel" class="section">hotPixel</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.hotPixel.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>hot<wbr/>Pixel.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No hot pixel correction is applied.<wbr/></p> +<p>The frame rate must not be reduced relative to sensor raw output +for this option.<wbr/></p> +<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Hot pixel correction is applied,<wbr/> without reducing frame +rate relative to sensor raw output.<wbr/></p> +<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>High-quality hot pixel correction is applied,<wbr/> at a cost +of possibly reduced frame rate relative to sensor raw output.<wbr/></p> +<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operational mode for hot pixel correction.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.hotPixel.availableHotPixelModes">android.<wbr/>hot<wbr/>Pixel.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Hotpixel correction interpolates out,<wbr/> or otherwise removes,<wbr/> pixels +that do not accurately measure the incoming light (i.<wbr/>e.<wbr/> pixels that +are stuck at an arbitrary value or are oversensitive).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.hotPixel.availableHotPixelModes"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>hot<wbr/>Pixel.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of hot pixel correction modes for <a href="#controls_android.hotPixel.mode">android.<wbr/>hot<wbr/>Pixel.<wbr/>mode</a> that are supported by this +camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.hotPixel.mode">android.<wbr/>hot<wbr/>Pixel.<wbr/>mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>FULL mode camera devices will always support FAST.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>To avoid performance issues,<wbr/> there will be significantly fewer hot +pixels than actual pixels on the camera sensor.<wbr/> +HAL must support both FAST and HIGH_<wbr/>QUALITY if hot pixel correction control is available +on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/> +That is,<wbr/> if the highest quality implementation on the camera device does not slow down +capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.hotPixel.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>hot<wbr/>Pixel.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No hot pixel correction is applied.<wbr/></p> +<p>The frame rate must not be reduced relative to sensor raw output +for this option.<wbr/></p> +<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Hot pixel correction is applied,<wbr/> without reducing frame +rate relative to sensor raw output.<wbr/></p> +<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>High-quality hot pixel correction is applied,<wbr/> at a cost +of possibly reduced frame rate relative to sensor raw output.<wbr/></p> +<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operational mode for hot pixel correction.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.hotPixel.availableHotPixelModes">android.<wbr/>hot<wbr/>Pixel.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Hotpixel correction interpolates out,<wbr/> or otherwise removes,<wbr/> pixels +that do not accurately measure the incoming light (i.<wbr/>e.<wbr/> pixels that +are stuck at an arbitrary value or are oversensitive).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_jpeg" class="section">jpeg</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.jpeg.gpsLocation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>jpeg.<wbr/>gps<wbr/>Location + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [java_public as location]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A location object to use when generating image GPS metadata.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Setting a location object in a request will include the GPS coordinates of the location +into any JPEG images captured based on the request.<wbr/> These coordinates can then be +viewed by anyone who receives the JPEG image.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.jpeg.gpsCoordinates"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>jpeg.<wbr/>gps<wbr/>Coordinates + </td> + <td class="entry_type"> + <span class="entry_type_name">double</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">latitude,<wbr/> longitude,<wbr/> altitude.<wbr/> First two in degrees,<wbr/> the third in meters</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>GPS coordinates to include in output JPEG +EXIF.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>(-180 - 180],<wbr/> [-90,<wbr/>90],<wbr/> [-inf,<wbr/> inf]</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.jpeg.gpsProcessingMethod"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>jpeg.<wbr/>gps<wbr/>Processing<wbr/>Method + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [ndk_public as string]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>32 characters describing GPS algorithm to +include in EXIF.<wbr/></p> + </td> + + <td class="entry_units"> + UTF-8 null-terminated string + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.jpeg.gpsTimestamp"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>jpeg.<wbr/>gps<wbr/>Timestamp + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Time GPS fix was made to include in +EXIF.<wbr/></p> + </td> + + <td class="entry_units"> + UTC in seconds since January 1,<wbr/> 1970 + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.jpeg.orientation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>jpeg.<wbr/>orientation + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The orientation for a JPEG image.<wbr/></p> + </td> + + <td class="entry_units"> + Degrees in multiples of 90 + </td> + + <td class="entry_range"> + <p>0,<wbr/> 90,<wbr/> 180,<wbr/> 270</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The clockwise rotation angle in degrees,<wbr/> relative to the orientation +to the camera,<wbr/> that the JPEG picture needs to be rotated by,<wbr/> to be viewed +upright.<wbr/></p> +<p>Camera devices may either encode this value into the JPEG EXIF header,<wbr/> or +rotate the image data to match this orientation.<wbr/> When the image data is rotated,<wbr/> +the thumbnail data will also be rotated.<wbr/></p> +<p>Note that this orientation is relative to the orientation of the camera sensor,<wbr/> given +by <a href="#static_android.sensor.orientation">android.<wbr/>sensor.<wbr/>orientation</a>.<wbr/></p> +<p>To translate from the device orientation given by the Android sensor APIs,<wbr/> the following +sample code may be used:</p> +<pre><code>private int getJpegOrientation(CameraCharacteristics c,<wbr/> int deviceOrientation) { + if (deviceOrientation == android.<wbr/>view.<wbr/>Orientation<wbr/>Event<wbr/>Listener.<wbr/>ORIENTATION_<wbr/>UNKNOWN) return 0; + int sensorOrientation = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>SENSOR_<wbr/>ORIENTATION); + + //<wbr/> Round device orientation to a multiple of 90 + deviceOrientation = (deviceOrientation + 45) /<wbr/> 90 * 90; + + //<wbr/> Reverse device orientation for front-facing cameras + boolean facingFront = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING) == Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING_<wbr/>FRONT; + if (facingFront) deviceOrientation = -deviceOrientation; + + //<wbr/> Calculate desired JPEG orientation relative to camera orientation to make + //<wbr/> the image upright relative to the device orientation + int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360; + + return jpegOrientation; +} +</code></pre> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.jpeg.quality"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>jpeg.<wbr/>quality + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Compression quality of the final JPEG +image.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>1-100; larger is higher quality</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>85-95 is typical usage range.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.jpeg.thumbnailQuality"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Quality + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Compression quality of JPEG +thumbnail.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>1-100; larger is higher quality</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.jpeg.thumbnailSize"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as size]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Resolution of embedded JPEG thumbnail.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.jpeg.availableThumbnailSizes">android.<wbr/>jpeg.<wbr/>available<wbr/>Thumbnail<wbr/>Sizes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to (0,<wbr/> 0) value,<wbr/> the JPEG EXIF will not contain thumbnail,<wbr/> +but the captured JPEG will still be a valid image.<wbr/></p> +<p>For best results,<wbr/> when issuing a request for a JPEG image,<wbr/> the thumbnail size selected +should have the same aspect ratio as the main JPEG output.<wbr/></p> +<p>If the thumbnail image aspect ratio differs from the JPEG primary image aspect +ratio,<wbr/> the camera device creates the thumbnail by cropping it from the primary image.<wbr/> +For example,<wbr/> if the primary image has 4:3 aspect ratio,<wbr/> the thumbnail image has +16:9 aspect ratio,<wbr/> the primary image will be cropped vertically (letterbox) to +generate the thumbnail image.<wbr/> The thumbnail image will always have a smaller Field +Of View (FOV) than the primary image when aspect ratios differ.<wbr/></p> +<p>When an <a href="#controls_android.jpeg.orientation">android.<wbr/>jpeg.<wbr/>orientation</a> of non-zero degree is requested,<wbr/> +the camera device will handle thumbnail rotation in one of the following ways:</p> +<ul> +<li>Set the <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a> + and keep jpeg and thumbnail image data unrotated.<wbr/></li> +<li>Rotate the jpeg and thumbnail image data and not set + <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>.<wbr/> In this + case,<wbr/> LIMITED or FULL hardware level devices will report rotated thumnail size in + capture result,<wbr/> so the width and height will be interchanged if 90 or 270 degree + orientation is requested.<wbr/> LEGACY device will always report unrotated thumbnail + size.<wbr/></li> +</ul> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL must not squeeze or stretch the downscaled primary image to generate thumbnail.<wbr/> +The cropping must be done on the primary jpeg image rather than the sensor active array.<wbr/> +The stream cropping rule specified by "S5.<wbr/> Cropping" in camera3.<wbr/>h doesn't apply to the +thumbnail image cropping.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.jpeg.availableThumbnailSizes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>jpeg.<wbr/>available<wbr/>Thumbnail<wbr/>Sizes + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 x n + </span> + <span class="entry_type_visibility"> [public as size]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of JPEG thumbnail sizes for <a href="#controls_android.jpeg.thumbnailSize">android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Size</a> supported by this +camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This list will include at least one non-zero resolution,<wbr/> plus <code>(0,<wbr/>0)</code> for indicating no +thumbnail should be generated.<wbr/></p> +<p>Below condiditions will be satisfied for this size list:</p> +<ul> +<li>The sizes will be sorted by increasing pixel area (width x height).<wbr/> +If several resolutions have the same area,<wbr/> they will be sorted by increasing width.<wbr/></li> +<li>The aspect ratio of the largest thumbnail size will be same as the +aspect ratio of largest JPEG output size in <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a>.<wbr/> +The largest size is defined as the size that has the largest pixel area +in a given size list.<wbr/></li> +<li>Each output JPEG size in <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> will have at least +one corresponding size that has the same aspect ratio in availableThumbnailSizes,<wbr/> +and vice versa.<wbr/></li> +<li>All non-<code>(0,<wbr/> 0)</code> sizes will have non-zero widths and heights.<wbr/></li> +</ul> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.jpeg.maxSize"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>jpeg.<wbr/>max<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Maximum size in bytes for the compressed +JPEG buffer</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Must be large enough to fit any JPEG produced by +the camera</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is used for sizing the gralloc buffers for +JPEG</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.jpeg.gpsLocation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>jpeg.<wbr/>gps<wbr/>Location + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [java_public as location]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A location object to use when generating image GPS metadata.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Setting a location object in a request will include the GPS coordinates of the location +into any JPEG images captured based on the request.<wbr/> These coordinates can then be +viewed by anyone who receives the JPEG image.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.jpeg.gpsCoordinates"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>jpeg.<wbr/>gps<wbr/>Coordinates + </td> + <td class="entry_type"> + <span class="entry_type_name">double</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">latitude,<wbr/> longitude,<wbr/> altitude.<wbr/> First two in degrees,<wbr/> the third in meters</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>GPS coordinates to include in output JPEG +EXIF.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>(-180 - 180],<wbr/> [-90,<wbr/>90],<wbr/> [-inf,<wbr/> inf]</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.jpeg.gpsProcessingMethod"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>jpeg.<wbr/>gps<wbr/>Processing<wbr/>Method + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [ndk_public as string]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>32 characters describing GPS algorithm to +include in EXIF.<wbr/></p> + </td> + + <td class="entry_units"> + UTF-8 null-terminated string + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.jpeg.gpsTimestamp"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>jpeg.<wbr/>gps<wbr/>Timestamp + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Time GPS fix was made to include in +EXIF.<wbr/></p> + </td> + + <td class="entry_units"> + UTC in seconds since January 1,<wbr/> 1970 + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.jpeg.orientation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>jpeg.<wbr/>orientation + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The orientation for a JPEG image.<wbr/></p> + </td> + + <td class="entry_units"> + Degrees in multiples of 90 + </td> + + <td class="entry_range"> + <p>0,<wbr/> 90,<wbr/> 180,<wbr/> 270</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The clockwise rotation angle in degrees,<wbr/> relative to the orientation +to the camera,<wbr/> that the JPEG picture needs to be rotated by,<wbr/> to be viewed +upright.<wbr/></p> +<p>Camera devices may either encode this value into the JPEG EXIF header,<wbr/> or +rotate the image data to match this orientation.<wbr/> When the image data is rotated,<wbr/> +the thumbnail data will also be rotated.<wbr/></p> +<p>Note that this orientation is relative to the orientation of the camera sensor,<wbr/> given +by <a href="#static_android.sensor.orientation">android.<wbr/>sensor.<wbr/>orientation</a>.<wbr/></p> +<p>To translate from the device orientation given by the Android sensor APIs,<wbr/> the following +sample code may be used:</p> +<pre><code>private int getJpegOrientation(CameraCharacteristics c,<wbr/> int deviceOrientation) { + if (deviceOrientation == android.<wbr/>view.<wbr/>Orientation<wbr/>Event<wbr/>Listener.<wbr/>ORIENTATION_<wbr/>UNKNOWN) return 0; + int sensorOrientation = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>SENSOR_<wbr/>ORIENTATION); + + //<wbr/> Round device orientation to a multiple of 90 + deviceOrientation = (deviceOrientation + 45) /<wbr/> 90 * 90; + + //<wbr/> Reverse device orientation for front-facing cameras + boolean facingFront = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING) == Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING_<wbr/>FRONT; + if (facingFront) deviceOrientation = -deviceOrientation; + + //<wbr/> Calculate desired JPEG orientation relative to camera orientation to make + //<wbr/> the image upright relative to the device orientation + int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360; + + return jpegOrientation; +} +</code></pre> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.jpeg.quality"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>jpeg.<wbr/>quality + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Compression quality of the final JPEG +image.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>1-100; larger is higher quality</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>85-95 is typical usage range.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.jpeg.size"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>jpeg.<wbr/>size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The size of the compressed JPEG image,<wbr/> in +bytes</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If no JPEG output is produced for the request,<wbr/> +this must be 0.<wbr/></p> +<p>Otherwise,<wbr/> this describes the real size of the compressed +JPEG image placed in the output stream.<wbr/> More specifically,<wbr/> +if <a href="#static_android.jpeg.maxSize">android.<wbr/>jpeg.<wbr/>max<wbr/>Size</a> = 1000000,<wbr/> and a specific capture +has <a href="#dynamic_android.jpeg.size">android.<wbr/>jpeg.<wbr/>size</a> = 500000,<wbr/> then the output buffer from +the JPEG stream will be 1000000 bytes,<wbr/> of which the first +500000 make up the real data.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.jpeg.thumbnailQuality"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Quality + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Compression quality of JPEG +thumbnail.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>1-100; larger is higher quality</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.jpeg.thumbnailSize"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as size]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Resolution of embedded JPEG thumbnail.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.jpeg.availableThumbnailSizes">android.<wbr/>jpeg.<wbr/>available<wbr/>Thumbnail<wbr/>Sizes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to (0,<wbr/> 0) value,<wbr/> the JPEG EXIF will not contain thumbnail,<wbr/> +but the captured JPEG will still be a valid image.<wbr/></p> +<p>For best results,<wbr/> when issuing a request for a JPEG image,<wbr/> the thumbnail size selected +should have the same aspect ratio as the main JPEG output.<wbr/></p> +<p>If the thumbnail image aspect ratio differs from the JPEG primary image aspect +ratio,<wbr/> the camera device creates the thumbnail by cropping it from the primary image.<wbr/> +For example,<wbr/> if the primary image has 4:3 aspect ratio,<wbr/> the thumbnail image has +16:9 aspect ratio,<wbr/> the primary image will be cropped vertically (letterbox) to +generate the thumbnail image.<wbr/> The thumbnail image will always have a smaller Field +Of View (FOV) than the primary image when aspect ratios differ.<wbr/></p> +<p>When an <a href="#controls_android.jpeg.orientation">android.<wbr/>jpeg.<wbr/>orientation</a> of non-zero degree is requested,<wbr/> +the camera device will handle thumbnail rotation in one of the following ways:</p> +<ul> +<li>Set the <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a> + and keep jpeg and thumbnail image data unrotated.<wbr/></li> +<li>Rotate the jpeg and thumbnail image data and not set + <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>.<wbr/> In this + case,<wbr/> LIMITED or FULL hardware level devices will report rotated thumnail size in + capture result,<wbr/> so the width and height will be interchanged if 90 or 270 degree + orientation is requested.<wbr/> LEGACY device will always report unrotated thumbnail + size.<wbr/></li> +</ul> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL must not squeeze or stretch the downscaled primary image to generate thumbnail.<wbr/> +The cropping must be done on the primary jpeg image rather than the sensor active array.<wbr/> +The stream cropping rule specified by "S5.<wbr/> Cropping" in camera3.<wbr/>h doesn't apply to the +thumbnail image cropping.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_lens" class="section">lens</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.lens.aperture"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>aperture + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired lens aperture size,<wbr/> as a ratio of lens focal length to the +effective aperture diameter.<wbr/></p> + </td> + + <td class="entry_units"> + The f-number (f/<wbr/>N) + </td> + + <td class="entry_range"> + <p><a href="#static_android.lens.info.availableApertures">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Setting this value is only supported on the camera devices that have a variable +aperture lens.<wbr/></p> +<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/> +this can be set along with <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> +<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> +to achieve manual exposure control.<wbr/></p> +<p>The requested aperture value may take several frames to reach the +requested value; the camera device will report the current (intermediate) +aperture size in capture result metadata while the aperture is changing.<wbr/> +While the aperture is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p> +<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of +the ON modes,<wbr/> this will be overridden by the camera device +auto-exposure algorithm,<wbr/> the overridden values are then provided +back to the user in the corresponding result.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.lens.filterDensity"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>filter<wbr/>Density + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired setting for the lens neutral density filter(s).<wbr/></p> + </td> + + <td class="entry_units"> + Exposure Value (EV) + </td> + + <td class="entry_range"> + <p><a href="#static_android.lens.info.availableFilterDensities">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control will not be supported on most camera devices.<wbr/></p> +<p>Lens filters are typically used to lower the amount of light the +sensor is exposed to (measured in steps of EV).<wbr/> As used here,<wbr/> an EV +step is the standard logarithmic representation,<wbr/> which are +non-negative,<wbr/> and inversely proportional to the amount of light +hitting the sensor.<wbr/> For example,<wbr/> setting this to 0 would result +in no reduction of the incoming light,<wbr/> and setting this to 2 would +mean that the filter is set to reduce incoming light by two stops +(allowing 1/<wbr/>4 of the prior amount of light to the sensor).<wbr/></p> +<p>It may take several frames before the lens filter density changes +to the requested value.<wbr/> While the filter density is still changing,<wbr/> +<a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.lens.focalLength"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>focal<wbr/>Length + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired lens focal length; used for optical zoom.<wbr/></p> + </td> + + <td class="entry_units"> + Millimeters + </td> + + <td class="entry_range"> + <p><a href="#static_android.lens.info.availableFocalLengths">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This setting controls the physical focal length of the camera +device's lens.<wbr/> Changing the focal length changes the field of +view of the camera device,<wbr/> and is usually used for optical zoom.<wbr/></p> +<p>Like <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>,<wbr/> this +setting won't be applied instantaneously,<wbr/> and it may take several +frames before the lens can change to the requested focal length.<wbr/> +While the focal length is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will +be set to MOVING.<wbr/></p> +<p>Optical zoom will not be supported on most devices.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.lens.focusDistance"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>focus<wbr/>Distance + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Desired distance to plane of sharpest focus,<wbr/> +measured from frontmost surface of the lens.<wbr/></p> + </td> + + <td class="entry_units"> + See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details + </td> + + <td class="entry_range"> + <p>>= 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control can be used for setting manual focus,<wbr/> on devices that support +the MANUAL_<wbr/>SENSOR capability and have a variable-focus lens (see +<a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>).<wbr/></p> +<p>A value of <code>0.<wbr/>0f</code> means infinity focus.<wbr/> The value set will be clamped to +<code>[0.<wbr/>0f,<wbr/> <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>]</code>.<wbr/></p> +<p>Like <a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> this setting won't be applied +instantaneously,<wbr/> and it may take several frames before the lens +can move to the requested focus distance.<wbr/> While the lens is still moving,<wbr/> +<a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p> +<p>LEGACY devices support at most setting this to <code>0.<wbr/>0f</code> +for infinity focus.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.lens.opticalStabilizationMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Optical stabilization is unavailable.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optical stabilization is enabled.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Sets whether the camera device uses optical image stabilization (OIS) +when capturing images.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>OIS is used to compensate for motion blur due to small +movements of the camera during capture.<wbr/> Unlike digital image +stabilization (<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> OIS +makes use of mechanical elements to stabilize the camera +sensor,<wbr/> and thus allows for longer exposure times before +camera shake becomes apparent.<wbr/></p> +<p>Switching between different optical stabilization modes may take several +frames to initialize,<wbr/> the camera device will report the current mode in +capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/> the +optical stabilization modes in the first several capture results may still +be "OFF",<wbr/> and it will become "ON" when the initialization is done.<wbr/></p> +<p>If a camera device supports both OIS and digital image stabilization +(<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may produce undesirable +interaction,<wbr/> so it is recommended not to enable both at the same time.<wbr/></p> +<p>Not all devices will support OIS; see +<a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a> for +available controls.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + + + <tr class="entry" id="static_android.lens.info.availableApertures"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of aperture size values for <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a> that are +supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + The aperture f-number + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If the camera device doesn't support a variable lens aperture,<wbr/> +this list will contain only one value,<wbr/> which is the fixed aperture size.<wbr/></p> +<p>If the camera device supports a variable aperture,<wbr/> the aperture values +in this list will be sorted in ascending order.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.info.availableFilterDensities"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of neutral density filter values for +<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> that are supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + Exposure value (EV) + </td> + + <td class="entry_range"> + <p>Values are >= 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If a neutral density filter is not supported by this camera device,<wbr/> +this list will contain only 0.<wbr/> Otherwise,<wbr/> this list will include every +filter density supported by the camera device,<wbr/> in ascending order.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.info.availableFocalLengths"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">The list of available focal lengths</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of focal lengths for <a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a> that are supported by this camera +device.<wbr/></p> + </td> + + <td class="entry_units"> + Millimeters + </td> + + <td class="entry_range"> + <p>Values are > 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If optical zoom is not supported,<wbr/> this list will only contain +a single value corresponding to the fixed focal length of the +device.<wbr/> Otherwise,<wbr/> this list will include every focal length supported +by the camera device,<wbr/> in ascending order.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.info.availableOpticalStabilization"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of optical image stabilization (OIS) modes for +<a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> that are supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If OIS is not supported by a given camera device,<wbr/> this list will +contain only OFF.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.info.hyperfocalDistance"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>info.<wbr/>hyperfocal<wbr/>Distance + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Hyperfocal distance for this lens.<wbr/></p> + </td> + + <td class="entry_units"> + See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details + </td> + + <td class="entry_range"> + <p>If lens is fixed focus,<wbr/> >= 0.<wbr/> If lens has focuser unit,<wbr/> the value is +within <code>(0.<wbr/>0f,<wbr/> <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>]</code></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If the lens is not fixed focus,<wbr/> the camera device will report this +field when <a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a> is APPROXIMATE or CALIBRATED.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.info.minimumFocusDistance"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Shortest distance from frontmost surface +of the lens that can be brought into sharp focus.<wbr/></p> + </td> + + <td class="entry_units"> + See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details + </td> + + <td class="entry_range"> + <p>>= 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If the lens is fixed-focus,<wbr/> this will be +0.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Mandatory for FULL devices; LIMITED devices +must always set this value to 0 for fixed-focus; and may omit +the minimum focus distance otherwise.<wbr/></p> +<p>This field is also mandatory for all devices advertising +the MANUAL_<wbr/>SENSOR capability.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.info.shadingMapSize"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [ndk_public as size]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">width and height (N,<wbr/> M) of lens shading map provided by the camera device.<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Dimensions of lens shading map.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Both values >= 1</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The map should be on the order of 30-40 rows and columns,<wbr/> and +must be smaller than 64x64.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.info.focusDistanceCalibration"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">UNCALIBRATED</span> + <span class="entry_type_enum_notes"><p>The lens focus distance is not accurate,<wbr/> and the units used for +<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> do not correspond to any physical units.<wbr/></p> +<p>Setting the lens to the same focus distance on separate occasions may +result in a different real focus distance,<wbr/> depending on factors such +as the orientation of the device,<wbr/> the age of the focusing mechanism,<wbr/> +and the device temperature.<wbr/> The focus distance value will still be +in the range of <code>[0,<wbr/> <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>]</code>,<wbr/> where 0 +represents the farthest focus.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">APPROXIMATE</span> + <span class="entry_type_enum_notes"><p>The lens focus distance is measured in diopters.<wbr/></p> +<p>However,<wbr/> setting the lens to the same focus distance +on separate occasions may result in a different real +focus distance,<wbr/> depending on factors such as the +orientation of the device,<wbr/> the age of the focusing +mechanism,<wbr/> and the device temperature.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CALIBRATED</span> + <span class="entry_type_enum_notes"><p>The lens focus distance is measured in diopters,<wbr/> and +is calibrated.<wbr/></p> +<p>The lens mechanism is calibrated so that setting the +same focus distance is repeatable on multiple +occasions with good accuracy,<wbr/> and the focus distance +corresponds to the real physical distance to the plane +of best focus.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The lens focus distance calibration quality.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The lens focus distance calibration quality determines the reliability of +focus related metadata entries,<wbr/> i.<wbr/>e.<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/> +<a href="#dynamic_android.lens.focusRange">android.<wbr/>lens.<wbr/>focus<wbr/>Range</a>,<wbr/> <a href="#static_android.lens.info.hyperfocalDistance">android.<wbr/>lens.<wbr/>info.<wbr/>hyperfocal<wbr/>Distance</a>,<wbr/> and +<a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>.<wbr/></p> +<p>APPROXIMATE and CALIBRATED devices report the focus metadata in +units of diopters (1/<wbr/>meter),<wbr/> so <code>0.<wbr/>0f</code> represents focusing at infinity,<wbr/> +and increasing positive numbers represent focusing closer and closer +to the camera device.<wbr/> The focus distance control also uses diopters +on these devices.<wbr/></p> +<p>UNCALIBRATED devices do not use units that are directly comparable +to any real physical measurement,<wbr/> but <code>0.<wbr/>0f</code> still represents farthest +focus,<wbr/> and <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> represents the +nearest focus the device can achieve.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For devices advertise APPROXIMATE quality or higher,<wbr/> diopters 0 (infinity +focus) must work.<wbr/> When autofocus is disabled (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> == OFF) +and the lens focus distance is set to 0 diopters +(<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> == 0),<wbr/> the lens will move to focus at infinity +and is stably focused at infinity even if the device tilts.<wbr/> It may take the +lens some time to move; during the move the lens state should be MOVING and +the output diopter value should be changing toward 0.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + + + <tr class="entry" id="static_android.lens.facing"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>lens.<wbr/>facing + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">FRONT</span> + <span class="entry_type_enum_notes"><p>The camera device faces the same direction as the device's screen.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">BACK</span> + <span class="entry_type_enum_notes"><p>The camera device faces the opposite direction as the device's screen.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">EXTERNAL</span> + <span class="entry_type_enum_notes"><p>The camera device is an external camera,<wbr/> and has no fixed facing relative to the +device's screen.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Direction the camera faces relative to +device screen.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.poseRotation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>pose<wbr/>Rotation + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The orientation of the camera relative to the sensor +coordinate system.<wbr/></p> + </td> + + <td class="entry_units"> + + Quaternion coefficients + + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The four coefficients that describe the quaternion +rotation from the Android sensor coordinate system to a +camera-aligned coordinate system where the X-axis is +aligned with the long side of the image sensor,<wbr/> the Y-axis +is aligned with the short side of the image sensor,<wbr/> and +the Z-axis is aligned with the optical axis of the sensor.<wbr/></p> +<p>To convert from the quaternion coefficients <code>(x,<wbr/>y,<wbr/>z,<wbr/>w)</code> +to the axis of rotation <code>(a_<wbr/>x,<wbr/> a_<wbr/>y,<wbr/> a_<wbr/>z)</code> and rotation +amount <code>theta</code>,<wbr/> the following formulas can be used:</p> +<pre><code> theta = 2 * acos(w) +a_<wbr/>x = x /<wbr/> sin(theta/<wbr/>2) +a_<wbr/>y = y /<wbr/> sin(theta/<wbr/>2) +a_<wbr/>z = z /<wbr/> sin(theta/<wbr/>2) +</code></pre> +<p>To create a 3x3 rotation matrix that applies the rotation +defined by this quaternion,<wbr/> the following matrix can be +used:</p> +<pre><code>R = [ 1 - 2y^2 - 2z^2,<wbr/> 2xy - 2zw,<wbr/> 2xz + 2yw,<wbr/> + 2xy + 2zw,<wbr/> 1 - 2x^2 - 2z^2,<wbr/> 2yz - 2xw,<wbr/> + 2xz - 2yw,<wbr/> 2yz + 2xw,<wbr/> 1 - 2x^2 - 2y^2 ] +</code></pre> +<p>This matrix can then be used to apply the rotation to a + column vector point with</p> +<p><code>p' = Rp</code></p> +<p>where <code>p</code> is in the device sensor coordinate system,<wbr/> and + <code>p'</code> is in the camera-oriented coordinate system.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.poseTranslation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>pose<wbr/>Translation + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Position of the camera optical center.<wbr/></p> + </td> + + <td class="entry_units"> + Meters + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The position of the camera device's lens optical center,<wbr/> +as a three-dimensional vector <code>(x,<wbr/>y,<wbr/>z)</code>,<wbr/> relative to the +optical center of the largest camera device facing in the +same direction as this camera,<wbr/> in the <a href="https://developer.android.com/reference/android/hardware/SensorEvent.html">Android sensor coordinate +axes</a>.<wbr/> Note that only the axis definitions are shared with +the sensor coordinate system,<wbr/> but not the origin.<wbr/></p> +<p>If this device is the largest or only camera device with a +given facing,<wbr/> then this position will be <code>(0,<wbr/> 0,<wbr/> 0)</code>; a +camera device with a lens optical center located 3 cm from +the main sensor along the +X axis (to the right from the +user's perspective) will report <code>(0.<wbr/>03,<wbr/> 0,<wbr/> 0)</code>.<wbr/></p> +<p>To transform a pixel coordinates between two cameras +facing the same direction,<wbr/> first the source camera +<a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a> must be corrected for.<wbr/> Then +the source camera <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> needs +to be applied,<wbr/> followed by the <a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> +of the source camera,<wbr/> the translation of the source camera +relative to the destination camera,<wbr/> the +<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> of the destination camera,<wbr/> and +finally the inverse of <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> +of the destination camera.<wbr/> This obtains a +radial-distortion-free coordinate in the destination +camera pixel coordinates.<wbr/></p> +<p>To compare this against a real image from the destination +camera,<wbr/> the destination camera image then needs to be +corrected for radial distortion before comparison or +sampling.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.intrinsicCalibration"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 5 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The parameters for this camera device's intrinsic +calibration.<wbr/></p> + </td> + + <td class="entry_units"> + + Pixels in the + android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size + coordinate system.<wbr/> + + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The five calibration parameters that describe the +transform from camera-centric 3D coordinates to sensor +pixel coordinates:</p> +<pre><code>[f_<wbr/>x,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>x,<wbr/> c_<wbr/>y,<wbr/> s] +</code></pre> +<p>Where <code>f_<wbr/>x</code> and <code>f_<wbr/>y</code> are the horizontal and vertical +focal lengths,<wbr/> <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code> is the position of the optical +axis,<wbr/> and <code>s</code> is a skew parameter for the sensor plane not +being aligned with the lens plane.<wbr/></p> +<p>These are typically used within a transformation matrix K:</p> +<pre><code>K = [ f_<wbr/>x,<wbr/> s,<wbr/> c_<wbr/>x,<wbr/> + 0,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>y,<wbr/> + 0 0,<wbr/> 1 ] +</code></pre> +<p>which can then be combined with the camera pose rotation +<code>R</code> and translation <code>t</code> (<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> and +<a href="#static_android.lens.poseTranslation">android.<wbr/>lens.<wbr/>pose<wbr/>Translation</a>,<wbr/> respective) to calculate the +complete transform from world coordinates to pixel +coordinates:</p> +<pre><code>P = [ K 0 * [ R t + 0 1 ] 0 1 ] +</code></pre> +<p>and with <code>p_<wbr/>w</code> being a point in the world coordinate system +and <code>p_<wbr/>s</code> being a point in the camera active pixel array +coordinate system,<wbr/> and with the mapping including the +homogeneous division by z:</p> +<pre><code> p_<wbr/>h = (x_<wbr/>h,<wbr/> y_<wbr/>h,<wbr/> z_<wbr/>h) = P p_<wbr/>w +p_<wbr/>s = p_<wbr/>h /<wbr/> z_<wbr/>h +</code></pre> +<p>so <code>[x_<wbr/>s,<wbr/> y_<wbr/>s]</code> is the pixel coordinates of the world +point,<wbr/> <code>z_<wbr/>s = 1</code>,<wbr/> and <code>w_<wbr/>s</code> is a measurement of disparity +(depth) in pixel coordinates.<wbr/></p> +<p>Note that the coordinate system for this transform is the +<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> system,<wbr/> +where <code>(0,<wbr/>0)</code> is the top-left of the +preCorrectionActiveArraySize rectangle.<wbr/> Once the pose and +intrinsic calibration transforms have been applied to a +world point,<wbr/> then the <a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a> +transform needs to be applied,<wbr/> and the result adjusted to +be in the <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> coordinate +system (where <code>(0,<wbr/> 0)</code> is the top-left of the +activeArraySize rectangle),<wbr/> to determine the final pixel +coordinate of the world point for processed (non-RAW) +output buffers.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.lens.radialDistortion"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>radial<wbr/>Distortion + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 6 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The correction coefficients to correct for this camera device's +radial and tangential lens distortion.<wbr/></p> + </td> + + <td class="entry_units"> + + Unitless coefficients.<wbr/> + + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Four radial distortion coefficients <code>[kappa_<wbr/>0,<wbr/> kappa_<wbr/>1,<wbr/> kappa_<wbr/>2,<wbr/> +kappa_<wbr/>3]</code> and two tangential distortion coefficients +<code>[kappa_<wbr/>4,<wbr/> kappa_<wbr/>5]</code> that can be used to correct the +lens's geometric distortion with the mapping equations:</p> +<pre><code> x_<wbr/>c = x_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) + + kappa_<wbr/>4 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>5 * ( r^2 + 2 * x_<wbr/>i^2 ) + y_<wbr/>c = y_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) + + kappa_<wbr/>5 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>4 * ( r^2 + 2 * y_<wbr/>i^2 ) +</code></pre> +<p>Here,<wbr/> <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> are the coordinates to sample in the +input image that correspond to the pixel values in the +corrected image at the coordinate <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code>:</p> +<pre><code> correctedImage(x_<wbr/>i,<wbr/> y_<wbr/>i) = sample_<wbr/>at(x_<wbr/>c,<wbr/> y_<wbr/>c,<wbr/> inputImage) +</code></pre> +<p>The pixel coordinates are defined in a normalized +coordinate system related to the +<a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> calibration fields.<wbr/> +Both <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code> and <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> have <code>(0,<wbr/>0)</code> at the +lens optical center <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code>.<wbr/> The maximum magnitudes +of both x and y coordinates are normalized to be 1 at the +edge further from the optical center,<wbr/> so the range +for both dimensions is <code>-1 <= x <= 1</code>.<wbr/></p> +<p>Finally,<wbr/> <code>r</code> represents the radial distance from the +optical center,<wbr/> <code>r^2 = x_<wbr/>i^2 + y_<wbr/>i^2</code>,<wbr/> and its magnitude +is therefore no larger than <code>|<wbr/>r|<wbr/> <= sqrt(2)</code>.<wbr/></p> +<p>The distortion model used is the Brown-Conrady model.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.lens.aperture"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>aperture + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired lens aperture size,<wbr/> as a ratio of lens focal length to the +effective aperture diameter.<wbr/></p> + </td> + + <td class="entry_units"> + The f-number (f/<wbr/>N) + </td> + + <td class="entry_range"> + <p><a href="#static_android.lens.info.availableApertures">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Setting this value is only supported on the camera devices that have a variable +aperture lens.<wbr/></p> +<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/> +this can be set along with <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> +<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> +to achieve manual exposure control.<wbr/></p> +<p>The requested aperture value may take several frames to reach the +requested value; the camera device will report the current (intermediate) +aperture size in capture result metadata while the aperture is changing.<wbr/> +While the aperture is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p> +<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of +the ON modes,<wbr/> this will be overridden by the camera device +auto-exposure algorithm,<wbr/> the overridden values are then provided +back to the user in the corresponding result.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.filterDensity"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>filter<wbr/>Density + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired setting for the lens neutral density filter(s).<wbr/></p> + </td> + + <td class="entry_units"> + Exposure Value (EV) + </td> + + <td class="entry_range"> + <p><a href="#static_android.lens.info.availableFilterDensities">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control will not be supported on most camera devices.<wbr/></p> +<p>Lens filters are typically used to lower the amount of light the +sensor is exposed to (measured in steps of EV).<wbr/> As used here,<wbr/> an EV +step is the standard logarithmic representation,<wbr/> which are +non-negative,<wbr/> and inversely proportional to the amount of light +hitting the sensor.<wbr/> For example,<wbr/> setting this to 0 would result +in no reduction of the incoming light,<wbr/> and setting this to 2 would +mean that the filter is set to reduce incoming light by two stops +(allowing 1/<wbr/>4 of the prior amount of light to the sensor).<wbr/></p> +<p>It may take several frames before the lens filter density changes +to the requested value.<wbr/> While the filter density is still changing,<wbr/> +<a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.focalLength"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>focal<wbr/>Length + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired lens focal length; used for optical zoom.<wbr/></p> + </td> + + <td class="entry_units"> + Millimeters + </td> + + <td class="entry_range"> + <p><a href="#static_android.lens.info.availableFocalLengths">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This setting controls the physical focal length of the camera +device's lens.<wbr/> Changing the focal length changes the field of +view of the camera device,<wbr/> and is usually used for optical zoom.<wbr/></p> +<p>Like <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>,<wbr/> this +setting won't be applied instantaneously,<wbr/> and it may take several +frames before the lens can change to the requested focal length.<wbr/> +While the focal length is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will +be set to MOVING.<wbr/></p> +<p>Optical zoom will not be supported on most devices.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.focusDistance"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>focus<wbr/>Distance + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Desired distance to plane of sharpest focus,<wbr/> +measured from frontmost surface of the lens.<wbr/></p> + </td> + + <td class="entry_units"> + See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details + </td> + + <td class="entry_range"> + <p>>= 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Should be zero for fixed-focus cameras</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.focusRange"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>focus<wbr/>Range + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as pairFloatFloat]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + <div class="entry_type_notes">Range of scene distances that are in focus</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The range of scene distances that are in +sharp focus (depth of field).<wbr/></p> + </td> + + <td class="entry_units"> + A pair of focus distances in diopters: (near,<wbr/> + far); see android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details.<wbr/> + </td> + + <td class="entry_range"> + <p>>=0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If variable focus not supported,<wbr/> can still report +fixed depth of field range</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.opticalStabilizationMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Optical stabilization is unavailable.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Optical stabilization is enabled.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Sets whether the camera device uses optical image stabilization (OIS) +when capturing images.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>OIS is used to compensate for motion blur due to small +movements of the camera during capture.<wbr/> Unlike digital image +stabilization (<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> OIS +makes use of mechanical elements to stabilize the camera +sensor,<wbr/> and thus allows for longer exposure times before +camera shake becomes apparent.<wbr/></p> +<p>Switching between different optical stabilization modes may take several +frames to initialize,<wbr/> the camera device will report the current mode in +capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/> the +optical stabilization modes in the first several capture results may still +be "OFF",<wbr/> and it will become "ON" when the initialization is done.<wbr/></p> +<p>If a camera device supports both OIS and digital image stabilization +(<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may produce undesirable +interaction,<wbr/> so it is recommended not to enable both at the same time.<wbr/></p> +<p>Not all devices will support OIS; see +<a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a> for +available controls.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.state"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>state + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">STATIONARY</span> + <span class="entry_type_enum_notes"><p>The lens parameters (<a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/> +<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>) are not changing.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MOVING</span> + <span class="entry_type_enum_notes"><p>One or several of the lens parameters +(<a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/> +<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> or <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>) is +currently changing.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Current lens status.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For lens parameters <a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/> +<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>,<wbr/> when changes are requested,<wbr/> +they may take several frames to reach the requested values.<wbr/> This state indicates +the current status of the lens parameters.<wbr/></p> +<p>When the state is STATIONARY,<wbr/> the lens parameters are not changing.<wbr/> This could be +either because the parameters are all fixed,<wbr/> or because the lens has had enough +time to reach the most recently-requested values.<wbr/> +If all these lens parameters are not changable for a camera device,<wbr/> as listed below:</p> +<ul> +<li>Fixed focus (<code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> == 0</code>),<wbr/> which means +<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> parameter will always be 0.<wbr/></li> +<li>Fixed focal length (<a href="#static_android.lens.info.availableFocalLengths">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths</a> contains single value),<wbr/> +which means the optical zoom is not supported.<wbr/></li> +<li>No ND filter (<a href="#static_android.lens.info.availableFilterDensities">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities</a> contains only 0).<wbr/></li> +<li>Fixed aperture (<a href="#static_android.lens.info.availableApertures">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures</a> contains single value).<wbr/></li> +</ul> +<p>Then this state will always be STATIONARY.<wbr/></p> +<p>When the state is MOVING,<wbr/> it indicates that at least one of the lens parameters +is changing.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.poseRotation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>pose<wbr/>Rotation + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The orientation of the camera relative to the sensor +coordinate system.<wbr/></p> + </td> + + <td class="entry_units"> + + Quaternion coefficients + + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The four coefficients that describe the quaternion +rotation from the Android sensor coordinate system to a +camera-aligned coordinate system where the X-axis is +aligned with the long side of the image sensor,<wbr/> the Y-axis +is aligned with the short side of the image sensor,<wbr/> and +the Z-axis is aligned with the optical axis of the sensor.<wbr/></p> +<p>To convert from the quaternion coefficients <code>(x,<wbr/>y,<wbr/>z,<wbr/>w)</code> +to the axis of rotation <code>(a_<wbr/>x,<wbr/> a_<wbr/>y,<wbr/> a_<wbr/>z)</code> and rotation +amount <code>theta</code>,<wbr/> the following formulas can be used:</p> +<pre><code> theta = 2 * acos(w) +a_<wbr/>x = x /<wbr/> sin(theta/<wbr/>2) +a_<wbr/>y = y /<wbr/> sin(theta/<wbr/>2) +a_<wbr/>z = z /<wbr/> sin(theta/<wbr/>2) +</code></pre> +<p>To create a 3x3 rotation matrix that applies the rotation +defined by this quaternion,<wbr/> the following matrix can be +used:</p> +<pre><code>R = [ 1 - 2y^2 - 2z^2,<wbr/> 2xy - 2zw,<wbr/> 2xz + 2yw,<wbr/> + 2xy + 2zw,<wbr/> 1 - 2x^2 - 2z^2,<wbr/> 2yz - 2xw,<wbr/> + 2xz - 2yw,<wbr/> 2yz + 2xw,<wbr/> 1 - 2x^2 - 2y^2 ] +</code></pre> +<p>This matrix can then be used to apply the rotation to a + column vector point with</p> +<p><code>p' = Rp</code></p> +<p>where <code>p</code> is in the device sensor coordinate system,<wbr/> and + <code>p'</code> is in the camera-oriented coordinate system.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.poseTranslation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>pose<wbr/>Translation + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Position of the camera optical center.<wbr/></p> + </td> + + <td class="entry_units"> + Meters + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The position of the camera device's lens optical center,<wbr/> +as a three-dimensional vector <code>(x,<wbr/>y,<wbr/>z)</code>,<wbr/> relative to the +optical center of the largest camera device facing in the +same direction as this camera,<wbr/> in the <a href="https://developer.android.com/reference/android/hardware/SensorEvent.html">Android sensor coordinate +axes</a>.<wbr/> Note that only the axis definitions are shared with +the sensor coordinate system,<wbr/> but not the origin.<wbr/></p> +<p>If this device is the largest or only camera device with a +given facing,<wbr/> then this position will be <code>(0,<wbr/> 0,<wbr/> 0)</code>; a +camera device with a lens optical center located 3 cm from +the main sensor along the +X axis (to the right from the +user's perspective) will report <code>(0.<wbr/>03,<wbr/> 0,<wbr/> 0)</code>.<wbr/></p> +<p>To transform a pixel coordinates between two cameras +facing the same direction,<wbr/> first the source camera +<a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a> must be corrected for.<wbr/> Then +the source camera <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> needs +to be applied,<wbr/> followed by the <a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> +of the source camera,<wbr/> the translation of the source camera +relative to the destination camera,<wbr/> the +<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> of the destination camera,<wbr/> and +finally the inverse of <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> +of the destination camera.<wbr/> This obtains a +radial-distortion-free coordinate in the destination +camera pixel coordinates.<wbr/></p> +<p>To compare this against a real image from the destination +camera,<wbr/> the destination camera image then needs to be +corrected for radial distortion before comparison or +sampling.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.intrinsicCalibration"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 5 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The parameters for this camera device's intrinsic +calibration.<wbr/></p> + </td> + + <td class="entry_units"> + + Pixels in the + android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size + coordinate system.<wbr/> + + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The five calibration parameters that describe the +transform from camera-centric 3D coordinates to sensor +pixel coordinates:</p> +<pre><code>[f_<wbr/>x,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>x,<wbr/> c_<wbr/>y,<wbr/> s] +</code></pre> +<p>Where <code>f_<wbr/>x</code> and <code>f_<wbr/>y</code> are the horizontal and vertical +focal lengths,<wbr/> <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code> is the position of the optical +axis,<wbr/> and <code>s</code> is a skew parameter for the sensor plane not +being aligned with the lens plane.<wbr/></p> +<p>These are typically used within a transformation matrix K:</p> +<pre><code>K = [ f_<wbr/>x,<wbr/> s,<wbr/> c_<wbr/>x,<wbr/> + 0,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>y,<wbr/> + 0 0,<wbr/> 1 ] +</code></pre> +<p>which can then be combined with the camera pose rotation +<code>R</code> and translation <code>t</code> (<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> and +<a href="#static_android.lens.poseTranslation">android.<wbr/>lens.<wbr/>pose<wbr/>Translation</a>,<wbr/> respective) to calculate the +complete transform from world coordinates to pixel +coordinates:</p> +<pre><code>P = [ K 0 * [ R t + 0 1 ] 0 1 ] +</code></pre> +<p>and with <code>p_<wbr/>w</code> being a point in the world coordinate system +and <code>p_<wbr/>s</code> being a point in the camera active pixel array +coordinate system,<wbr/> and with the mapping including the +homogeneous division by z:</p> +<pre><code> p_<wbr/>h = (x_<wbr/>h,<wbr/> y_<wbr/>h,<wbr/> z_<wbr/>h) = P p_<wbr/>w +p_<wbr/>s = p_<wbr/>h /<wbr/> z_<wbr/>h +</code></pre> +<p>so <code>[x_<wbr/>s,<wbr/> y_<wbr/>s]</code> is the pixel coordinates of the world +point,<wbr/> <code>z_<wbr/>s = 1</code>,<wbr/> and <code>w_<wbr/>s</code> is a measurement of disparity +(depth) in pixel coordinates.<wbr/></p> +<p>Note that the coordinate system for this transform is the +<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> system,<wbr/> +where <code>(0,<wbr/>0)</code> is the top-left of the +preCorrectionActiveArraySize rectangle.<wbr/> Once the pose and +intrinsic calibration transforms have been applied to a +world point,<wbr/> then the <a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a> +transform needs to be applied,<wbr/> and the result adjusted to +be in the <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> coordinate +system (where <code>(0,<wbr/> 0)</code> is the top-left of the +activeArraySize rectangle),<wbr/> to determine the final pixel +coordinate of the world point for processed (non-RAW) +output buffers.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.lens.radialDistortion"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>lens.<wbr/>radial<wbr/>Distortion + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 6 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The correction coefficients to correct for this camera device's +radial and tangential lens distortion.<wbr/></p> + </td> + + <td class="entry_units"> + + Unitless coefficients.<wbr/> + + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Four radial distortion coefficients <code>[kappa_<wbr/>0,<wbr/> kappa_<wbr/>1,<wbr/> kappa_<wbr/>2,<wbr/> +kappa_<wbr/>3]</code> and two tangential distortion coefficients +<code>[kappa_<wbr/>4,<wbr/> kappa_<wbr/>5]</code> that can be used to correct the +lens's geometric distortion with the mapping equations:</p> +<pre><code> x_<wbr/>c = x_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) + + kappa_<wbr/>4 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>5 * ( r^2 + 2 * x_<wbr/>i^2 ) + y_<wbr/>c = y_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) + + kappa_<wbr/>5 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>4 * ( r^2 + 2 * y_<wbr/>i^2 ) +</code></pre> +<p>Here,<wbr/> <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> are the coordinates to sample in the +input image that correspond to the pixel values in the +corrected image at the coordinate <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code>:</p> +<pre><code> correctedImage(x_<wbr/>i,<wbr/> y_<wbr/>i) = sample_<wbr/>at(x_<wbr/>c,<wbr/> y_<wbr/>c,<wbr/> inputImage) +</code></pre> +<p>The pixel coordinates are defined in a normalized +coordinate system related to the +<a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> calibration fields.<wbr/> +Both <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code> and <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> have <code>(0,<wbr/>0)</code> at the +lens optical center <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code>.<wbr/> The maximum magnitudes +of both x and y coordinates are normalized to be 1 at the +edge further from the optical center,<wbr/> so the range +for both dimensions is <code>-1 <= x <= 1</code>.<wbr/></p> +<p>Finally,<wbr/> <code>r</code> represents the radial distance from the +optical center,<wbr/> <code>r^2 = x_<wbr/>i^2 + y_<wbr/>i^2</code>,<wbr/> and its magnitude +is therefore no larger than <code>|<wbr/>r|<wbr/> <= sqrt(2)</code>.<wbr/></p> +<p>The distortion model used is the Brown-Conrady model.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_noiseReduction" class="section">noiseReduction</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.noiseReduction.mode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>noise<wbr/>Reduction.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No noise reduction is applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Noise reduction is applied without reducing frame rate relative to sensor +output.<wbr/> It may be the same as OFF if noise reduction will reduce frame rate +relative to sensor.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>High-quality noise reduction is applied,<wbr/> at the cost of possibly reduced frame +rate relative to sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MINIMAL</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>MINIMAL noise reduction is applied without reducing frame rate relative to +sensor output.<wbr/> </p></span> + </li> + <li> + <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Noise reduction is applied at different levels for different output streams,<wbr/> +based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have noise +reduction applied,<wbr/> while higher-resolution streams have MINIMAL (if supported) or no +noise reduction applied (if MINIMAL is not supported.<wbr/>) The degree of noise reduction +for low-resolution streams is tuned so that frame rate is not impacted,<wbr/> and the quality +is equal to or better than FAST (since it is only applied to lower-resolution outputs,<wbr/> +quality may improve from FAST).<wbr/></p> +<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode +with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures +high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is +produced via reprocessing when a user takes a picture.<wbr/> For such a use case,<wbr/> the +high-resolution buffers must not have noise reduction applied to maximize efficiency of +preview and to avoid over-applying noise filtering when reprocessing,<wbr/> while +low-resolution buffers (used for recording or preview,<wbr/> generally) need noise reduction +applied for reasonable preview quality.<wbr/></p> +<p>This mode is guaranteed to be supported by devices that support either the +YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities +(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will +be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Mode of operation for the noise reduction algorithm.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The noise reduction algorithm attempts to improve image quality by removing +excessive noise added by the capture process,<wbr/> especially in dark conditions.<wbr/></p> +<p>OFF means no noise reduction will be applied by the camera device,<wbr/> for both raw and +YUV domain.<wbr/></p> +<p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,<wbr/>to remove +demosaicing or other processing artifacts.<wbr/> For YUV_<wbr/>REPROCESSING,<wbr/> MINIMAL is same as OFF.<wbr/> +This mode is optional,<wbr/> may not be support by all devices.<wbr/> The application should check +<a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> before using it.<wbr/></p> +<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined noise filtering +will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device +will use the highest-quality noise filtering algorithms,<wbr/> +even if it slows down capture rate.<wbr/> FAST means the camera device will not +slow down capture rate when applying noise filtering.<wbr/> FAST may be the same as MINIMAL if +MINIMAL is listed,<wbr/> or the same as OFF if any noise filtering will slow down capture rate.<wbr/> +Every output stream will have a similar amount of enhancement applied.<wbr/></p> +<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular +buffer of high-resolution images during preview and reprocess image(s) from that buffer +into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies +noise reduction to low-resolution streams (below maximum recording resolution) to maximize +preview quality,<wbr/> but does not apply noise reduction to high-resolution streams,<wbr/> since +those will be reprocessed later if necessary.<wbr/></p> +<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera device +will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV domain noise reduction,<wbr/> respectively.<wbr/> The camera device +may adjust the noise reduction parameters for best image quality based on the +<a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> if it is set.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to +adjust the internal noise reduction parameters appropriately to get the best quality +images.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.noiseReduction.strength"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>noise<wbr/>Reduction.<wbr/>strength + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Control the amount of noise reduction +applied to the images</p> + </td> + + <td class="entry_units"> + 1-10; 10 is max noise reduction + </td> + + <td class="entry_range"> + <p>1 - 10</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.noiseReduction.availableNoiseReductionModes"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of noise reduction modes for <a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a> that are supported +by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Full-capability camera devices will always support OFF and FAST.<wbr/></p> +<p>Camera devices that support YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING will support +ZERO_<wbr/>SHUTTER_<wbr/>LAG.<wbr/></p> +<p>Legacy-capability camera devices will only support FAST mode.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if noise reduction control is available +on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/> +That is,<wbr/> if the highest quality implementation on the camera device does not slow down +capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.noiseReduction.mode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>noise<wbr/>Reduction.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No noise reduction is applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Noise reduction is applied without reducing frame rate relative to sensor +output.<wbr/> It may be the same as OFF if noise reduction will reduce frame rate +relative to sensor.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>High-quality noise reduction is applied,<wbr/> at the cost of possibly reduced frame +rate relative to sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MINIMAL</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>MINIMAL noise reduction is applied without reducing frame rate relative to +sensor output.<wbr/> </p></span> + </li> + <li> + <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Noise reduction is applied at different levels for different output streams,<wbr/> +based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have noise +reduction applied,<wbr/> while higher-resolution streams have MINIMAL (if supported) or no +noise reduction applied (if MINIMAL is not supported.<wbr/>) The degree of noise reduction +for low-resolution streams is tuned so that frame rate is not impacted,<wbr/> and the quality +is equal to or better than FAST (since it is only applied to lower-resolution outputs,<wbr/> +quality may improve from FAST).<wbr/></p> +<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode +with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures +high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is +produced via reprocessing when a user takes a picture.<wbr/> For such a use case,<wbr/> the +high-resolution buffers must not have noise reduction applied to maximize efficiency of +preview and to avoid over-applying noise filtering when reprocessing,<wbr/> while +low-resolution buffers (used for recording or preview,<wbr/> generally) need noise reduction +applied for reasonable preview quality.<wbr/></p> +<p>This mode is guaranteed to be supported by devices that support either the +YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities +(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will +be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Mode of operation for the noise reduction algorithm.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The noise reduction algorithm attempts to improve image quality by removing +excessive noise added by the capture process,<wbr/> especially in dark conditions.<wbr/></p> +<p>OFF means no noise reduction will be applied by the camera device,<wbr/> for both raw and +YUV domain.<wbr/></p> +<p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,<wbr/>to remove +demosaicing or other processing artifacts.<wbr/> For YUV_<wbr/>REPROCESSING,<wbr/> MINIMAL is same as OFF.<wbr/> +This mode is optional,<wbr/> may not be support by all devices.<wbr/> The application should check +<a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> before using it.<wbr/></p> +<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined noise filtering +will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device +will use the highest-quality noise filtering algorithms,<wbr/> +even if it slows down capture rate.<wbr/> FAST means the camera device will not +slow down capture rate when applying noise filtering.<wbr/> FAST may be the same as MINIMAL if +MINIMAL is listed,<wbr/> or the same as OFF if any noise filtering will slow down capture rate.<wbr/> +Every output stream will have a similar amount of enhancement applied.<wbr/></p> +<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular +buffer of high-resolution images during preview and reprocess image(s) from that buffer +into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies +noise reduction to low-resolution streams (below maximum recording resolution) to maximize +preview quality,<wbr/> but does not apply noise reduction to high-resolution streams,<wbr/> since +those will be reprocessed later if necessary.<wbr/></p> +<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera device +will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV domain noise reduction,<wbr/> respectively.<wbr/> The camera device +may adjust the noise reduction parameters for best image quality based on the +<a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> if it is set.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to +adjust the internal noise reduction parameters appropriately to get the best quality +images.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_quirks" class="section">quirks</td></tr> + + + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.quirks.meteringCropRegion"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>quirks.<wbr/>metering<wbr/>Crop<wbr/>Region + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>If set to 1,<wbr/> the camera service does not +scale 'normalized' coordinates with respect to the crop +region.<wbr/> This applies to metering input (a{e,<wbr/>f,<wbr/>wb}Region +and output (face rectangles).<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Normalized coordinates refer to those in the +(-1000,<wbr/>1000) range mentioned in the +android.<wbr/>hardware.<wbr/>Camera API.<wbr/></p> +<p>HAL implementations should instead always use and emit +sensor array-relative coordinates for all region data.<wbr/> Does +not need to be listed in static metadata.<wbr/> Support will be +removed in future versions of camera service.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.quirks.triggerAfWithAuto"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>quirks.<wbr/>trigger<wbr/>Af<wbr/>With<wbr/>Auto + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>If set to 1,<wbr/> then the camera service always +switches to FOCUS_<wbr/>MODE_<wbr/>AUTO before issuing a AF +trigger.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL implementations should implement AF trigger +modes for AUTO,<wbr/> MACRO,<wbr/> CONTINUOUS_<wbr/>FOCUS,<wbr/> and +CONTINUOUS_<wbr/>PICTURE modes instead of using this flag.<wbr/> Does +not need to be listed in static metadata.<wbr/> Support will be +removed in future versions of camera service</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.quirks.useZslFormat"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>quirks.<wbr/>use<wbr/>Zsl<wbr/>Format + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>If set to 1,<wbr/> the camera service uses +CAMERA2_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>ZSL instead of +HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>IMPLEMENTATION_<wbr/>DEFINED for the zero +shutter lag stream</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL implementations should use gralloc usage flags +to determine that a stream will be used for +zero-shutter-lag,<wbr/> instead of relying on an explicit +format setting.<wbr/> Does not need to be listed in static +metadata.<wbr/> Support will be removed in future versions of +camera service.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.quirks.usePartialResult"> + <td class="entry_name + entry_name_deprecated + " rowspan="5"> + android.<wbr/>quirks.<wbr/>use<wbr/>Partial<wbr/>Result + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [hidden]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>If set to 1,<wbr/> the HAL will always split result +metadata for a single capture into multiple buffers,<wbr/> +returned using multiple process_<wbr/>capture_<wbr/>result calls.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Does not need to be listed in static +metadata.<wbr/> Support for partial results will be reworked in +future versions of camera service.<wbr/> This quirk will stop +working at that point; DO NOT USE without careful +consideration of future support.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Refer to <code>camera3_<wbr/>capture_<wbr/>result::partial_<wbr/>result</code> +for information on how to implement partial results.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.quirks.partialResult"> + <td class="entry_name + entry_name_deprecated + " rowspan="5"> + android.<wbr/>quirks.<wbr/>partial<wbr/>Result + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [hidden as boolean]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">FINAL</span> + <span class="entry_type_enum_notes"><p>The last or only metadata result buffer +for this capture.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PARTIAL</span> + <span class="entry_type_enum_notes"><p>A partial buffer of result metadata for this +capture.<wbr/> More result buffers for this capture will be sent +by the camera device,<wbr/> the last of which will be marked +FINAL.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether a result given to the framework is the +final one for the capture,<wbr/> or only a partial that contains a +subset of the full set of dynamic metadata +values.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + <p>Optional.<wbr/> Default value is FINAL.<wbr/></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The entries in the result metadata buffers for a +single capture may not overlap,<wbr/> except for this entry.<wbr/> The +FINAL buffers must retain FIFO ordering relative to the +requests that generate them,<wbr/> so the FINAL buffer for frame 3 must +always be sent to the framework after the FINAL buffer for frame 2,<wbr/> and +before the FINAL buffer for frame 4.<wbr/> PARTIAL buffers may be returned +in any order relative to other frames,<wbr/> but all PARTIAL buffers for a given +capture must arrive before the FINAL buffer for that capture.<wbr/> This entry may +only be used by the camera device if quirks.<wbr/>usePartialResult is set to 1.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Refer to <code>camera3_<wbr/>capture_<wbr/>result::partial_<wbr/>result</code> +for information on how to implement partial results.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_request" class="section">request</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.request.frameCount"> + <td class="entry_name + entry_name_deprecated + " rowspan="1"> + android.<wbr/>request.<wbr/>frame<wbr/>Count + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A frame counter set by the framework.<wbr/> Must +be maintained unchanged in output frame.<wbr/> This value monotonically +increases with every new result (that is,<wbr/> each new result has a unique +frameCount value).<wbr/></p> + </td> + + <td class="entry_units"> + incrementing integer + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + <p>Any int.<wbr/></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.request.id"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>request.<wbr/>id + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [hidden]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>An application-specified ID for the current +request.<wbr/> Must be maintained unchanged in output +frame</p> + </td> + + <td class="entry_units"> + arbitrary integer assigned by application + </td> + + <td class="entry_range"> + <p>Any int</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.request.inputStreams"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>request.<wbr/>input<wbr/>Streams + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List which camera reprocess stream is used +for the source of reprocessing data.<wbr/></p> + </td> + + <td class="entry_units"> + List of camera reprocess stream IDs + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + <p>Typically,<wbr/> only one entry allowed,<wbr/> must be a valid reprocess stream ID.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_HAL2">HAL2</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Only meaningful when <a href="#controls_android.request.type">android.<wbr/>request.<wbr/>type</a> == +REPROCESS.<wbr/> Ignored otherwise</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.request.metadataMode"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>request.<wbr/>metadata<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">NONE</span> + <span class="entry_type_enum_notes"><p>No metadata should be produced on output,<wbr/> except +for application-bound buffer data.<wbr/> If no +application-bound streams exist,<wbr/> no frame should be +placed in the output frame queue.<wbr/> If such streams +exist,<wbr/> a frame should be placed on the output queue +with null metadata but with the necessary output buffer +information.<wbr/> Timestamp information should still be +included with any output stream buffers</p></span> + </li> + <li> + <span class="entry_type_enum_name">FULL</span> + <span class="entry_type_enum_notes"><p>All metadata should be produced.<wbr/> Statistics will +only be produced if they are separately +enabled</p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>How much metadata to produce on +output</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.request.outputStreams"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>request.<wbr/>output<wbr/>Streams + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Lists which camera output streams image data +from this capture must be sent to</p> + </td> + + <td class="entry_units"> + List of camera stream IDs + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + <p>List must only include streams that have been +created</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_HAL2">HAL2</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If no output streams are listed,<wbr/> then the image +data should simply be discarded.<wbr/> The image data must +still be captured for metadata and statistics production,<wbr/> +and the lens and flash must operate as requested.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.request.type"> + <td class="entry_name + entry_name_deprecated + " rowspan="1"> + android.<wbr/>request.<wbr/>type + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">CAPTURE</span> + <span class="entry_type_enum_notes"><p>Capture a new image from the imaging hardware,<wbr/> +and process it according to the +settings</p></span> + </li> + <li> + <span class="entry_type_enum_name">REPROCESS</span> + <span class="entry_type_enum_notes"><p>Process previously captured data; the +<a href="#controls_android.request.inputStreams">android.<wbr/>request.<wbr/>input<wbr/>Streams</a> parameter determines the +source reprocessing stream.<wbr/> TODO: Mark dynamic metadata +needed for reprocessing with [RP]</p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The type of the request; either CAPTURE or +REPROCESS.<wbr/> For HAL3,<wbr/> this tag is redundant.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_HAL2">HAL2</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.request.maxNumOutputStreams"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum numbers of different types of output streams +that can be configured and used simultaneously by a camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>For processed (and stalling) format streams,<wbr/> >= 1.<wbr/></p> +<p>For Raw format (either stalling or non-stalling) streams,<wbr/> >= 0.<wbr/></p> +<p>For processed (but not stalling) format streams,<wbr/> >= 3 +for FULL mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>); +>= 2 for LIMITED mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>).<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is a 3 element tuple that contains the max number of output simultaneous +streams for raw sensor,<wbr/> processed (but not stalling),<wbr/> and processed (and stalling) +formats respectively.<wbr/> For example,<wbr/> assuming that JPEG is typically a processed and +stalling stream,<wbr/> if max raw sensor format output stream number is 1,<wbr/> max YUV streams +number is 3,<wbr/> and max JPEG stream number is 2,<wbr/> then this tuple should be <code>(1,<wbr/> 3,<wbr/> 2)</code>.<wbr/></p> +<p>This lists the upper bound of the number of output streams supported by +the camera device.<wbr/> Using more streams simultaneously may require more hardware and +CPU resources that will consume more power.<wbr/> The image format for an output stream can +be any supported format provided by <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a>.<wbr/> +The formats defined in <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> can be catergorized +into the 3 stream types as below:</p> +<ul> +<li>Processed (but stalling): any non-RAW format with a stallDurations > 0.<wbr/> + Typically <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">JPEG format</a>.<wbr/></li> +<li>Raw formats: <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_SENSOR">RAW_<wbr/>SENSOR</a>,<wbr/> <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">RAW10</a>,<wbr/> or <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW12">RAW12</a>.<wbr/></li> +<li>Processed (but not-stalling): any non-RAW format without a stall duration.<wbr/> + Typically <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">YUV_<wbr/>420_<wbr/>888</a>,<wbr/> + <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>,<wbr/> or + <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>.<wbr/></li> +</ul> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.maxNumOutputRaw"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Raw + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [java_public]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum numbers of different types of output streams +that can be configured and used simultaneously by a camera device +for any <code>RAW</code> formats.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 0</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This value contains the max number of output simultaneous +streams from the raw sensor.<wbr/></p> +<p>This lists the upper bound of the number of output streams supported by +the camera device.<wbr/> Using more streams simultaneously may require more hardware and +CPU resources that will consume more power.<wbr/> The image format for this kind of an output stream can +be any <code>RAW</code> and supported format provided by <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/></p> +<p>In particular,<wbr/> a <code>RAW</code> format is typically one of:</p> +<ul> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_SENSOR">RAW_<wbr/>SENSOR</a></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">RAW10</a></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW12">RAW12</a></li> +</ul> +<p>LEGACY mode devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> <code>==</code> LEGACY) +never support raw streams.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.maxNumOutputProc"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Proc + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [java_public]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum numbers of different types of output streams +that can be configured and used simultaneously by a camera device +for any processed (but not-stalling) formats.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 3 +for FULL mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>); +>= 2 for LIMITED mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>).<wbr/></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This value contains the max number of output simultaneous +streams for any processed (but not-stalling) formats.<wbr/></p> +<p>This lists the upper bound of the number of output streams supported by +the camera device.<wbr/> Using more streams simultaneously may require more hardware and +CPU resources that will consume more power.<wbr/> The image format for this kind of an output stream can +be any non-<code>RAW</code> and supported format provided by <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/></p> +<p>Processed (but not-stalling) is defined as any non-RAW format without a stall duration.<wbr/> +Typically:</p> +<ul> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">YUV_<wbr/>420_<wbr/>888</a></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a></li> +<li>Implementation-defined formats,<wbr/> i.<wbr/>e.<wbr/> <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#isOutputSupportedFor(Class)">StreamConfigurationMap#isOutputSupportedFor(Class)</a></li> +</ul> +<p>For full guarantees,<wbr/> query <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> with a +processed format -- it will return 0 for a non-stalling stream.<wbr/></p> +<p>LEGACY devices will support at least 2 processing/<wbr/>non-stalling streams.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.maxNumOutputProcStalling"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Proc<wbr/>Stalling + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [java_public]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum numbers of different types of output streams +that can be configured and used simultaneously by a camera device +for any processed (and stalling) formats.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 1</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This value contains the max number of output simultaneous +streams for any processed (but not-stalling) formats.<wbr/></p> +<p>This lists the upper bound of the number of output streams supported by +the camera device.<wbr/> Using more streams simultaneously may require more hardware and +CPU resources that will consume more power.<wbr/> The image format for this kind of an output stream can +be any non-<code>RAW</code> and supported format provided by <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/></p> +<p>A processed and stalling format is defined as any non-RAW format with a stallDurations +> 0.<wbr/> Typically only the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">JPEG format</a> is a +stalling format.<wbr/></p> +<p>For full guarantees,<wbr/> query <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> with a +processed format -- it will return a non-0 value for a stalling stream.<wbr/></p> +<p>LEGACY devices will support up to 1 processing/<wbr/>stalling stream.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.maxNumReprocessStreams"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Reprocess<wbr/>Streams + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 1 + </span> + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>How many reprocessing streams of any type +can be allocated at the same time.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + <p>>= 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_HAL2">HAL2</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Only used by HAL2.<wbr/>x.<wbr/></p> +<p>When set to 0,<wbr/> it means no reprocess stream is supported.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.maxNumInputStreams"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum numbers of any type of input streams +that can be configured and used simultaneously by a camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>0 or 1.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to 0,<wbr/> it means no input stream is supported.<wbr/></p> +<p>The image format for a input stream can be any supported format returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a>.<wbr/> When using an +input stream,<wbr/> there must be at least one output stream configured to to receive the +reprocessed images.<wbr/></p> +<p>When an input stream and some output streams are used in a reprocessing request,<wbr/> +only the input buffer will be used to produce these output stream buffers,<wbr/> and a +new sensor image will not be captured.<wbr/></p> +<p>For example,<wbr/> for Zero Shutter Lag (ZSL) still capture use case,<wbr/> the input +stream image format will be PRIVATE,<wbr/> the associated output stream image format +should be JPEG.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For the reprocessing flow and controls,<wbr/> see +hardware/<wbr/>libhardware/<wbr/>include/<wbr/>hardware/<wbr/>camera3.<wbr/>h Section 10 for more details.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.pipelineMaxDepth"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Specifies the number of maximum pipeline stages a frame +has to go through from when it's exposed to when it's available +to the framework.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>A typical minimum value for this is 2 (one stage to expose,<wbr/> +one stage to readout) from the sensor.<wbr/> The ISP then usually adds +its own stages to do custom HW processing.<wbr/> Further stages may be +added by SW processing.<wbr/></p> +<p>Depending on what settings are used (e.<wbr/>g.<wbr/> YUV,<wbr/> JPEG) and what +processing is enabled (e.<wbr/>g.<wbr/> face detection),<wbr/> the actual pipeline +depth (specified by <a href="#dynamic_android.request.pipelineDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Depth</a>) may be less than +the max pipeline depth.<wbr/></p> +<p>A pipeline depth of X stages is equivalent to a pipeline latency of +X frame intervals.<wbr/></p> +<p>This value will normally be 8 or less,<wbr/> however,<wbr/> for high speed capture session,<wbr/> +the max pipeline depth will be up to 8 x size of high speed capture request list.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This value should be 4 or less,<wbr/> expect for the high speed recording session,<wbr/> where the +max batch sizes may be larger than 1.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.partialResultCount"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>request.<wbr/>partial<wbr/>Result<wbr/>Count + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Defines how many sub-components +a result will be composed of.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 1</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>In order to combat the pipeline latency,<wbr/> partial results +may be delivered to the application layer from the camera device as +soon as they are available.<wbr/></p> +<p>Optional; defaults to 1.<wbr/> A value of 1 means that partial +results are not supported,<wbr/> and only the final TotalCaptureResult will +be produced by the camera device.<wbr/></p> +<p>A typical use case for this might be: after requesting an +auto-focus (AF) lock the new AF state might be available 50% +of the way through the pipeline.<wbr/> The camera device could +then immediately dispatch this state via a partial result to +the application,<wbr/> and the rest of the metadata via later +partial results.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.availableCapabilities"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>request.<wbr/>available<wbr/>Capabilities + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">BACKWARD_COMPATIBLE</span> + <span class="entry_type_enum_notes"><p>The minimal set of capabilities that every camera +device (regardless of <a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a>) +supports.<wbr/></p> +<p>This capability is listed by all normal devices,<wbr/> and +indicates that the camera device has a feature set +that's comparable to the baseline requirements for the +older android.<wbr/>hardware.<wbr/>Camera API.<wbr/></p> +<p>Devices with the DEPTH_<wbr/>OUTPUT capability might not list this +capability,<wbr/> indicating that they support only depth measurement,<wbr/> +not standard color output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MANUAL_SENSOR</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>The camera device can be manually controlled (3A algorithms such +as auto-exposure,<wbr/> and auto-focus can be bypassed).<wbr/> +The camera device supports basic manual control of the sensor image +acquisition related stages.<wbr/> This means the following controls are +guaranteed to be supported:</p> +<ul> +<li>Manual frame duration control<ul> +<li><a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a></li> +<li><a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a></li> +</ul> +</li> +<li>Manual exposure control<ul> +<li><a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a></li> +<li><a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></li> +</ul> +</li> +<li>Manual sensitivity control<ul> +<li><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></li> +<li><a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a></li> +</ul> +</li> +<li>Manual lens control (if the lens is adjustable)<ul> +<li>android.<wbr/>lens.<wbr/>*</li> +</ul> +</li> +<li>Manual flash control (if a flash unit is present)<ul> +<li>android.<wbr/>flash.<wbr/>*</li> +</ul> +</li> +<li>Manual black level locking<ul> +<li><a href="#controls_android.blackLevel.lock">android.<wbr/>black<wbr/>Level.<wbr/>lock</a></li> +</ul> +</li> +<li>Auto exposure lock<ul> +<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li> +</ul> +</li> +</ul> +<p>If any of the above 3A algorithms are enabled,<wbr/> then the camera +device will accurately report the values applied by 3A in the +result.<wbr/></p> +<p>A given camera device may also support additional manual sensor controls,<wbr/> +but this capability only covers the above list of controls.<wbr/></p> +<p>If this is supported,<wbr/> <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> will +additionally return a min frame duration that is greater than +zero for each supported size-format combination.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">MANUAL_POST_PROCESSING</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>The camera device post-processing stages can be manually controlled.<wbr/> +The camera device supports basic manual control of the image post-processing +stages.<wbr/> This means the following controls are guaranteed to be supported:</p> +<ul> +<li> +<p>Manual tonemap control</p> +<ul> +<li><a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a></li> +<li><a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a></li> +<li><a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></li> +<li><a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a></li> +<li><a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a></li> +</ul> +</li> +<li> +<p>Manual white balance control</p> +<ul> +<li><a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a></li> +<li><a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a></li> +</ul> +</li> +<li>Manual lens shading map control<ul> +<li><a href="#controls_android.shading.mode">android.<wbr/>shading.<wbr/>mode</a></li> +<li><a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a></li> +<li><a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a></li> +<li><a href="#static_android.lens.info.shadingMapSize">android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size</a></li> +</ul> +</li> +<li>Manual aberration correction control (if aberration correction is supported)<ul> +<li><a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a></li> +<li><a href="#static_android.colorCorrection.availableAberrationModes">android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes</a></li> +</ul> +</li> +<li>Auto white balance lock<ul> +<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li> +</ul> +</li> +</ul> +<p>If auto white balance is enabled,<wbr/> then the camera device +will accurately report the values applied by AWB in the result.<wbr/></p> +<p>A given camera device may also support additional post-processing +controls,<wbr/> but this capability only covers the above list of controls.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">RAW</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>The camera device supports outputting RAW buffers and +metadata for interpreting them.<wbr/></p> +<p>Devices supporting the RAW capability allow both for +saving DNG files,<wbr/> and for direct application processing of +raw sensor images.<wbr/></p> +<ul> +<li>RAW_<wbr/>SENSOR is supported as an output format.<wbr/></li> +<li>The maximum available resolution for RAW_<wbr/>SENSOR streams + will match either the value in + <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a> or + <a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>.<wbr/></li> +<li>All DNG-related optional metadata entries are provided + by the camera device.<wbr/></li> +</ul></span> + </li> + <li> + <span class="entry_type_enum_name">PRIVATE_REPROCESSING</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>The camera device supports the Zero Shutter Lag reprocessing use case.<wbr/></p> +<ul> +<li>One input stream is supported,<wbr/> that is,<wbr/> <code><a href="#static_android.request.maxNumInputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams</a> == 1</code>.<wbr/></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> is supported as an output/<wbr/>input format,<wbr/> + that is,<wbr/> <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> is included in the lists of + formats returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a> and <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputFormats">StreamConfigurationMap#getOutputFormats</a>.<wbr/></li> +<li><a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getValidOutputFormatsForInput">StreamConfigurationMap#getValidOutputFormatsForInput</a> + returns non empty int[] for each supported input format returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a>.<wbr/></li> +<li>Each size returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputSizes">getInputSizes(ImageFormat.<wbr/>PRIVATE)</a> is also included in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">getOutputSizes(ImageFormat.<wbr/>PRIVATE)</a></li> +<li>Using <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> does not cause a frame rate drop + relative to the sensor's maximum capture rate (at that resolution).<wbr/></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> will be reprocessable into both + <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> and + <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a> formats.<wbr/></li> +<li>The maximum available resolution for PRIVATE streams + (both input/<wbr/>output) will match the maximum available + resolution of JPEG streams.<wbr/></li> +<li>Static metadata <a href="#static_android.reprocess.maxCaptureStall">android.<wbr/>reprocess.<wbr/>max<wbr/>Capture<wbr/>Stall</a>.<wbr/></li> +<li>Only below controls are effective for reprocessing requests and + will be present in capture results,<wbr/> other controls in reprocess + requests will be ignored by the camera device.<wbr/><ul> +<li>android.<wbr/>jpeg.<wbr/>*</li> +<li><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a></li> +<li><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a></li> +</ul> +</li> +<li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> and + <a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a> will both list ZERO_<wbr/>SHUTTER_<wbr/>LAG as a supported mode.<wbr/></li> +</ul></span> + </li> + <li> + <span class="entry_type_enum_name">READ_SENSOR_SETTINGS</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>The camera device supports accurately reporting the sensor settings for many of +the sensor controls while the built-in 3A algorithm is running.<wbr/> This allows +reporting of sensor settings even when these settings cannot be manually changed.<wbr/></p> +<p>The values reported for the following controls are guaranteed to be available +in the CaptureResult,<wbr/> including when 3A is enabled:</p> +<ul> +<li>Exposure control<ul> +<li><a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a></li> +</ul> +</li> +<li>Sensitivity control<ul> +<li><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></li> +</ul> +</li> +<li>Lens controls (if the lens is adjustable)<ul> +<li><a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a></li> +<li><a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a></li> +</ul> +</li> +</ul> +<p>This capability is a subset of the MANUAL_<wbr/>SENSOR control capability,<wbr/> and will +always be included if the MANUAL_<wbr/>SENSOR capability is available.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">BURST_CAPTURE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>The camera device supports capturing high-resolution images at >= 20 frames per +second,<wbr/> in at least the uncompressed YUV format,<wbr/> when post-processing settings are set +to FAST.<wbr/> Additionally,<wbr/> maximum-resolution images can be captured at >= 10 frames +per second.<wbr/> Here,<wbr/> 'high resolution' means at least 8 megapixels,<wbr/> or the maximum +resolution of the device,<wbr/> whichever is smaller.<wbr/></p> +<p>More specifically,<wbr/> this means that a size matching the camera device's active array +size is listed as a supported size for the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> format in either <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">StreamConfigurationMap#getOutputSizes</a> or <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighResolutionOutputSizes">StreamConfigurationMap#getHighResolutionOutputSizes</a>,<wbr/> +with a minimum frame duration for that format and size of either <= 1/<wbr/>20 s,<wbr/> or +<= 1/<wbr/>10 s,<wbr/> respectively; and the <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a> entry +lists at least one FPS range where the minimum FPS is >= 1 /<wbr/> minimumFrameDuration +for the maximum-size YUV_<wbr/>420_<wbr/>888 format.<wbr/> If that maximum size is listed in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighResolutionOutputSizes">StreamConfigurationMap#getHighResolutionOutputSizes</a>,<wbr/> +then the list of resolutions for YUV_<wbr/>420_<wbr/>888 from <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">StreamConfigurationMap#getOutputSizes</a> contains at +least one resolution >= 8 megapixels,<wbr/> with a minimum frame duration of <= 1/<wbr/>20 +s.<wbr/></p> +<p>If the device supports the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">ImageFormat#RAW10</a>,<wbr/> <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW12">ImageFormat#RAW12</a>,<wbr/> then those can also be captured at the same rate +as the maximum-size YUV_<wbr/>420_<wbr/>888 resolution is.<wbr/></p> +<p>If the device supports the PRIVATE_<wbr/>REPROCESSING capability,<wbr/> then the same guarantees +as for the YUV_<wbr/>420_<wbr/>888 format also apply to the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> format.<wbr/></p> +<p>In addition,<wbr/> the <a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> field is guaranted to have a value between 0 +and 4,<wbr/> inclusive.<wbr/> <a href="#static_android.control.aeLockAvailable">android.<wbr/>control.<wbr/>ae<wbr/>Lock<wbr/>Available</a> and <a href="#static_android.control.awbLockAvailable">android.<wbr/>control.<wbr/>awb<wbr/>Lock<wbr/>Available</a> +are also guaranteed to be <code>true</code> so burst capture with these two locks ON yields +consistent image output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">YUV_REPROCESSING</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>The camera device supports the YUV_<wbr/>420_<wbr/>888 reprocessing use case,<wbr/> similar as +PRIVATE_<wbr/>REPROCESSING,<wbr/> This capability requires the camera device to support the +following:</p> +<ul> +<li>One input stream is supported,<wbr/> that is,<wbr/> <code><a href="#static_android.request.maxNumInputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams</a> == 1</code>.<wbr/></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> is supported as an output/<wbr/>input format,<wbr/> that is,<wbr/> + YUV_<wbr/>420_<wbr/>888 is included in the lists of formats returned by + <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a> and + <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputFormats">StreamConfigurationMap#getOutputFormats</a>.<wbr/></li> +<li><a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getValidOutputFormatsForInput">StreamConfigurationMap#getValidOutputFormatsForInput</a> + returns non-empty int[] for each supported input format returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a>.<wbr/></li> +<li>Each size returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputSizes">get<wbr/>Input<wbr/>Sizes(YUV_<wbr/>420_<wbr/>888)</a> is also included in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">get<wbr/>Output<wbr/>Sizes(YUV_<wbr/>420_<wbr/>888)</a></li> +<li>Using <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> does not cause a frame rate drop + relative to the sensor's maximum capture rate (at that resolution).<wbr/></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> will be reprocessable into both + <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> and <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a> formats.<wbr/></li> +<li>The maximum available resolution for <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> streams (both input/<wbr/>output) will match the + maximum available resolution of <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a> streams.<wbr/></li> +<li>Static metadata <a href="#static_android.reprocess.maxCaptureStall">android.<wbr/>reprocess.<wbr/>max<wbr/>Capture<wbr/>Stall</a>.<wbr/></li> +<li>Only the below controls are effective for reprocessing requests and will be present + in capture results.<wbr/> The reprocess requests are from the original capture results that + are associated with the intermediate <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> + output buffers.<wbr/> All other controls in the reprocess requests will be ignored by the + camera device.<wbr/><ul> +<li>android.<wbr/>jpeg.<wbr/>*</li> +<li><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a></li> +<li><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a></li> +<li><a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a></li> +</ul> +</li> +<li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> and + <a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a> will both list ZERO_<wbr/>SHUTTER_<wbr/>LAG as a supported mode.<wbr/></li> +</ul></span> + </li> + <li> + <span class="entry_type_enum_name">DEPTH_OUTPUT</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>The camera device can produce depth measurements from its field of view.<wbr/></p> +<p>This capability requires the camera device to support the following:</p> +<ul> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#DEPTH16">ImageFormat#DEPTH16</a> is supported as an output format.<wbr/></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#DEPTH_POINT_CLOUD">Image<wbr/>Format#DEPTH_<wbr/>POINT_<wbr/>CLOUD</a> is optionally supported as an + output format.<wbr/></li> +<li>This camera device,<wbr/> and all camera devices with the same <a href="#static_android.lens.facing">android.<wbr/>lens.<wbr/>facing</a>,<wbr/> + will list the following calibration entries in both + <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a> and + <a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">CaptureResult</a>:<ul> +<li><a href="#static_android.lens.poseTranslation">android.<wbr/>lens.<wbr/>pose<wbr/>Translation</a></li> +<li><a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a></li> +<li><a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a></li> +<li><a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a></li> +</ul> +</li> +<li>The <a href="#static_android.depth.depthIsExclusive">android.<wbr/>depth.<wbr/>depth<wbr/>Is<wbr/>Exclusive</a> entry is listed by this device.<wbr/></li> +<li>A LIMITED camera with only the DEPTH_<wbr/>OUTPUT capability does not have to support + normal YUV_<wbr/>420_<wbr/>888,<wbr/> JPEG,<wbr/> and PRIV-format outputs.<wbr/> It only has to support the DEPTH16 + format.<wbr/></li> +</ul> +<p>Generally,<wbr/> depth output operates at a slower frame rate than standard color capture,<wbr/> +so the DEPTH16 and DEPTH_<wbr/>POINT_<wbr/>CLOUD formats will commonly have a stall duration that +should be accounted for (see +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>).<wbr/> +On a device that supports both depth and color-based output,<wbr/> to enable smooth preview,<wbr/> +using a repeating burst is recommended,<wbr/> where a depth-output target is only included +once every N frames,<wbr/> where N is the ratio between preview output rate and depth output +rate,<wbr/> including depth stall time.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CONSTRAINED_HIGH_SPEED_VIDEO</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>The device supports constrained high speed video recording (frame rate >=120fps) +use case.<wbr/> The camera device will support high speed capture session created by +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>,<wbr/> which +only accepts high speed request lists created by +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>.<wbr/></p> +<p>A camera device can still support high speed video streaming by advertising the high speed +FPS ranges in <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a>.<wbr/> For this case,<wbr/> all normal +capture request per frame control and synchronization requirements will apply to +the high speed fps ranges,<wbr/> the same as all other fps ranges.<wbr/> This capability describes +the capability of a specialized operating mode with many limitations (see below),<wbr/> which +is only targeted at high speed video recording.<wbr/></p> +<p>The supported high speed video sizes and fps ranges are specified in +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoFpsRanges">StreamConfigurationMap#getHighSpeedVideoFpsRanges</a>.<wbr/> +To get desired output frame rates,<wbr/> the application is only allowed to select video size +and FPS range combinations provided by +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoSizes">StreamConfigurationMap#getHighSpeedVideoSizes</a>.<wbr/> +The fps range can be controlled via <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a>.<wbr/></p> +<p>In this capability,<wbr/> the camera device will override aeMode,<wbr/> awbMode,<wbr/> and afMode to +ON,<wbr/> AUTO,<wbr/> and CONTINUOUS_<wbr/>VIDEO,<wbr/> respectively.<wbr/> All post-processing block mode +controls will be overridden to be FAST.<wbr/> Therefore,<wbr/> no manual control of capture +and post-processing parameters is possible.<wbr/> All other controls operate the +same as when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == AUTO.<wbr/> This means that all other +android.<wbr/>control.<wbr/>* fields continue to work,<wbr/> such as</p> +<ul> +<li><a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a></li> +<li><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a></li> +<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li> +<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li> +<li><a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></li> +<li><a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a></li> +<li><a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a></li> +<li><a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a></li> +<li><a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a></li> +<li><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a></li> +</ul> +<p>Outside of android.<wbr/>control.<wbr/>*,<wbr/> the following controls will work:</p> +<ul> +<li><a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> (TORCH mode only,<wbr/> automatic flash for still capture will not +work since aeMode is ON)</li> +<li><a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> (if it is supported)</li> +<li><a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a></li> +<li><a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> (if it is supported)</li> +</ul> +<p>For high speed recording use case,<wbr/> the actual maximum supported frame rate may +be lower than what camera can output,<wbr/> depending on the destination Surfaces for +the image data.<wbr/> For example,<wbr/> if the destination surface is from video encoder,<wbr/> +the application need check if the video encoder is capable of supporting the +high frame rate for a given video size,<wbr/> or it will end up with lower recording +frame rate.<wbr/> If the destination surface is from preview window,<wbr/> the actual preview frame +rate will be bounded by the screen refresh rate.<wbr/></p> +<p>The camera device will only support up to 2 high speed simultaneous output surfaces +(preview and recording surfaces) +in this mode.<wbr/> Above controls will be effective only if all of below conditions are true:</p> +<ul> +<li>The application creates a camera capture session with no more than 2 surfaces via +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>.<wbr/> The +targeted surfaces must be preview surface (either from +<a href="https://developer.android.com/reference/android/view/SurfaceView.html">SurfaceView</a> or <a href="https://developer.android.com/reference/android/graphics/SurfaceTexture.html">SurfaceTexture</a>) or +recording surface(either from <a href="https://developer.android.com/reference/android/media/MediaRecorder.html#getSurface">MediaRecorder#getSurface</a> or +<a href="https://developer.android.com/reference/android/media/MediaCodec.html#createInputSurface">MediaCodec#createInputSurface</a>).<wbr/></li> +<li>The stream sizes are selected from the sizes reported by +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoSizes">StreamConfigurationMap#getHighSpeedVideoSizes</a>.<wbr/></li> +<li>The FPS ranges are selected from +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoFpsRanges">StreamConfigurationMap#getHighSpeedVideoFpsRanges</a>.<wbr/></li> +</ul> +<p>When above conditions are NOT satistied,<wbr/> +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a> +will fail.<wbr/></p> +<p>Switching to a FPS range that has different maximum FPS may trigger some camera device +reconfigurations,<wbr/> which may introduce extra latency.<wbr/> It is recommended that +the application avoids unnecessary maximum target FPS changes as much as possible +during high speed streaming.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of capabilities that this camera device +advertises as fully supporting.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>A capability is a contract that the camera device makes in order +to be able to satisfy one or more use cases.<wbr/></p> +<p>Listing a capability guarantees that the whole set of features +required to support a common use will all be available.<wbr/></p> +<p>Using a subset of the functionality provided by an unsupported +capability may be possible on a specific camera device implementation; +to do this query each of <a href="#static_android.request.availableRequestKeys">android.<wbr/>request.<wbr/>available<wbr/>Request<wbr/>Keys</a>,<wbr/> +<a href="#static_android.request.availableResultKeys">android.<wbr/>request.<wbr/>available<wbr/>Result<wbr/>Keys</a>,<wbr/> +<a href="#static_android.request.availableCharacteristicsKeys">android.<wbr/>request.<wbr/>available<wbr/>Characteristics<wbr/>Keys</a>.<wbr/></p> +<p>The following capabilities are guaranteed to be available on +<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> <code>==</code> FULL devices:</p> +<ul> +<li>MANUAL_<wbr/>SENSOR</li> +<li>MANUAL_<wbr/>POST_<wbr/>PROCESSING</li> +</ul> +<p>Other capabilities may be available on either FULL or LIMITED +devices,<wbr/> but the application should query this key to be sure.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Additional constraint details per-capability will be available +in the Compatibility Test Suite.<wbr/></p> +<p>Minimum baseline requirements required for the +BACKWARD_<wbr/>COMPATIBLE capability are not explicitly listed.<wbr/> +Instead refer to "BC" tags and the camera CTS tests in the +android.<wbr/>hardware.<wbr/>camera2.<wbr/>cts package.<wbr/></p> +<p>Listed controls that can be either request or result (e.<wbr/>g.<wbr/> +<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>) must be available both in the +request and the result in order to be considered to be +capability-compliant.<wbr/></p> +<p>For example,<wbr/> if the HAL claims to support MANUAL control,<wbr/> +then exposure time must be configurable via the request <em>and</em> +the actual exposure applied must be available via +the result.<wbr/></p> +<p>If MANUAL_<wbr/>SENSOR is omitted,<wbr/> the HAL may choose to omit the +<a href="#static_android.scaler.availableMinFrameDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Min<wbr/>Frame<wbr/>Durations</a> static property entirely.<wbr/></p> +<p>For PRIVATE_<wbr/>REPROCESSING and YUV_<wbr/>REPROCESSING capabilities,<wbr/> see +hardware/<wbr/>libhardware/<wbr/>include/<wbr/>hardware/<wbr/>camera3.<wbr/>h Section 10 for more information.<wbr/></p> +<p>Devices that support the MANUAL_<wbr/>SENSOR capability must support the +CAMERA3_<wbr/>TEMPLATE_<wbr/>MANUAL template defined in camera3.<wbr/>h.<wbr/></p> +<p>Devices that support the PRIVATE_<wbr/>REPROCESSING capability or the +YUV_<wbr/>REPROCESSING capability must support the +CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template defined in camera3.<wbr/>h.<wbr/></p> +<p>For DEPTH_<wbr/>OUTPUT,<wbr/> the depth-format keys +<a href="#static_android.depth.availableDepthStreamConfigurations">android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stream<wbr/>Configurations</a>,<wbr/> +<a href="#static_android.depth.availableDepthMinFrameDurations">android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Min<wbr/>Frame<wbr/>Durations</a>,<wbr/> +<a href="#static_android.depth.availableDepthStallDurations">android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stall<wbr/>Durations</a> must be available,<wbr/> in +addition to the other keys explicitly mentioned in the DEPTH_<wbr/>OUTPUT +enum notes.<wbr/> The entry <a href="#static_android.depth.maxDepthSamples">android.<wbr/>depth.<wbr/>max<wbr/>Depth<wbr/>Samples</a> must be available +if the DEPTH_<wbr/>POINT_<wbr/>CLOUD format is supported (HAL pixel format BLOB,<wbr/> dataspace +DEPTH).<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.availableRequestKeys"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>request.<wbr/>available<wbr/>Request<wbr/>Keys + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A list of all keys that the camera device has available +to use with <a href="https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html">CaptureRequest</a>.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Attempting to set a key into a CaptureRequest that is not +listed here will result in an invalid request and will be rejected +by the camera device.<wbr/></p> +<p>This field can be used to query the feature set of a camera device +at a more granular level than capabilities.<wbr/> This is especially +important for optional keys that are not listed under any capability +in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Vendor tags must not be listed here.<wbr/> Use the vendor tag metadata +extensions C api instead (refer to camera3.<wbr/>h for more details).<wbr/></p> +<p>Setting/<wbr/>getting vendor tags will be checked against the metadata +vendor extensions API and not against this field.<wbr/></p> +<p>The HAL must not consume any request tags that are not listed either +here or in the vendor tag list.<wbr/></p> +<p>The public camera2 API will always make the vendor tags visible +via +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureRequestKeys">CameraCharacteristics#getAvailableCaptureRequestKeys</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.availableResultKeys"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>request.<wbr/>available<wbr/>Result<wbr/>Keys + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A list of all keys that the camera device has available +to use with <a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">CaptureResult</a>.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Attempting to get a key from a CaptureResult that is not +listed here will always return a <code>null</code> value.<wbr/> Getting a key from +a CaptureResult that is listed here will generally never return a <code>null</code> +value.<wbr/></p> +<p>The following keys may return <code>null</code> unless they are enabled:</p> +<ul> +<li><a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> (non-null iff <a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> == ON)</li> +</ul> +<p>(Those sometimes-null keys will nevertheless be listed here +if they are available.<wbr/>)</p> +<p>This field can be used to query the feature set of a camera device +at a more granular level than capabilities.<wbr/> This is especially +important for optional keys that are not listed under any capability +in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Tags listed here must always have an entry in the result metadata,<wbr/> +even if that size is 0 elements.<wbr/> Only array-type tags (e.<wbr/>g.<wbr/> lists,<wbr/> +matrices,<wbr/> strings) are allowed to have 0 elements.<wbr/></p> +<p>Vendor tags must not be listed here.<wbr/> Use the vendor tag metadata +extensions C api instead (refer to camera3.<wbr/>h for more details).<wbr/></p> +<p>Setting/<wbr/>getting vendor tags will be checked against the metadata +vendor extensions API and not against this field.<wbr/></p> +<p>The HAL must not produce any result tags that are not listed either +here or in the vendor tag list.<wbr/></p> +<p>The public camera2 API will always make the vendor tags visible via <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureResultKeys">CameraCharacteristics#getAvailableCaptureResultKeys</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.request.availableCharacteristicsKeys"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>request.<wbr/>available<wbr/>Characteristics<wbr/>Keys + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A list of all keys that the camera device has available +to use with <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a>.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry follows the same rules as +<a href="#static_android.request.availableResultKeys">android.<wbr/>request.<wbr/>available<wbr/>Result<wbr/>Keys</a> (except that it applies for +CameraCharacteristics instead of CaptureResult).<wbr/> See above for more +details.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Keys listed here must always have an entry in the static info metadata,<wbr/> +even if that size is 0 elements.<wbr/> Only array-type tags (e.<wbr/>g.<wbr/> lists,<wbr/> +matrices,<wbr/> strings) are allowed to have 0 elements.<wbr/></p> +<p>Vendor tags must not be listed here.<wbr/> Use the vendor tag metadata +extensions C api instead (refer to camera3.<wbr/>h for more details).<wbr/></p> +<p>Setting/<wbr/>getting vendor tags will be checked against the metadata +vendor extensions API and not against this field.<wbr/></p> +<p>The HAL must not have any tags in its static info that are not listed +either here or in the vendor tag list.<wbr/></p> +<p>The public camera2 API will always make the vendor tags visible +via <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getKeys">CameraCharacteristics#getKeys</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.request.frameCount"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>request.<wbr/>frame<wbr/>Count + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [hidden]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A frame counter set by the framework.<wbr/> This value monotonically +increases with every new result (that is,<wbr/> each new result has a unique +frameCount value).<wbr/></p> + </td> + + <td class="entry_units"> + count of frames + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + <p>> 0</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Reset on release()</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.request.id"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>request.<wbr/>id + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [hidden]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>An application-specified ID for the current +request.<wbr/> Must be maintained unchanged in output +frame</p> + </td> + + <td class="entry_units"> + arbitrary integer assigned by application + </td> + + <td class="entry_range"> + <p>Any int</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.request.metadataMode"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>request.<wbr/>metadata<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">NONE</span> + <span class="entry_type_enum_notes"><p>No metadata should be produced on output,<wbr/> except +for application-bound buffer data.<wbr/> If no +application-bound streams exist,<wbr/> no frame should be +placed in the output frame queue.<wbr/> If such streams +exist,<wbr/> a frame should be placed on the output queue +with null metadata but with the necessary output buffer +information.<wbr/> Timestamp information should still be +included with any output stream buffers</p></span> + </li> + <li> + <span class="entry_type_enum_name">FULL</span> + <span class="entry_type_enum_notes"><p>All metadata should be produced.<wbr/> Statistics will +only be produced if they are separately +enabled</p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>How much metadata to produce on +output</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.request.outputStreams"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>request.<wbr/>output<wbr/>Streams + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Lists which camera output streams image data +from this capture must be sent to</p> + </td> + + <td class="entry_units"> + List of camera stream IDs + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + <p>List must only include streams that have been +created</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_HAL2">HAL2</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If no output streams are listed,<wbr/> then the image +data should simply be discarded.<wbr/> The image data must +still be captured for metadata and statistics production,<wbr/> +and the lens and flash must operate as requested.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.request.pipelineDepth"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>request.<wbr/>pipeline<wbr/>Depth + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Specifies the number of pipeline stages the frame went +through from when it was exposed to when the final completed result +was available to the framework.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><= <a href="#static_android.request.pipelineMaxDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Depending on what settings are used in the request,<wbr/> and +what streams are configured,<wbr/> the data may undergo less processing,<wbr/> +and some pipeline stages skipped.<wbr/></p> +<p>See <a href="#static_android.request.pipelineMaxDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth</a> for more details.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This value must always represent the accurate count of how many +pipeline stages were actually used.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_scaler" class="section">scaler</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.scaler.cropRegion"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>scaler.<wbr/>crop<wbr/>Region + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public as rectangle]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired region of the sensor to read out for this capture.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates relative to + android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control can be used to implement digital zoom.<wbr/></p> +<p>The crop region coordinate system is based off +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with <code>(0,<wbr/> 0)</code> being the +top-left corner of the sensor active array.<wbr/></p> +<p>Output streams use this rectangle to produce their output,<wbr/> +cropping to a smaller region if necessary to maintain the +stream's aspect ratio,<wbr/> then scaling the sensor input to +match the output's configured resolution.<wbr/></p> +<p>The crop region is applied after the RAW to other color +space (e.<wbr/>g.<wbr/> YUV) conversion.<wbr/> Since raw streams +(e.<wbr/>g.<wbr/> RAW16) don't have the conversion stage,<wbr/> they are not +croppable.<wbr/> The crop region will be ignored by raw streams.<wbr/></p> +<p>For non-raw streams,<wbr/> any additional per-stream cropping will +be done to maximize the final pixel area of the stream.<wbr/></p> +<p>For example,<wbr/> if the crop region is set to a 4:3 aspect +ratio,<wbr/> then 4:3 streams will use the exact crop +region.<wbr/> 16:9 streams will further crop vertically +(letterbox).<wbr/></p> +<p>Conversely,<wbr/> if the crop region is set to a 16:9,<wbr/> then 4:3 +outputs will crop horizontally (pillarbox),<wbr/> and 16:9 +streams will match exactly.<wbr/> These additional crops will +be centered within the crop region.<wbr/></p> +<p>The width and height of the crop region cannot +be set to be smaller than +<code>floor( activeArraySize.<wbr/>width /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code> and +<code>floor( activeArraySize.<wbr/>height /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code>,<wbr/> respectively.<wbr/></p> +<p>The camera device may adjust the crop region to account +for rounding and other hardware requirements; the final +crop region used will be included in the output capture +result.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The output streams must maintain square pixels at all +times,<wbr/> no matter what the relative aspect ratios of the +crop region and the stream are.<wbr/> Negative values for +corner are allowed for raw output if full pixel array is +larger than active pixel array.<wbr/> Width and height may be +rounded to nearest larger supportable width,<wbr/> especially +for raw output,<wbr/> where only a few fixed scales may be +possible.<wbr/></p> +<p>For a set of output streams configured,<wbr/> if the sensor output is cropped to a smaller +size than active array size,<wbr/> the HAL need follow below cropping rules:</p> +<ul> +<li> +<p>The HAL need handle the cropRegion as if the sensor crop size is the effective active +array size.<wbr/>More specifically,<wbr/> the HAL must transform the request cropRegion from +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> to the sensor cropped pixel area size in this way:</p> +<ol> +<li>Translate the requested cropRegion w.<wbr/>r.<wbr/>t.,<wbr/> the left top corner of the sensor +cropped pixel area by (tx,<wbr/> ty),<wbr/> +where <code>tx = sensorCrop.<wbr/>top * (sensorCrop.<wbr/>height /<wbr/> activeArraySize.<wbr/>height)</code> +and <code>tx = sensorCrop.<wbr/>left * (sensorCrop.<wbr/>width /<wbr/> activeArraySize.<wbr/>width)</code>.<wbr/> The +(sensorCrop.<wbr/>top,<wbr/> sensorCrop.<wbr/>left) is the coordinate based off the +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></li> +<li>Scale the width and height of requested cropRegion with scaling factor of +sensor<wbr/>Crop.<wbr/>width/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>width and sensor<wbr/>Crop.<wbr/>height/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>height +respectively.<wbr/> +Once this new cropRegion is calculated,<wbr/> the HAL must use this region to crop the image +with regard to the sensor crop size (effective active array size).<wbr/> The HAL still need +follow the general cropping rule for this new cropRegion and effective active +array size.<wbr/></li> +</ol> +</li> +<li> +<p>The HAL must report the cropRegion with regard to <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/> +The HAL need convert the new cropRegion generated above w.<wbr/>r.<wbr/>t.,<wbr/> full active array size.<wbr/> +The reported cropRegion may be slightly different with the requested cropRegion since +the HAL may adjust the crop region to account for rounding,<wbr/> conversion error,<wbr/> or other +hardware limitations.<wbr/></p> +</li> +</ul> +<p>HAL2.<wbr/>x uses only (x,<wbr/> y,<wbr/> width)</p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.scaler.availableFormats"> + <td class="entry_name + entry_name_deprecated + " rowspan="5"> + android.<wbr/>scaler.<wbr/>available<wbr/>Formats + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [hidden as imageFormat]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">RAW16</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_value">0x20</span> + <span class="entry_type_enum_notes"><p>RAW16 is a standard,<wbr/> cross-platform format for raw image +buffers with 16-bit pixels.<wbr/></p> +<p>Buffers of this format are typically expected to have a +Bayer Color Filter Array (CFA) layout,<wbr/> which is given in +<a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>.<wbr/> Sensors with +CFAs that are not representable by a format in +<a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a> should not +use this format.<wbr/></p> +<p>Buffers of this format will also follow the constraints given for +RAW_<wbr/>OPAQUE buffers,<wbr/> but with relaxed performance constraints.<wbr/></p> +<p>This format is intended to give users access to the full contents +of the buffers coming directly from the image sensor prior to any +cropping or scaling operations,<wbr/> and all coordinate systems for +metadata used for this format are relative to the size of the +active region of the image sensor before any geometric distortion +correction has been applied (i.<wbr/>e.<wbr/> +<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>).<wbr/> Supported +dimensions for this format are limited to the full dimensions of +the sensor (e.<wbr/>g.<wbr/> either <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a> or +<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> will be the +only supported output size).<wbr/></p> +<p>See <a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a> for +the full set of performance guarantees.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">RAW_OPAQUE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_value">0x24</span> + <span class="entry_type_enum_notes"><p>RAW_<wbr/>OPAQUE (or +<a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_PRIVATE">RAW_<wbr/>PRIVATE</a> +as referred in public API) is a format for raw image buffers +coming from an image sensor.<wbr/></p> +<p>The actual structure of buffers of this format is +platform-specific,<wbr/> but must follow several constraints:</p> +<ol> +<li>No image post-processing operations may have been applied to +buffers of this type.<wbr/> These buffers contain raw image data coming +directly from the image sensor.<wbr/></li> +<li>If a buffer of this format is passed to the camera device for +reprocessing,<wbr/> the resulting images will be identical to the images +produced if the buffer had come directly from the sensor and was +processed with the same settings.<wbr/></li> +</ol> +<p>The intended use for this format is to allow access to the native +raw format buffers coming directly from the camera sensor without +any additional conversions or decrease in framerate.<wbr/></p> +<p>See <a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a> for the full set of +performance guarantees.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">YV12</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_value">0x32315659</span> + <span class="entry_type_enum_notes"><p>YCrCb 4:2:0 Planar</p></span> + </li> + <li> + <span class="entry_type_enum_name">YCrCb_420_SP</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_value">0x11</span> + <span class="entry_type_enum_notes"><p>NV21</p></span> + </li> + <li> + <span class="entry_type_enum_name">IMPLEMENTATION_DEFINED</span> + <span class="entry_type_enum_value">0x22</span> + <span class="entry_type_enum_notes"><p>System internal format,<wbr/> not application-accessible</p></span> + </li> + <li> + <span class="entry_type_enum_name">YCbCr_420_888</span> + <span class="entry_type_enum_value">0x23</span> + <span class="entry_type_enum_notes"><p>Flexible YUV420 Format</p></span> + </li> + <li> + <span class="entry_type_enum_name">BLOB</span> + <span class="entry_type_enum_value">0x21</span> + <span class="entry_type_enum_notes"><p>JPEG format</p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The list of image formats that are supported by this +camera device for output streams.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>All camera devices will support JPEG and YUV_<wbr/>420_<wbr/>888 formats.<wbr/></p> +<p>When set to YUV_<wbr/>420_<wbr/>888,<wbr/> application can access the YUV420 data directly.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>These format values are from HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>* in +system/<wbr/>core/<wbr/>include/<wbr/>system/<wbr/>graphics.<wbr/>h.<wbr/></p> +<p>When IMPLEMENTATION_<wbr/>DEFINED is used,<wbr/> the platform +gralloc module will select a format based on the usage flags provided +by the camera HAL device and the other endpoint of the stream.<wbr/> It is +usually used by preview and recording streams,<wbr/> where the application doesn't +need access the image data.<wbr/></p> +<p>YCb<wbr/>Cr_<wbr/>420_<wbr/>888 format must be supported by the HAL.<wbr/> When an image stream +needs CPU/<wbr/>application direct access,<wbr/> this format will be used.<wbr/></p> +<p>The BLOB format must be supported by the HAL.<wbr/> This is used for the JPEG stream.<wbr/></p> +<p>A RAW_<wbr/>OPAQUE buffer should contain only pixel data.<wbr/> It is strongly +recommended that any information used by the camera device when +processing images is fully expressed by the result metadata +for that image buffer.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableJpegMinDurations"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Min<wbr/>Durations + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [hidden]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The minimum frame duration that is supported +for each resolution in <a href="#static_android.scaler.availableJpegSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Sizes</a>.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + <p>TODO: Remove property.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This corresponds to the minimum steady-state frame duration when only +that JPEG stream is active and captured in a burst,<wbr/> with all +processing (typically in android.<wbr/>*.<wbr/>mode) set to FAST.<wbr/></p> +<p>When multiple streams are configured,<wbr/> the minimum +frame duration will be >= max(individual stream min +durations)</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableJpegSizes"> + <td class="entry_name + entry_name_deprecated + " rowspan="5"> + android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Sizes + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 2 + </span> + <span class="entry_type_visibility"> [hidden as size]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The JPEG resolutions that are supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + <p>TODO: Remove property.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The resolutions are listed as <code>(width,<wbr/> height)</code> pairs.<wbr/> All camera devices will support +sensor maximum resolution (defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>).<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL must include sensor maximum resolution +(defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>),<wbr/> +and should include half/<wbr/>quarter of sensor maximum resolution.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableMaxDigitalZoom"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum ratio between both active area width +and crop region width,<wbr/> and active area height and +crop region height,<wbr/> for <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>.<wbr/></p> + </td> + + <td class="entry_units"> + Zoom scale factor + </td> + + <td class="entry_range"> + <p>>=1</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This represents the maximum amount of zooming possible by +the camera device,<wbr/> or equivalently,<wbr/> the minimum cropping +window size.<wbr/></p> +<p>Crop regions that have a width or height that is smaller +than this ratio allows will be rounded up to the minimum +allowed size by the camera device.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableProcessedMinDurations"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>scaler.<wbr/>available<wbr/>Processed<wbr/>Min<wbr/>Durations + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [hidden]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>For each available processed output size (defined in +<a href="#static_android.scaler.availableProcessedSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Processed<wbr/>Sizes</a>),<wbr/> this property lists the +minimum supportable frame duration for that size.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This should correspond to the frame duration when only that processed +stream is active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode) +set to FAST.<wbr/></p> +<p>When multiple streams are configured,<wbr/> the minimum frame duration will +be >= max(individual stream min durations).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableProcessedSizes"> + <td class="entry_name + entry_name_deprecated + " rowspan="5"> + android.<wbr/>scaler.<wbr/>available<wbr/>Processed<wbr/>Sizes + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 2 + </span> + <span class="entry_type_visibility"> [hidden as size]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The resolutions available for use with +processed output streams,<wbr/> such as YV12,<wbr/> NV12,<wbr/> and +platform opaque YUV/<wbr/>RGB streams to the GPU or video +encoders.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The resolutions are listed as <code>(width,<wbr/> height)</code> pairs.<wbr/></p> +<p>For a given use case,<wbr/> the actual maximum supported resolution +may be lower than what is listed here,<wbr/> depending on the destination +Surface for the image data.<wbr/> For example,<wbr/> for recording video,<wbr/> +the video encoder chosen may have a maximum size limit (e.<wbr/>g.<wbr/> 1080p) +smaller than what the camera (e.<wbr/>g.<wbr/> maximum resolution is 3264x2448) +can provide.<wbr/></p> +<p>Please reference the documentation for the image data destination to +check if it limits the maximum size for image data.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For FULL capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>),<wbr/> +the HAL must include all JPEG sizes listed in <a href="#static_android.scaler.availableJpegSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Sizes</a> +and each below resolution if it is smaller than or equal to the sensor +maximum resolution (if they are not listed in JPEG sizes already):</p> +<ul> +<li>240p (320 x 240)</li> +<li>480p (640 x 480)</li> +<li>720p (1280 x 720)</li> +<li>1080p (1920 x 1080)</li> +</ul> +<p>For LIMITED capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>),<wbr/> +the HAL only has to list up to the maximum video size supported by the devices.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableRawMinDurations"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>scaler.<wbr/>available<wbr/>Raw<wbr/>Min<wbr/>Durations + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [system]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>For each available raw output size (defined in +<a href="#static_android.scaler.availableRawSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Raw<wbr/>Sizes</a>),<wbr/> this property lists the minimum +supportable frame duration for that size.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Should correspond to the frame duration when only the raw stream is +active.<wbr/></p> +<p>When multiple streams are configured,<wbr/> the minimum +frame duration will be >= max(individual stream min +durations)</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableRawSizes"> + <td class="entry_name + entry_name_deprecated + " rowspan="1"> + android.<wbr/>scaler.<wbr/>available<wbr/>Raw<wbr/>Sizes + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 2 + </span> + <span class="entry_type_visibility"> [system as size]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The resolutions available for use with raw +sensor output streams,<wbr/> listed as width,<wbr/> +height</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableInputOutputFormatsMap"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [hidden as reprocessFormatsMap]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The mapping of image formats that are supported by this +camera device for input streams,<wbr/> to their corresponding output formats.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>All camera devices with at least 1 +<a href="#static_android.request.maxNumInputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams</a> will have at least one +available input format.<wbr/></p> +<p>The camera device will support the following map of formats,<wbr/> +if its dependent capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>) is supported:</p> +<table> +<thead> +<tr> +<th align="left">Input Format</th> +<th align="left">Output Format</th> +<th align="left">Capability</th> +</tr> +</thead> +<tbody> +<tr> +<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a></td> +<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td> +<td align="left">PRIVATE_<wbr/>REPROCESSING</td> +</tr> +<tr> +<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a></td> +<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td> +<td align="left">PRIVATE_<wbr/>REPROCESSING</td> +</tr> +<tr> +<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td> +<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td> +<td align="left">YUV_<wbr/>REPROCESSING</td> +</tr> +<tr> +<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td> +<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td> +<td align="left">YUV_<wbr/>REPROCESSING</td> +</tr> +</tbody> +</table> +<p>PRIVATE refers to a device-internal format that is not directly application-visible.<wbr/> A +PRIVATE input surface can be acquired by <a href="https://developer.android.com/reference/android/media/ImageReader.html#newInstance">ImageReader#newInstance</a> +with <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> as the format.<wbr/></p> +<p>For a PRIVATE_<wbr/>REPROCESSING-capable camera device,<wbr/> using the PRIVATE format as either input +or output will never hurt maximum frame rate (i.<wbr/>e.<wbr/> <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">getOutputStallDuration(ImageFormat.<wbr/>PRIVATE,<wbr/> size)</a> is always 0),<wbr/></p> +<p>Attempting to configure an input stream with output streams not +listed as available in this map is not valid.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For the formats,<wbr/> see <code>system/<wbr/>core/<wbr/>include/<wbr/>system/<wbr/>graphics.<wbr/>h</code> for a definition +of the image format enumerations.<wbr/> The PRIVATE format refers to the +HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>IMPLEMENTATION_<wbr/>DEFINED format.<wbr/> The HAL could determine +the actual format by using the gralloc usage flags.<wbr/> +For ZSL use case in particular,<wbr/> the HAL could choose appropriate format (partially +processed YUV or RAW based format) by checking the format and GRALLOC_<wbr/>USAGE_<wbr/>HW_<wbr/>CAMERA_<wbr/>ZSL.<wbr/> +See camera3.<wbr/>h for more details.<wbr/></p> +<p>This value is encoded as a variable-size array-of-arrays.<wbr/> +The inner array always contains <code>[format,<wbr/> length,<wbr/> ...<wbr/>]</code> where +<code>...<wbr/></code> has <code>length</code> elements.<wbr/> An inner array is followed by another +inner array if the total metadata entry size hasn't yet been exceeded.<wbr/></p> +<p>A code sample to read/<wbr/>write this encoding (with a device that +supports reprocessing IMPLEMENTATION_<wbr/>DEFINED to YUV_<wbr/>420_<wbr/>888,<wbr/> and JPEG,<wbr/> +and reprocessing YUV_<wbr/>420_<wbr/>888 to YUV_<wbr/>420_<wbr/>888 and JPEG):</p> +<pre><code>//<wbr/> reading +int32_<wbr/>t* contents = &entry.<wbr/>i32[0]; +for (size_<wbr/>t i = 0; i < entry.<wbr/>count; ) { + int32_<wbr/>t format = contents[i++]; + int32_<wbr/>t length = contents[i++]; + int32_<wbr/>t output_<wbr/>formats[length]; + memcpy(&output_<wbr/>formats[0],<wbr/> &contents[i],<wbr/> + length * sizeof(int32_<wbr/>t)); + i += length; +} + +//<wbr/> writing (static example,<wbr/> PRIVATE_<wbr/>REPROCESSING + YUV_<wbr/>REPROCESSING) +int32_<wbr/>t[] contents = { + IMPLEMENTATION_<wbr/>DEFINED,<wbr/> 2,<wbr/> YUV_<wbr/>420_<wbr/>888,<wbr/> BLOB,<wbr/> + YUV_<wbr/>420_<wbr/>888,<wbr/> 2,<wbr/> YUV_<wbr/>420_<wbr/>888,<wbr/> BLOB,<wbr/> +}; +update_<wbr/>camera_<wbr/>metadata_<wbr/>entry(metadata,<wbr/> index,<wbr/> &contents[0],<wbr/> + sizeof(contents)/<wbr/>sizeof(contents[0]),<wbr/> &updated_<wbr/>entry); +</code></pre> +<p>If the HAL claims to support any of the capabilities listed in the +above details,<wbr/> then it must also support all the input-output +combinations listed for that capability.<wbr/> It can optionally support +additional formats if it so chooses.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableStreamConfigurations"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 4 + </span> + <span class="entry_type_visibility"> [ndk_public as streamConfiguration]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OUTPUT</span> + </li> + <li> + <span class="entry_type_enum_name">INPUT</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The available stream configurations that this +camera device supports +(i.<wbr/>e.<wbr/> format,<wbr/> width,<wbr/> height,<wbr/> output/<wbr/>input stream).<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The configurations are listed as <code>(format,<wbr/> width,<wbr/> height,<wbr/> input?)</code> +tuples.<wbr/></p> +<p>For a given use case,<wbr/> the actual maximum supported resolution +may be lower than what is listed here,<wbr/> depending on the destination +Surface for the image data.<wbr/> For example,<wbr/> for recording video,<wbr/> +the video encoder chosen may have a maximum size limit (e.<wbr/>g.<wbr/> 1080p) +smaller than what the camera (e.<wbr/>g.<wbr/> maximum resolution is 3264x2448) +can provide.<wbr/></p> +<p>Please reference the documentation for the image data destination to +check if it limits the maximum size for image data.<wbr/></p> +<p>Not all output formats may be supported in a configuration with +an input stream of a particular format.<wbr/> For more details,<wbr/> see +<a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a>.<wbr/></p> +<p>The following table describes the minimum required output stream +configurations based on the hardware level +(<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a>):</p> +<table> +<thead> +<tr> +<th align="center">Format</th> +<th align="center">Size</th> +<th align="center">Hardware Level</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center">JPEG</td> +<td align="center"><a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></td> +<td align="center">Any</td> +<td align="center"></td> +</tr> +<tr> +<td align="center">JPEG</td> +<td align="center">1920x1080 (1080p)</td> +<td align="center">Any</td> +<td align="center">if 1080p <= activeArraySize</td> +</tr> +<tr> +<td align="center">JPEG</td> +<td align="center">1280x720 (720)</td> +<td align="center">Any</td> +<td align="center">if 720p <= activeArraySize</td> +</tr> +<tr> +<td align="center">JPEG</td> +<td align="center">640x480 (480p)</td> +<td align="center">Any</td> +<td align="center">if 480p <= activeArraySize</td> +</tr> +<tr> +<td align="center">JPEG</td> +<td align="center">320x240 (240p)</td> +<td align="center">Any</td> +<td align="center">if 240p <= activeArraySize</td> +</tr> +<tr> +<td align="center">YUV_<wbr/>420_<wbr/>888</td> +<td align="center">all output sizes available for JPEG</td> +<td align="center">FULL</td> +<td align="center"></td> +</tr> +<tr> +<td align="center">YUV_<wbr/>420_<wbr/>888</td> +<td align="center">all output sizes available for JPEG,<wbr/> up to the maximum video size</td> +<td align="center">LIMITED</td> +<td align="center"></td> +</tr> +<tr> +<td align="center">IMPLEMENTATION_<wbr/>DEFINED</td> +<td align="center">same as YUV_<wbr/>420_<wbr/>888</td> +<td align="center">Any</td> +<td align="center"></td> +</tr> +</tbody> +</table> +<p>Refer to <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> for additional +mandatory stream configurations on a per-capability basis.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>It is recommended (but not mandatory) to also include half/<wbr/>quarter +of sensor maximum resolution for JPEG formats (regardless of hardware +level).<wbr/></p> +<p>(The following is a rewording of the above required table):</p> +<p>For JPEG format,<wbr/> the sizes may be restricted by below conditions:</p> +<ul> +<li>The HAL may choose the aspect ratio of each Jpeg size to be one of well known ones +(e.<wbr/>g.<wbr/> 4:3,<wbr/> 16:9,<wbr/> 3:2 etc.<wbr/>).<wbr/> If the sensor maximum resolution +(defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) has an aspect ratio other than these,<wbr/> +it does not have to be included in the supported JPEG sizes.<wbr/></li> +<li>Some hardware JPEG encoders may have pixel boundary alignment requirements,<wbr/> such as +the dimensions being a multiple of 16.<wbr/></li> +</ul> +<p>Therefore,<wbr/> the maximum JPEG size may be smaller than sensor maximum resolution.<wbr/> +However,<wbr/> the largest JPEG size must be as close as possible to the sensor maximum +resolution given above constraints.<wbr/> It is required that after aspect ratio adjustments,<wbr/> +additional size reduction due to other issues must be less than 3% in area.<wbr/> For example,<wbr/> +if the sensor maximum resolution is 3280x2464,<wbr/> if the maximum JPEG size has aspect +ratio 4:3,<wbr/> the JPEG encoder alignment requirement is 16,<wbr/> the maximum JPEG size will be +3264x2448.<wbr/></p> +<p>For FULL capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>),<wbr/> +the HAL must include all YUV_<wbr/>420_<wbr/>888 sizes that have JPEG sizes listed +here as output streams.<wbr/></p> +<p>It must also include each below resolution if it is smaller than or +equal to the sensor maximum resolution (for both YUV_<wbr/>420_<wbr/>888 and JPEG +formats),<wbr/> as output streams:</p> +<ul> +<li>240p (320 x 240)</li> +<li>480p (640 x 480)</li> +<li>720p (1280 x 720)</li> +<li>1080p (1920 x 1080)</li> +</ul> +<p>For LIMITED capability devices +(<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>),<wbr/> +the HAL only has to list up to the maximum video size +supported by the device.<wbr/></p> +<p>Regardless of hardware level,<wbr/> every output resolution available for +YUV_<wbr/>420_<wbr/>888 must also be available for IMPLEMENTATION_<wbr/>DEFINED.<wbr/></p> +<p>This supercedes the following fields,<wbr/> which are now deprecated:</p> +<ul> +<li>availableFormats</li> +<li>available[Processed,<wbr/>Raw,<wbr/>Jpeg]Sizes</li> +</ul> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableMinFrameDurations"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>scaler.<wbr/>available<wbr/>Min<wbr/>Frame<wbr/>Durations + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 x n + </span> + <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>This lists the minimum frame duration for each +format/<wbr/>size combination.<wbr/></p> + </td> + + <td class="entry_units"> + (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This should correspond to the frame duration when only that +stream is active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode) +set to either OFF or FAST.<wbr/></p> +<p>When multiple streams are used in a request,<wbr/> the minimum frame +duration will be max(individual stream min durations).<wbr/></p> +<p>The minimum frame duration of a stream (of a particular format,<wbr/> size) +is the same regardless of whether the stream is input or output.<wbr/></p> +<p>See <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> and +<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> for more details about +calculating the max frame rate.<wbr/></p> +<p>(Keep in sync with +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>)</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.availableStallDurations"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 x n + </span> + <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>This lists the maximum stall duration for each +output format/<wbr/>size combination.<wbr/></p> + </td> + + <td class="entry_units"> + (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>A stall duration is how much extra time would get added +to the normal minimum frame duration for a repeating request +that has streams with non-zero stall.<wbr/></p> +<p>For example,<wbr/> consider JPEG captures which have the following +characteristics:</p> +<ul> +<li>JPEG streams act like processed YUV streams in requests for which +they are not included; in requests in which they are directly +referenced,<wbr/> they act as JPEG streams.<wbr/> This is because supporting a +JPEG stream requires the underlying YUV data to always be ready for +use by a JPEG encoder,<wbr/> but the encoder will only be used (and impact +frame duration) on requests that actually reference a JPEG stream.<wbr/></li> +<li>The JPEG processor can run concurrently to the rest of the camera +pipeline,<wbr/> but cannot process more than 1 capture at a time.<wbr/></li> +</ul> +<p>In other words,<wbr/> using a repeating YUV request would result +in a steady frame rate (let's say it's 30 FPS).<wbr/> If a single +JPEG request is submitted periodically,<wbr/> the frame rate will stay +at 30 FPS (as long as we wait for the previous JPEG to return each +time).<wbr/> If we try to submit a repeating YUV + JPEG request,<wbr/> then +the frame rate will drop from 30 FPS.<wbr/></p> +<p>In general,<wbr/> submitting a new request with a non-0 stall time +stream will <em>not</em> cause a frame rate drop unless there are still +outstanding buffers for that stream from previous requests.<wbr/></p> +<p>Submitting a repeating request with streams (call this <code>S</code>) +is the same as setting the minimum frame duration from +the normal minimum frame duration corresponding to <code>S</code>,<wbr/> added with +the maximum stall duration for <code>S</code>.<wbr/></p> +<p>If interleaving requests with and without a stall duration,<wbr/> +a request will stall by the maximum of the remaining times +for each can-stall stream with outstanding buffers.<wbr/></p> +<p>This means that a stalling request will not have an exposure start +until the stall has completed.<wbr/></p> +<p>This should correspond to the stall duration when only that stream is +active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode) set to FAST +or OFF.<wbr/> Setting any of the processing modes to HIGH_<wbr/>QUALITY +effectively results in an indeterminate stall duration for all +streams in a request (the regular stall calculation rules are +ignored).<wbr/></p> +<p>The following formats may always have a stall duration:</p> +<ul> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_SENSOR">ImageFormat#RAW_<wbr/>SENSOR</a></li> +</ul> +<p>The following formats will never have a stall duration:</p> +<ul> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></li> +<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">ImageFormat#RAW10</a></li> +</ul> +<p>All other formats may or may not have an allowed stall duration on +a per-capability basis; refer to <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> +for more details.<wbr/></p> +<p>See <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> for more information about +calculating the max frame rate (absent stalls).<wbr/></p> +<p>(Keep up to date with +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> )</p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If possible,<wbr/> it is recommended that all non-JPEG formats +(such as RAW16) should not have a stall duration.<wbr/> RAW10,<wbr/> RAW12,<wbr/> RAW_<wbr/>OPAQUE +and IMPLEMENTATION_<wbr/>DEFINED must not have stall durations.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.streamConfigurationMap"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [java_public as streamConfigurationMap]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The available stream configurations that this +camera device supports; also includes the minimum frame durations +and the stall durations for each format/<wbr/>size combination.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>All camera devices will support sensor maximum resolution (defined by +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) for the JPEG format.<wbr/></p> +<p>For a given use case,<wbr/> the actual maximum supported resolution +may be lower than what is listed here,<wbr/> depending on the destination +Surface for the image data.<wbr/> For example,<wbr/> for recording video,<wbr/> +the video encoder chosen may have a maximum size limit (e.<wbr/>g.<wbr/> 1080p) +smaller than what the camera (e.<wbr/>g.<wbr/> maximum resolution is 3264x2448) +can provide.<wbr/></p> +<p>Please reference the documentation for the image data destination to +check if it limits the maximum size for image data.<wbr/></p> +<p>The following table describes the minimum required output stream +configurations based on the hardware level +(<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a>):</p> +<table> +<thead> +<tr> +<th align="center">Format</th> +<th align="center">Size</th> +<th align="center">Hardware Level</th> +<th align="center">Notes</th> +</tr> +</thead> +<tbody> +<tr> +<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td> +<td align="center"><a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> (*1)</td> +<td align="center">Any</td> +<td align="center"></td> +</tr> +<tr> +<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td> +<td align="center">1920x1080 (1080p)</td> +<td align="center">Any</td> +<td align="center">if 1080p <= activeArraySize</td> +</tr> +<tr> +<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td> +<td align="center">1280x720 (720p)</td> +<td align="center">Any</td> +<td align="center">if 720p <= activeArraySize</td> +</tr> +<tr> +<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td> +<td align="center">640x480 (480p)</td> +<td align="center">Any</td> +<td align="center">if 480p <= activeArraySize</td> +</tr> +<tr> +<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td> +<td align="center">320x240 (240p)</td> +<td align="center">Any</td> +<td align="center">if 240p <= activeArraySize</td> +</tr> +<tr> +<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td> +<td align="center">all output sizes available for JPEG</td> +<td align="center">FULL</td> +<td align="center"></td> +</tr> +<tr> +<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td> +<td align="center">all output sizes available for JPEG,<wbr/> up to the maximum video size</td> +<td align="center">LIMITED</td> +<td align="center"></td> +</tr> +<tr> +<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a></td> +<td align="center">same as YUV_<wbr/>420_<wbr/>888</td> +<td align="center">Any</td> +<td align="center"></td> +</tr> +</tbody> +</table> +<p>Refer to <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a> for additional mandatory +stream configurations on a per-capability basis.<wbr/></p> +<p>*1: For JPEG format,<wbr/> the sizes may be restricted by below conditions:</p> +<ul> +<li>The HAL may choose the aspect ratio of each Jpeg size to be one of well known ones +(e.<wbr/>g.<wbr/> 4:3,<wbr/> 16:9,<wbr/> 3:2 etc.<wbr/>).<wbr/> If the sensor maximum resolution +(defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) has an aspect ratio other than these,<wbr/> +it does not have to be included in the supported JPEG sizes.<wbr/></li> +<li>Some hardware JPEG encoders may have pixel boundary alignment requirements,<wbr/> such as +the dimensions being a multiple of 16.<wbr/> +Therefore,<wbr/> the maximum JPEG size may be smaller than sensor maximum resolution.<wbr/> +However,<wbr/> the largest JPEG size will be as close as possible to the sensor maximum +resolution given above constraints.<wbr/> It is required that after aspect ratio adjustments,<wbr/> +additional size reduction due to other issues must be less than 3% in area.<wbr/> For example,<wbr/> +if the sensor maximum resolution is 3280x2464,<wbr/> if the maximum JPEG size has aspect +ratio 4:3,<wbr/> and the JPEG encoder alignment requirement is 16,<wbr/> the maximum JPEG size will be +3264x2448.<wbr/></li> +</ul> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Do not set this property directly +(it is synthetic and will not be available at the HAL layer); +set the <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> instead.<wbr/></p> +<p>Not all output formats may be supported in a configuration with +an input stream of a particular format.<wbr/> For more details,<wbr/> see +<a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a>.<wbr/></p> +<p>It is recommended (but not mandatory) to also include half/<wbr/>quarter +of sensor maximum resolution for JPEG formats (regardless of hardware +level).<wbr/></p> +<p>(The following is a rewording of the above required table):</p> +<p>The HAL must include sensor maximum resolution (defined by +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>).<wbr/></p> +<p>For FULL capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>),<wbr/> +the HAL must include all YUV_<wbr/>420_<wbr/>888 sizes that have JPEG sizes listed +here as output streams.<wbr/></p> +<p>It must also include each below resolution if it is smaller than or +equal to the sensor maximum resolution (for both YUV_<wbr/>420_<wbr/>888 and JPEG +formats),<wbr/> as output streams:</p> +<ul> +<li>240p (320 x 240)</li> +<li>480p (640 x 480)</li> +<li>720p (1280 x 720)</li> +<li>1080p (1920 x 1080)</li> +</ul> +<p>For LIMITED capability devices +(<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>),<wbr/> +the HAL only has to list up to the maximum video size +supported by the device.<wbr/></p> +<p>Regardless of hardware level,<wbr/> every output resolution available for +YUV_<wbr/>420_<wbr/>888 must also be available for IMPLEMENTATION_<wbr/>DEFINED.<wbr/></p> +<p>This supercedes the following fields,<wbr/> which are now deprecated:</p> +<ul> +<li>availableFormats</li> +<li>available[Processed,<wbr/>Raw,<wbr/>Jpeg]Sizes</li> +</ul> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.scaler.croppingType"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>scaler.<wbr/>cropping<wbr/>Type + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">CENTER_ONLY</span> + <span class="entry_type_enum_notes"><p>The camera device only supports centered crop regions.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FREEFORM</span> + <span class="entry_type_enum_notes"><p>The camera device supports arbitrarily chosen crop regions.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The crop type that this camera device supports.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When passing a non-centered crop region (<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>) to a camera +device that only supports CENTER_<wbr/>ONLY cropping,<wbr/> the camera device will move the +crop region to the center of the sensor active array (<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) +and keep the crop region width and height unchanged.<wbr/> The camera device will return the +final used crop region in metadata result <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>.<wbr/></p> +<p>Camera devices that support FREEFORM cropping will support any crop region that +is inside of the active array.<wbr/> The camera device will apply the same crop region and +return the final used crop region in capture result metadata <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>.<wbr/></p> +<p>LEGACY capability devices will only support CENTER_<wbr/>ONLY cropping.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.scaler.cropRegion"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>scaler.<wbr/>crop<wbr/>Region + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public as rectangle]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The desired region of the sensor to read out for this capture.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates relative to + android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This control can be used to implement digital zoom.<wbr/></p> +<p>The crop region coordinate system is based off +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with <code>(0,<wbr/> 0)</code> being the +top-left corner of the sensor active array.<wbr/></p> +<p>Output streams use this rectangle to produce their output,<wbr/> +cropping to a smaller region if necessary to maintain the +stream's aspect ratio,<wbr/> then scaling the sensor input to +match the output's configured resolution.<wbr/></p> +<p>The crop region is applied after the RAW to other color +space (e.<wbr/>g.<wbr/> YUV) conversion.<wbr/> Since raw streams +(e.<wbr/>g.<wbr/> RAW16) don't have the conversion stage,<wbr/> they are not +croppable.<wbr/> The crop region will be ignored by raw streams.<wbr/></p> +<p>For non-raw streams,<wbr/> any additional per-stream cropping will +be done to maximize the final pixel area of the stream.<wbr/></p> +<p>For example,<wbr/> if the crop region is set to a 4:3 aspect +ratio,<wbr/> then 4:3 streams will use the exact crop +region.<wbr/> 16:9 streams will further crop vertically +(letterbox).<wbr/></p> +<p>Conversely,<wbr/> if the crop region is set to a 16:9,<wbr/> then 4:3 +outputs will crop horizontally (pillarbox),<wbr/> and 16:9 +streams will match exactly.<wbr/> These additional crops will +be centered within the crop region.<wbr/></p> +<p>The width and height of the crop region cannot +be set to be smaller than +<code>floor( activeArraySize.<wbr/>width /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code> and +<code>floor( activeArraySize.<wbr/>height /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code>,<wbr/> respectively.<wbr/></p> +<p>The camera device may adjust the crop region to account +for rounding and other hardware requirements; the final +crop region used will be included in the output capture +result.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The output streams must maintain square pixels at all +times,<wbr/> no matter what the relative aspect ratios of the +crop region and the stream are.<wbr/> Negative values for +corner are allowed for raw output if full pixel array is +larger than active pixel array.<wbr/> Width and height may be +rounded to nearest larger supportable width,<wbr/> especially +for raw output,<wbr/> where only a few fixed scales may be +possible.<wbr/></p> +<p>For a set of output streams configured,<wbr/> if the sensor output is cropped to a smaller +size than active array size,<wbr/> the HAL need follow below cropping rules:</p> +<ul> +<li> +<p>The HAL need handle the cropRegion as if the sensor crop size is the effective active +array size.<wbr/>More specifically,<wbr/> the HAL must transform the request cropRegion from +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> to the sensor cropped pixel area size in this way:</p> +<ol> +<li>Translate the requested cropRegion w.<wbr/>r.<wbr/>t.,<wbr/> the left top corner of the sensor +cropped pixel area by (tx,<wbr/> ty),<wbr/> +where <code>tx = sensorCrop.<wbr/>top * (sensorCrop.<wbr/>height /<wbr/> activeArraySize.<wbr/>height)</code> +and <code>tx = sensorCrop.<wbr/>left * (sensorCrop.<wbr/>width /<wbr/> activeArraySize.<wbr/>width)</code>.<wbr/> The +(sensorCrop.<wbr/>top,<wbr/> sensorCrop.<wbr/>left) is the coordinate based off the +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></li> +<li>Scale the width and height of requested cropRegion with scaling factor of +sensor<wbr/>Crop.<wbr/>width/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>width and sensor<wbr/>Crop.<wbr/>height/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>height +respectively.<wbr/> +Once this new cropRegion is calculated,<wbr/> the HAL must use this region to crop the image +with regard to the sensor crop size (effective active array size).<wbr/> The HAL still need +follow the general cropping rule for this new cropRegion and effective active +array size.<wbr/></li> +</ol> +</li> +<li> +<p>The HAL must report the cropRegion with regard to <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/> +The HAL need convert the new cropRegion generated above w.<wbr/>r.<wbr/>t.,<wbr/> full active array size.<wbr/> +The reported cropRegion may be slightly different with the requested cropRegion since +the HAL may adjust the crop region to account for rounding,<wbr/> conversion error,<wbr/> or other +hardware limitations.<wbr/></p> +</li> +</ul> +<p>HAL2.<wbr/>x uses only (x,<wbr/> y,<wbr/> width)</p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_sensor" class="section">sensor</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.sensor.exposureTime"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>exposure<wbr/>Time + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Duration each pixel is exposed to +light.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p><a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If the sensor can't expose this exact duration,<wbr/> it will shorten the +duration exposed to the nearest possible value (rather than expose longer).<wbr/> +The final exposure time used will be available in the output capture result.<wbr/></p> +<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to +OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.sensor.frameDuration"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>frame<wbr/>Duration + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Duration from start of frame exposure to +start of next frame exposure.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p>See <a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a>,<wbr/> +<a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/> The duration +is capped to <code>max(duration,<wbr/> exposureTime + overhead)</code>.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The maximum frame rate that can be supported by a camera subsystem is +a function of many factors:</p> +<ul> +<li>Requested resolutions of output image streams</li> +<li>Availability of binning /<wbr/> skipping modes on the imager</li> +<li>The bandwidth of the imager interface</li> +<li>The bandwidth of the various ISP processing blocks</li> +</ul> +<p>Since these factors can vary greatly between different ISPs and +sensors,<wbr/> the camera abstraction tries to represent the bandwidth +restrictions with as simple a model as possible.<wbr/></p> +<p>The model presented has the following characteristics:</p> +<ul> +<li>The image sensor is always configured to output the smallest +resolution possible given the application's requested output stream +sizes.<wbr/> The smallest resolution is defined as being at least as large +as the largest requested output stream size; the camera pipeline must +never digitally upsample sensor data when the crop region covers the +whole sensor.<wbr/> In general,<wbr/> this means that if only small output stream +resolutions are configured,<wbr/> the sensor can provide a higher frame +rate.<wbr/></li> +<li>Since any request may use any or all the currently configured +output streams,<wbr/> the sensor and ISP must be configured to support +scaling a single capture to all the streams at the same time.<wbr/> This +means the camera pipeline must be ready to produce the largest +requested output size without any delay.<wbr/> Therefore,<wbr/> the overall +frame rate of a given configured stream set is governed only by the +largest requested stream resolution.<wbr/></li> +<li>Using more than one output stream in a request does not affect the +frame duration.<wbr/></li> +<li>Certain format-streams may need to do additional background processing +before data is consumed/<wbr/>produced by that stream.<wbr/> These processors +can run concurrently to the rest of the camera pipeline,<wbr/> but +cannot process more than 1 capture at a time.<wbr/></li> +</ul> +<p>The necessary information for the application,<wbr/> given the model above,<wbr/> +is provided via the <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> field using +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>.<wbr/> +These are used to determine the maximum frame rate /<wbr/> minimum frame +duration that is possible for a given stream configuration.<wbr/></p> +<p>Specifically,<wbr/> the application can use the following rules to +determine the minimum frame duration it can request from the camera +device:</p> +<ol> +<li>Let the set of currently configured input/<wbr/>output streams +be called <code>S</code>.<wbr/></li> +<li>Find the minimum frame durations for each stream in <code>S</code>,<wbr/> by looking +it up in <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> using <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a> +(with its respective size/<wbr/>format).<wbr/> Let this set of frame durations be +called <code>F</code>.<wbr/></li> +<li>For any given request <code>R</code>,<wbr/> the minimum frame duration allowed +for <code>R</code> is the maximum out of all values in <code>F</code>.<wbr/> Let the streams +used in <code>R</code> be called <code>S_<wbr/>r</code>.<wbr/></li> +</ol> +<p>If none of the streams in <code>S_<wbr/>r</code> have a stall time (listed in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> +using its respective size/<wbr/>format),<wbr/> then the frame duration in <code>F</code> +determines the steady state frame rate that the application will get +if it uses <code>R</code> as a repeating request.<wbr/> Let this special kind of +request be called <code>Rsimple</code>.<wbr/></p> +<p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved +by a single capture of a new request <code>Rstall</code> (which has at least +one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the +same minimum frame duration this will not cause a frame rate loss +if all buffers from the previous <code>Rstall</code> have already been +delivered.<wbr/></p> +<p>For more details about stalling,<wbr/> see +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>.<wbr/></p> +<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to +OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For more details about stalling,<wbr/> see +<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.sensor.sensitivity"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>sensitivity + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The amount of gain applied to sensor data +before processing.<wbr/></p> + </td> + + <td class="entry_units"> + ISO arithmetic units + </td> + + <td class="entry_range"> + <p><a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The sensitivity is the standard ISO sensitivity value,<wbr/> +as defined in ISO 12232:2006.<wbr/></p> +<p>The sensitivity must be within <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a>,<wbr/> and +if if it less than <a href="#static_android.sensor.maxAnalogSensitivity">android.<wbr/>sensor.<wbr/>max<wbr/>Analog<wbr/>Sensitivity</a>,<wbr/> the camera device +is guaranteed to use only analog amplification for applying the gain.<wbr/></p> +<p>If the camera device cannot apply the exact sensitivity +requested,<wbr/> it will reduce the gain to the nearest supported +value.<wbr/> The final sensitivity used will be available in the +output capture result.<wbr/></p> +<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to +OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>ISO 12232:2006 REI method is acceptable.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.sensor.testPatternData"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A pixel <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> that supplies the test pattern +when <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a> is SOLID_<wbr/>COLOR.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Each color channel is treated as an unsigned 32-bit integer.<wbr/> +The camera device then uses the most significant X bits +that correspond to how many bits are in its Bayer raw sensor +output.<wbr/></p> +<p>For example,<wbr/> a sensor with RAW10 Bayer output would use the +10 most significant bits from each color channel.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.sensor.testPatternMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No test pattern mode is used,<wbr/> and the camera +device returns captures from the image sensor.<wbr/></p> +<p>This is the default if the key is not set.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SOLID_COLOR</span> + <span class="entry_type_enum_notes"><p>Each pixel in <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> is replaced by its +respective color channel provided in +<a href="#controls_android.sensor.testPatternData">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data</a>.<wbr/></p> +<p>For example:</p> +<pre><code>android.<wbr/>testPatternData = [0,<wbr/> 0xFFFFFFFF,<wbr/> 0xFFFFFFFF,<wbr/> 0] +</code></pre> +<p>All green pixels are 100% green.<wbr/> All red/<wbr/>blue pixels are black.<wbr/></p> +<pre><code>android.<wbr/>testPatternData = [0xFFFFFFFF,<wbr/> 0,<wbr/> 0xFFFFFFFF,<wbr/> 0] +</code></pre> +<p>All red pixels are 100% red.<wbr/> Only the odd green pixels +are 100% green.<wbr/> All blue pixels are 100% black.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">COLOR_BARS</span> + <span class="entry_type_enum_notes"><p>All pixel data is replaced with an 8-bar color pattern.<wbr/></p> +<p>The vertical bars (left-to-right) are as follows:</p> +<ul> +<li>100% white</li> +<li>yellow</li> +<li>cyan</li> +<li>green</li> +<li>magenta</li> +<li>red</li> +<li>blue</li> +<li>black</li> +</ul> +<p>In general the image would look like the following:</p> +<pre><code>W Y C G M R B K +W Y C G M R B K +W Y C G M R B K +W Y C G M R B K +W Y C G M R B K +.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> +.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> +.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> + +(B = Blue,<wbr/> K = Black) +</code></pre> +<p>Each bar should take up 1/<wbr/>8 of the sensor pixel array width.<wbr/> +When this is not possible,<wbr/> the bar size should be rounded +down to the nearest integer and the pattern can repeat +on the right side.<wbr/></p> +<p>Each bar's height must always take up the full sensor +pixel array height.<wbr/></p> +<p>Each pixel in this test pattern must be set to either +0% intensity or 100% intensity.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">COLOR_BARS_FADE_TO_GRAY</span> + <span class="entry_type_enum_notes"><p>The test pattern is similar to COLOR_<wbr/>BARS,<wbr/> except that +each bar should start at its specified color at the top,<wbr/> +and fade to gray at the bottom.<wbr/></p> +<p>Furthermore each bar is further subdivided into a left and +right half.<wbr/> The left half should have a smooth gradient,<wbr/> +and the right half should have a quantized gradient.<wbr/></p> +<p>In particular,<wbr/> the right half's should consist of blocks of the +same color for 1/<wbr/>16th active sensor pixel array width.<wbr/></p> +<p>The least significant bits in the quantized gradient should +be copied from the most significant bits of the smooth gradient.<wbr/></p> +<p>The height of each bar should always be a multiple of 128.<wbr/> +When this is not the case,<wbr/> the pattern should repeat at the bottom +of the image.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PN9</span> + <span class="entry_type_enum_notes"><p>All pixel data is replaced by a pseudo-random sequence +generated from a PN9 512-bit sequence (typically implemented +in hardware with a linear feedback shift register).<wbr/></p> +<p>The generator should be reset at the beginning of each frame,<wbr/> +and thus each subsequent raw frame with this test pattern should +be exactly the same as the last.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CUSTOM1</span> + <span class="entry_type_enum_value">256</span> + <span class="entry_type_enum_notes"><p>The first custom test pattern.<wbr/> All custom patterns that are +available only on this camera device are at least this numeric +value.<wbr/></p> +<p>All of the custom test patterns will be static +(that is the raw image must not vary from frame to frame).<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>When enabled,<wbr/> the sensor sends a test pattern instead of +doing a real exposure from the camera.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.sensor.availableTestPatternModes">android.<wbr/>sensor.<wbr/>available<wbr/>Test<wbr/>Pattern<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When a test pattern is enabled,<wbr/> all manual sensor controls specified +by android.<wbr/>sensor.<wbr/>* will be ignored.<wbr/> All other controls should +work as normal.<wbr/></p> +<p>For example,<wbr/> if manual flash is enabled,<wbr/> flash firing should still +occur (and that the test pattern remain unmodified,<wbr/> since the flash +would not actually affect it).<wbr/></p> +<p>Defaults to OFF.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>All test patterns are specified in the Bayer domain.<wbr/></p> +<p>The HAL may choose to substitute test patterns from the sensor +with test patterns from on-device memory.<wbr/> In that case,<wbr/> it should be +indistinguishable to the ISP whether the data came from the +sensor interconnect bus (such as CSI2) or memory.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + + + <tr class="entry" id="static_android.sensor.info.activeArraySize"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public as rectangle]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">Four ints defining the active pixel rectangle</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The area of the image sensor which corresponds to active pixels after any geometric +distortion correction has been applied.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates on the image sensor + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is the rectangle representing the size of the active region of the sensor (i.<wbr/>e.<wbr/> +the region that actually receives light from the scene) after any geometric correction +has been applied,<wbr/> and should be treated as the maximum size in pixels of any of the +image output formats aside from the raw formats.<wbr/></p> +<p>This rectangle is defined relative to the full pixel array; (0,<wbr/>0) is the top-left of +the full pixel array,<wbr/> and the size of the full pixel array is given by +<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p> +<p>The coordinate system for most other keys that list pixel coordinates,<wbr/> including +<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>,<wbr/> is defined relative to the active array rectangle given in +this field,<wbr/> with <code>(0,<wbr/> 0)</code> being the top-left of this rectangle.<wbr/></p> +<p>The active array may be smaller than the full pixel array,<wbr/> since the full array may +include black calibration pixels or other inactive regions,<wbr/> and geometric correction +resulting in scaling or cropping may have been applied.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This array contains <code>(xmin,<wbr/> ymin,<wbr/> width,<wbr/> height)</code>.<wbr/> The <code>(xmin,<wbr/> ymin)</code> must be +>= <code>(0,<wbr/>0)</code>.<wbr/> +The <code>(width,<wbr/> height)</code> must be <= <code><a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a></code>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.sensitivityRange"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as rangeInt]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">Range of supported sensitivities</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Range of sensitivities for <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> supported by this +camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Min <= 100,<wbr/> Max >= 800</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The values are the standard ISO sensitivity values,<wbr/> +as defined in ISO 12232:2006.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.colorFilterArrangement"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">RGGB</span> + </li> + <li> + <span class="entry_type_enum_name">GRBG</span> + </li> + <li> + <span class="entry_type_enum_name">GBRG</span> + </li> + <li> + <span class="entry_type_enum_name">BGGR</span> + </li> + <li> + <span class="entry_type_enum_name">RGB</span> + <span class="entry_type_enum_notes"><p>Sensor is not Bayer; output has 3 16-bit +values for each pixel,<wbr/> instead of just 1 16-bit value +per pixel.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The arrangement of color filters on sensor; +represents the colors in the top-left 2x2 section of +the sensor,<wbr/> in reading order.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.exposureTimeRange"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as rangeLong]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">nanoseconds</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The range of image exposure times for <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a> supported +by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p>The minimum exposure time will be less than 100 us.<wbr/> For FULL +capability devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/> +the maximum exposure time will be greater than 100ms.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For FULL capability devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/> +The maximum of the range SHOULD be at least 1 second (1e9),<wbr/> MUST be at least +100ms.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.maxFrameDuration"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum possible frame duration (minimum frame rate) for +<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> that is supported this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p>For FULL capability devices +(<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/> at least 100ms.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Attempting to use frame durations beyond the maximum will result in the frame +duration being clipped to the maximum.<wbr/> See that control for a full definition of frame +durations.<wbr/></p> +<p>Refer to <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a> +for the minimum frame duration values.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For FULL capability devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/> +The maximum of the range SHOULD be at least +1 second (1e9),<wbr/> MUST be at least 100ms (100e6).<wbr/></p> +<p><a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a> must be greater or +equal to the <a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a> max +value (since exposure time overrides frame duration).<wbr/></p> +<p>Available minimum frame durations for JPEG must be no greater +than that of the YUV_<wbr/>420_<wbr/>888/<wbr/>IMPLEMENTATION_<wbr/>DEFINED +minimum frame durations (for that respective size).<wbr/></p> +<p>Since JPEG processing is considered offline and can take longer than +a single uncompressed capture,<wbr/> refer to +<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> +for details about encoding this scenario.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.physicalSize"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>info.<wbr/>physical<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as sizeF]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">width x height</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The physical dimensions of the full pixel +array.<wbr/></p> + </td> + + <td class="entry_units"> + Millimeters + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is the physical size of the sensor pixel +array defined by <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Needed for FOV calculation for old API</p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.pixelArraySize"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [public as size]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Dimensions of the full pixel array,<wbr/> possibly +including black calibration pixels.<wbr/></p> + </td> + + <td class="entry_units"> + Pixels + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The pixel count of the full pixel array of the image sensor,<wbr/> which covers +<a href="#static_android.sensor.info.physicalSize">android.<wbr/>sensor.<wbr/>info.<wbr/>physical<wbr/>Size</a> area.<wbr/> This represents the full pixel dimensions of +the raw buffers produced by this sensor.<wbr/></p> +<p>If a camera device supports raw sensor formats,<wbr/> either this or +<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> is the maximum dimensions for the raw +output formats listed in <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> (this depends on +whether or not the image sensor returns buffers containing pixels that are not +part of the active array region for blacklevel calibration or other purposes).<wbr/></p> +<p>Some parts of the full pixel array may not receive light from the scene,<wbr/> +or be otherwise inactive.<wbr/> The <a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> key +defines the rectangle of active pixels that will be included in processed image +formats.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.whiteLevel"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Maximum raw value output by sensor.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>> 255 (8-bit output)</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This specifies the fully-saturated encoding level for the raw +sample values from the sensor.<wbr/> This is typically caused by the +sensor becoming highly non-linear or clipping.<wbr/> The minimum for +each channel is specified by the offset in the +<a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> key.<wbr/></p> +<p>The white level is typically determined either by sensor bit depth +(8-14 bits is expected),<wbr/> or by the point where the sensor response +becomes too non-linear to be useful.<wbr/> The default value for this is +maximum representable value for a 16-bit raw sample (2^16 - 1).<wbr/></p> +<p>The white level values of captured images may vary for different +capture settings (e.<wbr/>g.,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>).<wbr/> This key +represents a coarse approximation for such case.<wbr/> It is recommended +to use <a href="#dynamic_android.sensor.dynamicWhiteLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>White<wbr/>Level</a> for captures when supported +by the camera device,<wbr/> which provides more accurate white level values.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The full bit depth of the sensor must be available in the raw data,<wbr/> +so the value for linear sensors should not be significantly lower +than maximum raw value supported,<wbr/> i.<wbr/>e.<wbr/> 2^(sensor bits per pixel).<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.timestampSource"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">UNKNOWN</span> + <span class="entry_type_enum_notes"><p>Timestamps from <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> are in nanoseconds and monotonic,<wbr/> +but can not be compared to timestamps from other subsystems +(e.<wbr/>g.<wbr/> accelerometer,<wbr/> gyro etc.<wbr/>),<wbr/> or other instances of the same or different +camera devices in the same system.<wbr/> Timestamps between streams and results for +a single camera instance are comparable,<wbr/> and the timestamps for all buffers +and the result metadata generated by a single capture are identical.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">REALTIME</span> + <span class="entry_type_enum_notes"><p>Timestamps from <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> are in the same timebase as +<a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a>,<wbr/> +and they can be compared to other timestamps using that base.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The time base source for sensor capture start timestamps.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The timestamps provided for captures are always in nanoseconds and monotonic,<wbr/> but +may not based on a time source that can be compared to other system time sources.<wbr/></p> +<p>This characteristic defines the source for the timestamps,<wbr/> and therefore whether they +can be compared against other system time sources/<wbr/>timestamps.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For camera devices implement UNKNOWN,<wbr/> the camera framework expects that the timestamp +source to be SYSTEM_<wbr/>TIME_<wbr/>MONOTONIC.<wbr/> For camera devices implement REALTIME,<wbr/> the camera +framework expects that the timestamp source to be SYSTEM_<wbr/>TIME_<wbr/>BOOTTIME.<wbr/> See +system/<wbr/>core/<wbr/>include/<wbr/>utils/<wbr/>Timers.<wbr/>h for the definition of SYSTEM_<wbr/>TIME_<wbr/>MONOTONIC and +SYSTEM_<wbr/>TIME_<wbr/>BOOTTIME.<wbr/> Note that HAL must follow above expectation; otherwise video +recording might suffer unexpected behavior.<wbr/></p> +<p>Also,<wbr/> camera devices implements REALTIME must pass the ITS sensor fusion test which +tests the alignment between camera timestamps and gyro sensor timestamps.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.lensShadingApplied"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">FALSE</span> + </li> + <li> + <span class="entry_type_enum_name">TRUE</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether the RAW images output from this camera device are subject to +lens shading correction.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If TRUE,<wbr/> all images produced by the camera device in the RAW image formats will +have lens shading correction already applied to it.<wbr/> If FALSE,<wbr/> the images will +not be adjusted for lens shading correction.<wbr/> +See <a href="#static_android.request.maxNumOutputRaw">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Raw</a> for a list of RAW image formats.<wbr/></p> +<p>This key will be <code>null</code> for all devices do not report this information.<wbr/> +Devices with RAW capability will always report this information in this key.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.info.preCorrectionActiveArraySize"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public as rectangle]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">Four ints defining the active pixel rectangle</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The area of the image sensor which corresponds to active pixels prior to the +application of any geometric distortion correction.<wbr/></p> + </td> + + <td class="entry_units"> + Pixel coordinates on the image sensor + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is the rectangle representing the size of the active region of the sensor (i.<wbr/>e.<wbr/> +the region that actually receives light from the scene) before any geometric correction +has been applied,<wbr/> and should be treated as the active region rectangle for any of the +raw formats.<wbr/> All metadata associated with raw processing (e.<wbr/>g.<wbr/> the lens shading +correction map,<wbr/> and radial distortion fields) treats the top,<wbr/> left of this rectangle as +the origin,<wbr/> (0,<wbr/>0).<wbr/></p> +<p>The size of this region determines the maximum field of view and the maximum number of +pixels that an image from this sensor can contain,<wbr/> prior to the application of +geometric distortion correction.<wbr/> The effective maximum pixel dimensions of a +post-distortion-corrected image is given by the <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> +field,<wbr/> and the effective maximum field of view for a post-distortion-corrected image +can be calculated by applying the geometric distortion correction fields to this +rectangle,<wbr/> and cropping to the rectangle given in <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p> +<p>E.<wbr/>g.<wbr/> to calculate position of a pixel,<wbr/> (x,<wbr/>y),<wbr/> in a processed YUV output image with the +dimensions in <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> given the position of a pixel,<wbr/> +(x',<wbr/> y'),<wbr/> in the raw pixel array with dimensions give in +<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>:</p> +<ol> +<li>Choose a pixel (x',<wbr/> y') within the active array region of the raw buffer given in +<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>,<wbr/> otherwise this pixel is considered +to be outside of the FOV,<wbr/> and will not be shown in the processed output image.<wbr/></li> +<li>Apply geometric distortion correction to get the post-distortion pixel coordinate,<wbr/> +(x_<wbr/>i,<wbr/> y_<wbr/>i).<wbr/> When applying geometric correction metadata,<wbr/> note that metadata for raw +buffers is defined relative to the top,<wbr/> left of the +<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> rectangle.<wbr/></li> +<li>If the resulting corrected pixel coordinate is within the region given in +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> then the position of this pixel in the +processed output image buffer is <code>(x_<wbr/>i - activeArray.<wbr/>left,<wbr/> y_<wbr/>i - activeArray.<wbr/>top)</code>,<wbr/> +when the top,<wbr/> left coordinate of that buffer is treated as (0,<wbr/> 0).<wbr/></li> +</ol> +<p>Thus,<wbr/> for pixel x',<wbr/>y' = (25,<wbr/> 25) on a sensor where <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a> +is (100,<wbr/>100),<wbr/> <a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> is (10,<wbr/> 10,<wbr/> 100,<wbr/> 100),<wbr/> +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> is (20,<wbr/> 20,<wbr/> 80,<wbr/> 80),<wbr/> and the geometric distortion +correction doesn't change the pixel coordinate,<wbr/> the resulting pixel selected in +pixel coordinates would be x,<wbr/>y = (25,<wbr/> 25) relative to the top,<wbr/>left of the raw buffer +with dimensions given in <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>,<wbr/> and would be (5,<wbr/> 5) +relative to the top,<wbr/>left of post-processed YUV output buffer with dimensions given in +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p> +<p>The currently supported fields that correct for geometric distortion are:</p> +<ol> +<li><a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a>.<wbr/></li> +</ol> +<p>If all of the geometric distortion fields are no-ops,<wbr/> this rectangle will be the same +as the post-distortion-corrected rectangle given in +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p> +<p>This rectangle is defined relative to the full pixel array; (0,<wbr/>0) is the top-left of +the full pixel array,<wbr/> and the size of the full pixel array is given by +<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p> +<p>The pre-correction active array may be smaller than the full pixel array,<wbr/> since the +full array may include black calibration pixels or other inactive regions.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This array contains <code>(xmin,<wbr/> ymin,<wbr/> width,<wbr/> height)</code>.<wbr/> The <code>(xmin,<wbr/> ymin)</code> must be +>= <code>(0,<wbr/>0)</code>.<wbr/> +The <code>(width,<wbr/> height)</code> must be <= <code><a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a></code>.<wbr/></p> +<p>If omitted by the HAL implementation,<wbr/> the camera framework will assume that this is +the same as the post-correction active array region given in +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + + + <tr class="entry" id="static_android.sensor.referenceIlluminant1"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1 + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">DAYLIGHT</span> + <span class="entry_type_enum_value">1</span> + </li> + <li> + <span class="entry_type_enum_name">FLUORESCENT</span> + <span class="entry_type_enum_value">2</span> + </li> + <li> + <span class="entry_type_enum_name">TUNGSTEN</span> + <span class="entry_type_enum_value">3</span> + <span class="entry_type_enum_notes"><p>Incandescent light</p></span> + </li> + <li> + <span class="entry_type_enum_name">FLASH</span> + <span class="entry_type_enum_value">4</span> + </li> + <li> + <span class="entry_type_enum_name">FINE_WEATHER</span> + <span class="entry_type_enum_value">9</span> + </li> + <li> + <span class="entry_type_enum_name">CLOUDY_WEATHER</span> + <span class="entry_type_enum_value">10</span> + </li> + <li> + <span class="entry_type_enum_name">SHADE</span> + <span class="entry_type_enum_value">11</span> + </li> + <li> + <span class="entry_type_enum_name">DAYLIGHT_FLUORESCENT</span> + <span class="entry_type_enum_value">12</span> + <span class="entry_type_enum_notes"><p>D 5700 - 7100K</p></span> + </li> + <li> + <span class="entry_type_enum_name">DAY_WHITE_FLUORESCENT</span> + <span class="entry_type_enum_value">13</span> + <span class="entry_type_enum_notes"><p>N 4600 - 5400K</p></span> + </li> + <li> + <span class="entry_type_enum_name">COOL_WHITE_FLUORESCENT</span> + <span class="entry_type_enum_value">14</span> + <span class="entry_type_enum_notes"><p>W 3900 - 4500K</p></span> + </li> + <li> + <span class="entry_type_enum_name">WHITE_FLUORESCENT</span> + <span class="entry_type_enum_value">15</span> + <span class="entry_type_enum_notes"><p>WW 3200 - 3700K</p></span> + </li> + <li> + <span class="entry_type_enum_name">STANDARD_A</span> + <span class="entry_type_enum_value">17</span> + </li> + <li> + <span class="entry_type_enum_name">STANDARD_B</span> + <span class="entry_type_enum_value">18</span> + </li> + <li> + <span class="entry_type_enum_name">STANDARD_C</span> + <span class="entry_type_enum_value">19</span> + </li> + <li> + <span class="entry_type_enum_name">D55</span> + <span class="entry_type_enum_value">20</span> + </li> + <li> + <span class="entry_type_enum_name">D65</span> + <span class="entry_type_enum_value">21</span> + </li> + <li> + <span class="entry_type_enum_name">D75</span> + <span class="entry_type_enum_value">22</span> + </li> + <li> + <span class="entry_type_enum_name">D50</span> + <span class="entry_type_enum_value">23</span> + </li> + <li> + <span class="entry_type_enum_name">ISO_STUDIO_TUNGSTEN</span> + <span class="entry_type_enum_value">24</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The standard reference illuminant used as the scene light source when +calculating the <a href="#static_android.sensor.colorTransform1">android.<wbr/>sensor.<wbr/>color<wbr/>Transform1</a>,<wbr/> +<a href="#static_android.sensor.calibrationTransform1">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform1</a>,<wbr/> and +<a href="#static_android.sensor.forwardMatrix1">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix1</a> matrices.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The values in this key correspond to the values defined for the +EXIF LightSource tag.<wbr/> These illuminants are standard light sources +that are often used calibrating camera devices.<wbr/></p> +<p>If this key is present,<wbr/> then <a href="#static_android.sensor.colorTransform1">android.<wbr/>sensor.<wbr/>color<wbr/>Transform1</a>,<wbr/> +<a href="#static_android.sensor.calibrationTransform1">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform1</a>,<wbr/> and +<a href="#static_android.sensor.forwardMatrix1">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix1</a> will also be present.<wbr/></p> +<p>Some devices may choose to provide a second set of calibration +information for improved quality,<wbr/> including +<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a> and its corresponding matrices.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The first reference illuminant (<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>) +and corresponding matrices must be present to support the RAW capability +and DNG output.<wbr/></p> +<p>When producing raw images with a color profile that has only been +calibrated against a single light source,<wbr/> it is valid to omit +<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a> along with the +<a href="#static_android.sensor.colorTransform2">android.<wbr/>sensor.<wbr/>color<wbr/>Transform2</a>,<wbr/> <a href="#static_android.sensor.calibrationTransform2">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2</a>,<wbr/> +and <a href="#static_android.sensor.forwardMatrix2">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2</a> matrices.<wbr/></p> +<p>If only <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a> is included,<wbr/> it should be +chosen so that it is representative of typical scene lighting.<wbr/> In +general,<wbr/> D50 or DAYLIGHT will be chosen for this case.<wbr/></p> +<p>If both <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a> and +<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a> are included,<wbr/> they should be +chosen to represent the typical range of scene lighting conditions.<wbr/> +In general,<wbr/> low color temperature illuminant such as Standard-A will +be chosen for the first reference illuminant and a higher color +temperature illuminant such as D65 will be chosen for the second +reference illuminant.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.referenceIlluminant2"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2 + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The standard reference illuminant used as the scene light source when +calculating the <a href="#static_android.sensor.colorTransform2">android.<wbr/>sensor.<wbr/>color<wbr/>Transform2</a>,<wbr/> +<a href="#static_android.sensor.calibrationTransform2">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2</a>,<wbr/> and +<a href="#static_android.sensor.forwardMatrix2">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2</a> matrices.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>See <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a> for more details.<wbr/></p> +<p>If this key is present,<wbr/> then <a href="#static_android.sensor.colorTransform2">android.<wbr/>sensor.<wbr/>color<wbr/>Transform2</a>,<wbr/> +<a href="#static_android.sensor.calibrationTransform2">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2</a>,<wbr/> and +<a href="#static_android.sensor.forwardMatrix2">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2</a> will also be present.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.calibrationTransform1"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform1 + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x 3 + </span> + <span class="entry_type_visibility"> [public as colorSpaceTransform]</span> + + + + + <div class="entry_type_notes">3x3 matrix in row-major-order</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A per-device calibration transform matrix that maps from the +reference sensor colorspace to the actual device sensor colorspace.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This matrix is used to correct for per-device variations in the +sensor colorspace,<wbr/> and is used for processing raw buffer data.<wbr/></p> +<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and +contains a per-device calibration transform that maps colors +from reference sensor color space (i.<wbr/>e.<wbr/> the "golden module" +colorspace) into this camera device's native sensor color +space under the first reference illuminant +(<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.calibrationTransform2"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2 + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x 3 + </span> + <span class="entry_type_visibility"> [public as colorSpaceTransform]</span> + + + + + <div class="entry_type_notes">3x3 matrix in row-major-order</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A per-device calibration transform matrix that maps from the +reference sensor colorspace to the actual device sensor colorspace +(this is the colorspace of the raw buffer data).<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This matrix is used to correct for per-device variations in the +sensor colorspace,<wbr/> and is used for processing raw buffer data.<wbr/></p> +<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and +contains a per-device calibration transform that maps colors +from reference sensor color space (i.<wbr/>e.<wbr/> the "golden module" +colorspace) into this camera device's native sensor color +space under the second reference illuminant +(<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a>).<wbr/></p> +<p>This matrix will only be present if the second reference +illuminant is present.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.colorTransform1"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>color<wbr/>Transform1 + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x 3 + </span> + <span class="entry_type_visibility"> [public as colorSpaceTransform]</span> + + + + + <div class="entry_type_notes">3x3 matrix in row-major-order</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A matrix that transforms color values from CIE XYZ color space to +reference sensor color space.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This matrix is used to convert from the standard CIE XYZ color +space to the reference sensor colorspace,<wbr/> and is used when processing +raw buffer data.<wbr/></p> +<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and +contains a color transform matrix that maps colors from the CIE +XYZ color space to the reference sensor color space (i.<wbr/>e.<wbr/> the +"golden module" colorspace) under the first reference illuminant +(<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>).<wbr/></p> +<p>The white points chosen in both the reference sensor color space +and the CIE XYZ colorspace when calculating this transform will +match the standard white point for the first reference illuminant +(i.<wbr/>e.<wbr/> no chromatic adaptation will be applied by this transform).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.colorTransform2"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>color<wbr/>Transform2 + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x 3 + </span> + <span class="entry_type_visibility"> [public as colorSpaceTransform]</span> + + + + + <div class="entry_type_notes">3x3 matrix in row-major-order</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A matrix that transforms color values from CIE XYZ color space to +reference sensor color space.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This matrix is used to convert from the standard CIE XYZ color +space to the reference sensor colorspace,<wbr/> and is used when processing +raw buffer data.<wbr/></p> +<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and +contains a color transform matrix that maps colors from the CIE +XYZ color space to the reference sensor color space (i.<wbr/>e.<wbr/> the +"golden module" colorspace) under the second reference illuminant +(<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a>).<wbr/></p> +<p>The white points chosen in both the reference sensor color space +and the CIE XYZ colorspace when calculating this transform will +match the standard white point for the second reference illuminant +(i.<wbr/>e.<wbr/> no chromatic adaptation will be applied by this transform).<wbr/></p> +<p>This matrix will only be present if the second reference +illuminant is present.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.forwardMatrix1"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix1 + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x 3 + </span> + <span class="entry_type_visibility"> [public as colorSpaceTransform]</span> + + + + + <div class="entry_type_notes">3x3 matrix in row-major-order</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A matrix that transforms white balanced camera colors from the reference +sensor colorspace to the CIE XYZ colorspace with a D50 whitepoint.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This matrix is used to convert to the standard CIE XYZ colorspace,<wbr/> and +is used when processing raw buffer data.<wbr/></p> +<p>This matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and contains +a color transform matrix that maps white balanced colors from the +reference sensor color space to the CIE XYZ color space with a D50 white +point.<wbr/></p> +<p>Under the first reference illuminant (<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>) +this matrix is chosen so that the standard white point for this reference +illuminant in the reference sensor colorspace is mapped to D50 in the +CIE XYZ colorspace.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.forwardMatrix2"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2 + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x 3 + </span> + <span class="entry_type_visibility"> [public as colorSpaceTransform]</span> + + + + + <div class="entry_type_notes">3x3 matrix in row-major-order</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A matrix that transforms white balanced camera colors from the reference +sensor colorspace to the CIE XYZ colorspace with a D50 whitepoint.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This matrix is used to convert to the standard CIE XYZ colorspace,<wbr/> and +is used when processing raw buffer data.<wbr/></p> +<p>This matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and contains +a color transform matrix that maps white balanced colors from the +reference sensor color space to the CIE XYZ color space with a D50 white +point.<wbr/></p> +<p>Under the second reference illuminant (<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a>) +this matrix is chosen so that the standard white point for this reference +illuminant in the reference sensor colorspace is mapped to D50 in the +CIE XYZ colorspace.<wbr/></p> +<p>This matrix will only be present if the second reference +illuminant is present.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.baseGainFactor"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>sensor.<wbr/>base<wbr/>Gain<wbr/>Factor + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Gain factor from electrons to raw units when +ISO=100</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.blackLevelPattern"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public as blackLevelPattern]</span> + + + + + <div class="entry_type_notes">2x2 raw count block</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A fixed black level offset for each of the color filter arrangement +(CFA) mosaic channels.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 0 for each.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This key specifies the zero light value for each of the CFA mosaic +channels in the camera sensor.<wbr/> The maximal value output by the +sensor is represented by the value in <a href="#static_android.sensor.info.whiteLevel">android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level</a>.<wbr/></p> +<p>The values are given in the same order as channels listed for the CFA +layout key (see <a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>),<wbr/> i.<wbr/>e.<wbr/> the +nth value given corresponds to the black level offset for the nth +color channel listed in the CFA.<wbr/></p> +<p>The black level values of captured images may vary for different +capture settings (e.<wbr/>g.,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>).<wbr/> This key +represents a coarse approximation for such case.<wbr/> It is recommended to +use <a href="#dynamic_android.sensor.dynamicBlackLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>Black<wbr/>Level</a> or use pixels from +<a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> directly for captures when +supported by the camera device,<wbr/> which provides more accurate black +level values.<wbr/> For raw capture in particular,<wbr/> it is recommended to use +pixels from <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> to calculate black +level values for each frame.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The values are given in row-column scan order,<wbr/> with the first value +corresponding to the element of the CFA in row=0,<wbr/> column=0.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.maxAnalogSensitivity"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>max<wbr/>Analog<wbr/>Sensitivity + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Maximum sensitivity that is implemented +purely through analog gain.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_FULL">FULL</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> values less than or +equal to this,<wbr/> all applied gain must be analog.<wbr/> For +values above this,<wbr/> the gain applied can be a mix of analog and +digital.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.orientation"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>orientation + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Clockwise angle through which the output image needs to be rotated to be +upright on the device screen in its native orientation.<wbr/></p> + </td> + + <td class="entry_units"> + Degrees of clockwise rotation; always a multiple of + 90 + </td> + + <td class="entry_range"> + <p>0,<wbr/> 90,<wbr/> 180,<wbr/> 270</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Also defines the direction of rolling shutter readout,<wbr/> which is from top to bottom in +the sensor's coordinate system.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.profileHueSatMapDimensions"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map<wbr/>Dimensions + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 + </span> + <span class="entry_type_visibility"> [system]</span> + + + + + <div class="entry_type_notes">Number of samples for hue,<wbr/> saturation,<wbr/> and value</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The number of input samples for each dimension of +<a href="#dynamic_android.sensor.profileHueSatMap">android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map</a>.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Hue >= 1,<wbr/> +Saturation >= 2,<wbr/> +Value >= 1</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The number of input samples for the hue,<wbr/> saturation,<wbr/> and value +dimension of <a href="#dynamic_android.sensor.profileHueSatMap">android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map</a>.<wbr/> The order of the +dimensions given is hue,<wbr/> saturation,<wbr/> value; where hue is the 0th +element.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.availableTestPatternModes"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>available<wbr/>Test<wbr/>Pattern<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of sensor test pattern modes for <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a> +supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Defaults to OFF,<wbr/> and always includes OFF if defined.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>All custom modes must be >= CUSTOM1.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.opticalBlackRegions"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 x num_regions + </span> + <span class="entry_type_visibility"> [public as rectangle]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of disjoint rectangles indicating the sensor +optically shielded black pixel regions.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>In most camera sensors,<wbr/> the active array is surrounded by some +optically shielded pixel areas.<wbr/> By blocking light,<wbr/> these pixels +provides a reliable black reference for black level compensation +in active array region.<wbr/></p> +<p>This key provides a list of disjoint rectangles specifying the +regions of optically shielded (with metal shield) black pixel +regions if the camera device is capable of reading out these black +pixels in the output raw images.<wbr/> In comparison to the fixed black +level values reported by <a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a>,<wbr/> this key +may provide a more accurate way for the application to calculate +black level of each captured raw images.<wbr/></p> +<p>When this key is reported,<wbr/> the <a href="#dynamic_android.sensor.dynamicBlackLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>Black<wbr/>Level</a> and +<a href="#dynamic_android.sensor.dynamicWhiteLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>White<wbr/>Level</a> will also be reported.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This array contains (xmin,<wbr/> ymin,<wbr/> width,<wbr/> height).<wbr/> The (xmin,<wbr/> ymin) +must be >= (0,<wbr/>0) and <= +<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/> The (width,<wbr/> height) must be +<= <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/> Each region must be +outside the region reported by +<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>.<wbr/></p> +<p>The HAL must report minimal number of disjoint regions for the +optically shielded back pixel regions.<wbr/> For example,<wbr/> if a region can +be covered by one rectangle,<wbr/> the HAL must not split this region into +multiple rectangles.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.sensor.opaqueRawSize"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>opaque<wbr/>Raw<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 3 + </span> + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Size in bytes for all the listed opaque RAW buffer sizes</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Must be large enough to fit the opaque RAW of corresponding size produced by +the camera</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This configurations are listed as <code>(width,<wbr/> height,<wbr/> size_<wbr/>in_<wbr/>bytes)</code> tuples.<wbr/> +This is used for sizing the gralloc buffers for opaque RAW buffers.<wbr/> +All RAW_<wbr/>OPAQUE output stream configuration listed in +<a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> will have a corresponding tuple in +this key.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This key is added in HAL3.<wbr/>4.<wbr/> +For HAL3.<wbr/>4 or above: devices advertising RAW_<wbr/>OPAQUE format output must list this key.<wbr/> +For HAL3.<wbr/>3 or earlier devices: if RAW_<wbr/>OPAQUE ouput is advertised,<wbr/> camera framework +will derive this key by assuming each pixel takes two bytes and no padding bytes +between rows.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.sensor.exposureTime"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>exposure<wbr/>Time + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Duration each pixel is exposed to +light.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p><a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If the sensor can't expose this exact duration,<wbr/> it will shorten the +duration exposed to the nearest possible value (rather than expose longer).<wbr/> +The final exposure time used will be available in the output capture result.<wbr/></p> +<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to +OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.frameDuration"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>frame<wbr/>Duration + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Duration from start of frame exposure to +start of next frame exposure.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p>See <a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a>,<wbr/> +<a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/> The duration +is capped to <code>max(duration,<wbr/> exposureTime + overhead)</code>.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The maximum frame rate that can be supported by a camera subsystem is +a function of many factors:</p> +<ul> +<li>Requested resolutions of output image streams</li> +<li>Availability of binning /<wbr/> skipping modes on the imager</li> +<li>The bandwidth of the imager interface</li> +<li>The bandwidth of the various ISP processing blocks</li> +</ul> +<p>Since these factors can vary greatly between different ISPs and +sensors,<wbr/> the camera abstraction tries to represent the bandwidth +restrictions with as simple a model as possible.<wbr/></p> +<p>The model presented has the following characteristics:</p> +<ul> +<li>The image sensor is always configured to output the smallest +resolution possible given the application's requested output stream +sizes.<wbr/> The smallest resolution is defined as being at least as large +as the largest requested output stream size; the camera pipeline must +never digitally upsample sensor data when the crop region covers the +whole sensor.<wbr/> In general,<wbr/> this means that if only small output stream +resolutions are configured,<wbr/> the sensor can provide a higher frame +rate.<wbr/></li> +<li>Since any request may use any or all the currently configured +output streams,<wbr/> the sensor and ISP must be configured to support +scaling a single capture to all the streams at the same time.<wbr/> This +means the camera pipeline must be ready to produce the largest +requested output size without any delay.<wbr/> Therefore,<wbr/> the overall +frame rate of a given configured stream set is governed only by the +largest requested stream resolution.<wbr/></li> +<li>Using more than one output stream in a request does not affect the +frame duration.<wbr/></li> +<li>Certain format-streams may need to do additional background processing +before data is consumed/<wbr/>produced by that stream.<wbr/> These processors +can run concurrently to the rest of the camera pipeline,<wbr/> but +cannot process more than 1 capture at a time.<wbr/></li> +</ul> +<p>The necessary information for the application,<wbr/> given the model above,<wbr/> +is provided via the <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> field using +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>.<wbr/> +These are used to determine the maximum frame rate /<wbr/> minimum frame +duration that is possible for a given stream configuration.<wbr/></p> +<p>Specifically,<wbr/> the application can use the following rules to +determine the minimum frame duration it can request from the camera +device:</p> +<ol> +<li>Let the set of currently configured input/<wbr/>output streams +be called <code>S</code>.<wbr/></li> +<li>Find the minimum frame durations for each stream in <code>S</code>,<wbr/> by looking +it up in <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> using <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a> +(with its respective size/<wbr/>format).<wbr/> Let this set of frame durations be +called <code>F</code>.<wbr/></li> +<li>For any given request <code>R</code>,<wbr/> the minimum frame duration allowed +for <code>R</code> is the maximum out of all values in <code>F</code>.<wbr/> Let the streams +used in <code>R</code> be called <code>S_<wbr/>r</code>.<wbr/></li> +</ol> +<p>If none of the streams in <code>S_<wbr/>r</code> have a stall time (listed in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> +using its respective size/<wbr/>format),<wbr/> then the frame duration in <code>F</code> +determines the steady state frame rate that the application will get +if it uses <code>R</code> as a repeating request.<wbr/> Let this special kind of +request be called <code>Rsimple</code>.<wbr/></p> +<p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved +by a single capture of a new request <code>Rstall</code> (which has at least +one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the +same minimum frame duration this will not cause a frame rate loss +if all buffers from the previous <code>Rstall</code> have already been +delivered.<wbr/></p> +<p>For more details about stalling,<wbr/> see +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>.<wbr/></p> +<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to +OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For more details about stalling,<wbr/> see +<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.sensitivity"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>sensitivity + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The amount of gain applied to sensor data +before processing.<wbr/></p> + </td> + + <td class="entry_units"> + ISO arithmetic units + </td> + + <td class="entry_range"> + <p><a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The sensitivity is the standard ISO sensitivity value,<wbr/> +as defined in ISO 12232:2006.<wbr/></p> +<p>The sensitivity must be within <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a>,<wbr/> and +if if it less than <a href="#static_android.sensor.maxAnalogSensitivity">android.<wbr/>sensor.<wbr/>max<wbr/>Analog<wbr/>Sensitivity</a>,<wbr/> the camera device +is guaranteed to use only analog amplification for applying the gain.<wbr/></p> +<p>If the camera device cannot apply the exact sensitivity +requested,<wbr/> it will reduce the gain to the nearest supported +value.<wbr/> The final sensitivity used will be available in the +output capture result.<wbr/></p> +<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to +OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>ISO 12232:2006 REI method is acceptable.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.timestamp"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>timestamp + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Time at start of exposure of first +row of the image sensor active array,<wbr/> in nanoseconds.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p>> 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The timestamps are also included in all image +buffers produced for the same capture,<wbr/> and will be identical +on all the outputs.<wbr/></p> +<p>When <a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> UNKNOWN,<wbr/> +the timestamps measure time since an unspecified starting point,<wbr/> +and are monotonically increasing.<wbr/> They can be compared with the +timestamps for other captures from the same camera device,<wbr/> but are +not guaranteed to be comparable to any other time source.<wbr/></p> +<p>When <a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> REALTIME,<wbr/> the +timestamps measure time in the same timebase as <a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a>,<wbr/> and they can +be compared to other timestamps from other subsystems that +are using that base.<wbr/></p> +<p>For reprocessing,<wbr/> the timestamp will match the start of exposure of +the input image,<wbr/> i.<wbr/>e.<wbr/> <a href="https://developer.android.com/reference/CaptureResult.html#SENSOR_TIMESTAMP">the +timestamp</a> in the TotalCaptureResult that was used to create the +reprocess capture request.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>All timestamps must be in reference to the kernel's +CLOCK_<wbr/>BOOTTIME monotonic clock,<wbr/> which properly accounts for +time spent asleep.<wbr/> This allows for synchronization with +sensors that continue to operate while the system is +otherwise asleep.<wbr/></p> +<p>If <a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> REALTIME,<wbr/> +The timestamp must be synchronized with the timestamps from other +sensor subsystems that are using the same timebase.<wbr/></p> +<p>For reprocessing,<wbr/> the input image's start of exposure can be looked up +with <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> from the metadata included in the +capture request.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.temperature"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>sensor.<wbr/>temperature + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The temperature of the sensor,<wbr/> sampled at the time +exposure began for this frame.<wbr/></p> +<p>The thermal diode being queried should be inside the sensor PCB,<wbr/> or +somewhere close to it.<wbr/></p> + </td> + + <td class="entry_units"> + Celsius + </td> + + <td class="entry_range"> + <p>Optional.<wbr/> This value is missing if no temperature is available.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.neutralColorPoint"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>neutral<wbr/>Color<wbr/>Point + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The estimated camera neutral color in the native sensor colorspace at +the time of capture.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This value gives the neutral color point encoded as an RGB value in the +native sensor color space.<wbr/> The neutral color point indicates the +currently estimated white point of the scene illumination.<wbr/> It can be +used to interpolate between the provided color transforms when +processing raw sensor data.<wbr/></p> +<p>The order of the values is R,<wbr/> G,<wbr/> B; where R is in the lowest index.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.noiseProfile"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>noise<wbr/>Profile + </td> + <td class="entry_type"> + <span class="entry_type_name">double</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 x CFA Channels + </span> + <span class="entry_type_visibility"> [public as pairDoubleDouble]</span> + + + + + <div class="entry_type_notes">Pairs of noise model coefficients</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Noise model coefficients for each CFA mosaic channel.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This key contains two noise model coefficients for each CFA channel +corresponding to the sensor amplification (S) and sensor readout +noise (O).<wbr/> These are given as pairs of coefficients for each channel +in the same order as channels listed for the CFA layout key +(see <a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>).<wbr/> This is +represented as an array of Pair<Double,<wbr/> Double>,<wbr/> where +the first member of the Pair at index n is the S coefficient and the +second member is the O coefficient for the nth color channel in the CFA.<wbr/></p> +<p>These coefficients are used in a two parameter noise model to describe +the amount of noise present in the image for each CFA channel.<wbr/> The +noise model used here is:</p> +<p>N(x) = sqrt(Sx + O)</p> +<p>Where x represents the recorded signal of a CFA channel normalized to +the range [0,<wbr/> 1],<wbr/> and S and O are the noise model coeffiecients for +that channel.<wbr/></p> +<p>A more detailed description of the noise model can be found in the +Adobe DNG specification for the NoiseProfile tag.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For a CFA layout of RGGB,<wbr/> the list of coefficients would be given as +an array of doubles S0,<wbr/>O0,<wbr/>S1,<wbr/>O1,...,<wbr/> where S0 and O0 are the coefficients +for the red channel,<wbr/> S1 and O1 are the coefficients for the first green +channel,<wbr/> etc.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.profileHueSatMap"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + hue_samples x saturation_samples x value_samples x 3 + </span> + <span class="entry_type_visibility"> [system]</span> + + + + + <div class="entry_type_notes">Mapping for hue,<wbr/> saturation,<wbr/> and value</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A mapping containing a hue shift,<wbr/> saturation scale,<wbr/> and value scale +for each pixel.<wbr/></p> + </td> + + <td class="entry_units"> + + The hue shift is given in degrees; saturation and value scale factors are + unitless and are between 0 and 1 inclusive + + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>hue_<wbr/>samples,<wbr/> saturation_<wbr/>samples,<wbr/> and value_<wbr/>samples are given in +<a href="#static_android.sensor.profileHueSatMapDimensions">android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map<wbr/>Dimensions</a>.<wbr/></p> +<p>Each entry of this map contains three floats corresponding to the +hue shift,<wbr/> saturation scale,<wbr/> and value scale,<wbr/> respectively; where the +hue shift has the lowest index.<wbr/> The map entries are stored in the key +in nested loop order,<wbr/> with the value divisions in the outer loop,<wbr/> the +hue divisions in the middle loop,<wbr/> and the saturation divisions in the +inner loop.<wbr/> All zero input saturation entries are required to have a +value scale factor of 1.<wbr/>0.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.profileToneCurve"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>sensor.<wbr/>profile<wbr/>Tone<wbr/>Curve + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + samples x 2 + </span> + <span class="entry_type_visibility"> [system]</span> + + + + + <div class="entry_type_notes">Samples defining a spline for a tone-mapping curve</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A list of x,<wbr/>y samples defining a tone-mapping curve for gamma adjustment.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Each sample has an input range of <code>[0,<wbr/> 1]</code> and an output range of +<code>[0,<wbr/> 1]</code>.<wbr/> The first sample is required to be <code>(0,<wbr/> 0)</code>,<wbr/> and the last +sample is required to be <code>(1,<wbr/> 1)</code>.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This key contains a default tone curve that can be applied while +processing the image as a starting point for user adjustments.<wbr/> +The curve is specified as a list of value pairs in linear gamma.<wbr/> +The curve is interpolated using a cubic spline.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.greenSplit"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>green<wbr/>Split + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The worst-case divergence between Bayer green channels.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This value is an estimate of the worst case split between the +Bayer green channels in the red and blue rows in the sensor color +filter array.<wbr/></p> +<p>The green split is calculated as follows:</p> +<ol> +<li>A 5x5 pixel (or larger) window W within the active sensor array is +chosen.<wbr/> The term 'pixel' here is taken to mean a group of 4 Bayer +mosaic channels (R,<wbr/> Gr,<wbr/> Gb,<wbr/> B).<wbr/> The location and size of the window +chosen is implementation defined,<wbr/> and should be chosen to provide a +green split estimate that is both representative of the entire image +for this camera sensor,<wbr/> and can be calculated quickly.<wbr/></li> +<li>The arithmetic mean of the green channels from the red +rows (mean_<wbr/>Gr) within W is computed.<wbr/></li> +<li>The arithmetic mean of the green channels from the blue +rows (mean_<wbr/>Gb) within W is computed.<wbr/></li> +<li>The maximum ratio R of the two means is computed as follows: +<code>R = max((mean_<wbr/>Gr + 1)/<wbr/>(mean_<wbr/>Gb + 1),<wbr/> (mean_<wbr/>Gb + 1)/<wbr/>(mean_<wbr/>Gr + 1))</code></li> +</ol> +<p>The ratio R is the green split divergence reported for this property,<wbr/> +which represents how much the green channels differ in the mosaic +pattern.<wbr/> This value is typically used to determine the treatment of +the green mosaic channels when demosaicing.<wbr/></p> +<p>The green split value can be roughly interpreted as follows:</p> +<ul> +<li>R < 1.<wbr/>03 is a negligible split (<3% divergence).<wbr/></li> +<li>1.<wbr/>20 <= R >= 1.<wbr/>03 will require some software +correction to avoid demosaic errors (3-20% divergence).<wbr/></li> +<li>R > 1.<wbr/>20 will require strong software correction to produce +a usuable image (>20% divergence).<wbr/></li> +</ul> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The green split given may be a static value based on prior +characterization of the camera sensor using the green split +calculation method given here over a large,<wbr/> representative,<wbr/> sample +set of images.<wbr/> Other methods of calculation that produce equivalent +results,<wbr/> and can be interpreted in the same manner,<wbr/> may be used.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.testPatternData"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A pixel <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> that supplies the test pattern +when <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a> is SOLID_<wbr/>COLOR.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Each color channel is treated as an unsigned 32-bit integer.<wbr/> +The camera device then uses the most significant X bits +that correspond to how many bits are in its Bayer raw sensor +output.<wbr/></p> +<p>For example,<wbr/> a sensor with RAW10 Bayer output would use the +10 most significant bits from each color channel.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.testPatternMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No test pattern mode is used,<wbr/> and the camera +device returns captures from the image sensor.<wbr/></p> +<p>This is the default if the key is not set.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SOLID_COLOR</span> + <span class="entry_type_enum_notes"><p>Each pixel in <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> is replaced by its +respective color channel provided in +<a href="#controls_android.sensor.testPatternData">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data</a>.<wbr/></p> +<p>For example:</p> +<pre><code>android.<wbr/>testPatternData = [0,<wbr/> 0xFFFFFFFF,<wbr/> 0xFFFFFFFF,<wbr/> 0] +</code></pre> +<p>All green pixels are 100% green.<wbr/> All red/<wbr/>blue pixels are black.<wbr/></p> +<pre><code>android.<wbr/>testPatternData = [0xFFFFFFFF,<wbr/> 0,<wbr/> 0xFFFFFFFF,<wbr/> 0] +</code></pre> +<p>All red pixels are 100% red.<wbr/> Only the odd green pixels +are 100% green.<wbr/> All blue pixels are 100% black.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">COLOR_BARS</span> + <span class="entry_type_enum_notes"><p>All pixel data is replaced with an 8-bar color pattern.<wbr/></p> +<p>The vertical bars (left-to-right) are as follows:</p> +<ul> +<li>100% white</li> +<li>yellow</li> +<li>cyan</li> +<li>green</li> +<li>magenta</li> +<li>red</li> +<li>blue</li> +<li>black</li> +</ul> +<p>In general the image would look like the following:</p> +<pre><code>W Y C G M R B K +W Y C G M R B K +W Y C G M R B K +W Y C G M R B K +W Y C G M R B K +.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> +.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> +.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> + +(B = Blue,<wbr/> K = Black) +</code></pre> +<p>Each bar should take up 1/<wbr/>8 of the sensor pixel array width.<wbr/> +When this is not possible,<wbr/> the bar size should be rounded +down to the nearest integer and the pattern can repeat +on the right side.<wbr/></p> +<p>Each bar's height must always take up the full sensor +pixel array height.<wbr/></p> +<p>Each pixel in this test pattern must be set to either +0% intensity or 100% intensity.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">COLOR_BARS_FADE_TO_GRAY</span> + <span class="entry_type_enum_notes"><p>The test pattern is similar to COLOR_<wbr/>BARS,<wbr/> except that +each bar should start at its specified color at the top,<wbr/> +and fade to gray at the bottom.<wbr/></p> +<p>Furthermore each bar is further subdivided into a left and +right half.<wbr/> The left half should have a smooth gradient,<wbr/> +and the right half should have a quantized gradient.<wbr/></p> +<p>In particular,<wbr/> the right half's should consist of blocks of the +same color for 1/<wbr/>16th active sensor pixel array width.<wbr/></p> +<p>The least significant bits in the quantized gradient should +be copied from the most significant bits of the smooth gradient.<wbr/></p> +<p>The height of each bar should always be a multiple of 128.<wbr/> +When this is not the case,<wbr/> the pattern should repeat at the bottom +of the image.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PN9</span> + <span class="entry_type_enum_notes"><p>All pixel data is replaced by a pseudo-random sequence +generated from a PN9 512-bit sequence (typically implemented +in hardware with a linear feedback shift register).<wbr/></p> +<p>The generator should be reset at the beginning of each frame,<wbr/> +and thus each subsequent raw frame with this test pattern should +be exactly the same as the last.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">CUSTOM1</span> + <span class="entry_type_enum_value">256</span> + <span class="entry_type_enum_notes"><p>The first custom test pattern.<wbr/> All custom patterns that are +available only on this camera device are at least this numeric +value.<wbr/></p> +<p>All of the custom test patterns will be static +(that is the raw image must not vary from frame to frame).<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>When enabled,<wbr/> the sensor sends a test pattern instead of +doing a real exposure from the camera.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.sensor.availableTestPatternModes">android.<wbr/>sensor.<wbr/>available<wbr/>Test<wbr/>Pattern<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When a test pattern is enabled,<wbr/> all manual sensor controls specified +by android.<wbr/>sensor.<wbr/>* will be ignored.<wbr/> All other controls should +work as normal.<wbr/></p> +<p>For example,<wbr/> if manual flash is enabled,<wbr/> flash firing should still +occur (and that the test pattern remain unmodified,<wbr/> since the flash +would not actually affect it).<wbr/></p> +<p>Defaults to OFF.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>All test patterns are specified in the Bayer domain.<wbr/></p> +<p>The HAL may choose to substitute test patterns from the sensor +with test patterns from on-device memory.<wbr/> In that case,<wbr/> it should be +indistinguishable to the ISP whether the data came from the +sensor interconnect bus (such as CSI2) or memory.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.rollingShutterSkew"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>rolling<wbr/>Shutter<wbr/>Skew + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Duration between the start of first row exposure +and the start of last row exposure.<wbr/></p> + </td> + + <td class="entry_units"> + Nanoseconds + </td> + + <td class="entry_range"> + <p>>= 0 and < +<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is the exposure time skew between the first and last +row exposure start times.<wbr/> The first row and the last row are +the first and last rows inside of the +<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p> +<p>For typical camera sensors that use rolling shutters,<wbr/> this is also equivalent +to the frame readout time.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The HAL must report <code>0</code> if the sensor is using global shutter,<wbr/> where all pixels begin +exposure at the same time.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.dynamicBlackLevel"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>dynamic<wbr/>Black<wbr/>Level + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [public]</span> + + + + + <div class="entry_type_notes">2x2 raw count block</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A per-frame dynamic black level offset for each of the color filter +arrangement (CFA) mosaic channels.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 0 for each.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Camera sensor black levels may vary dramatically for different +capture settings (e.<wbr/>g.<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>).<wbr/> The fixed black +level reported by <a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> may be too +inaccurate to represent the actual value on a per-frame basis.<wbr/> The +camera device internal pipeline relies on reliable black level values +to process the raw images appropriately.<wbr/> To get the best image +quality,<wbr/> the camera device may choose to estimate the per frame black +level values either based on optically shielded black regions +(<a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a>) or its internal model.<wbr/></p> +<p>This key reports the camera device estimated per-frame zero light +value for each of the CFA mosaic channels in the camera sensor.<wbr/> The +<a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> may only represent a coarse +approximation of the actual black level values.<wbr/> This value is the +black level used in camera device internal image processing pipeline +and generally more accurate than the fixed black level values.<wbr/> +However,<wbr/> since they are estimated values by the camera device,<wbr/> they +may not be as accurate as the black level values calculated from the +optical black pixels reported by <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a>.<wbr/></p> +<p>The values are given in the same order as channels listed for the CFA +layout key (see <a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>),<wbr/> i.<wbr/>e.<wbr/> the +nth value given corresponds to the black level offset for the nth +color channel listed in the CFA.<wbr/></p> +<p>This key will be available if <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> is +available or the camera device advertises this key via +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureResultKeys">CameraCharacteristics#getAvailableCaptureResultKeys</a>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The values are given in row-column scan order,<wbr/> with the first value +corresponding to the element of the CFA in row=0,<wbr/> column=0.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.sensor.dynamicWhiteLevel"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sensor.<wbr/>dynamic<wbr/>White<wbr/>Level + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Maximum raw value output by sensor for this frame.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Since the <a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> may change for different +capture settings (e.<wbr/>g.,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>),<wbr/> the white +level will change accordingly.<wbr/> This key is similar to +<a href="#static_android.sensor.info.whiteLevel">android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level</a>,<wbr/> but specifies the camera device +estimated white level for each frame.<wbr/></p> +<p>This key will be available if <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> is +available or the camera device advertises this key via +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureRequestKeys">CameraCharacteristics#getAvailableCaptureRequestKeys</a>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The full bit depth of the sensor must be available in the raw data,<wbr/> +so the value for linear sensors should not be significantly lower +than maximum raw value supported,<wbr/> i.<wbr/>e.<wbr/> 2^(sensor bits per pixel).<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_shading" class="section">shading</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.shading.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>shading.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No lens shading correction is applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Apply lens shading corrections,<wbr/> without slowing +frame rate relative to sensor raw output</p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>Apply high-quality lens shading correction,<wbr/> at the +cost of possibly reduced frame rate.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Quality of lens shading correction applied +to the image data.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.shading.availableModes">android.<wbr/>shading.<wbr/>available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to OFF mode,<wbr/> no lens shading correction will be applied by the +camera device,<wbr/> and an identity lens shading map data will be provided +if <code><a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> == ON</code>.<wbr/> For example,<wbr/> for lens +shading map with size of <code>[ 4,<wbr/> 3 ]</code>,<wbr/> +the output <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a> for this case will be an identity +map shown below:</p> +<pre><code>[ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ] +</code></pre> +<p>When set to other modes,<wbr/> lens shading correction will be applied by the camera +device.<wbr/> Applications can request lens shading map data by setting +<a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> to ON,<wbr/> and then the camera device will provide lens +shading map data in <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a>; the returned shading map +data will be the one applied by the camera device for this capture request.<wbr/></p> +<p>The shading map data may depend on the auto-exposure (AE) and AWB statistics,<wbr/> therefore +the reliability of the map data may be affected by the AE and AWB algorithms.<wbr/> When AE and +AWB are in AUTO modes(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF and <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>!=</code> +OFF),<wbr/> to get best results,<wbr/> it is recommended that the applications wait for the AE and AWB +to be converged before using the returned shading map data.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.shading.strength"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>shading.<wbr/>strength + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Control the amount of shading correction +applied to the images</p> + </td> + + <td class="entry_units"> + unitless: 1-10; 10 is full shading + compensation + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.shading.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>shading.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>No lens shading correction is applied.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Apply lens shading corrections,<wbr/> without slowing +frame rate relative to sensor raw output</p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>Apply high-quality lens shading correction,<wbr/> at the +cost of possibly reduced frame rate.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Quality of lens shading correction applied +to the image data.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.shading.availableModes">android.<wbr/>shading.<wbr/>available<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to OFF mode,<wbr/> no lens shading correction will be applied by the +camera device,<wbr/> and an identity lens shading map data will be provided +if <code><a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> == ON</code>.<wbr/> For example,<wbr/> for lens +shading map with size of <code>[ 4,<wbr/> 3 ]</code>,<wbr/> +the output <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a> for this case will be an identity +map shown below:</p> +<pre><code>[ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ] +</code></pre> +<p>When set to other modes,<wbr/> lens shading correction will be applied by the camera +device.<wbr/> Applications can request lens shading map data by setting +<a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> to ON,<wbr/> and then the camera device will provide lens +shading map data in <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a>; the returned shading map +data will be the one applied by the camera device for this capture request.<wbr/></p> +<p>The shading map data may depend on the auto-exposure (AE) and AWB statistics,<wbr/> therefore +the reliability of the map data may be affected by the AE and AWB algorithms.<wbr/> When AE and +AWB are in AUTO modes(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF and <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>!=</code> +OFF),<wbr/> to get best results,<wbr/> it is recommended that the applications wait for the AE and AWB +to be converged before using the returned shading map data.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.shading.availableModes"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>shading.<wbr/>available<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">List of enums (android.<wbr/>shading.<wbr/>mode).<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of lens shading modes for <a href="#controls_android.shading.mode">android.<wbr/>shading.<wbr/>mode</a> that are supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.shading.mode">android.<wbr/>shading.<wbr/>mode</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This list contains lens shading modes that can be set for the camera device.<wbr/> +Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always +list OFF and FAST mode.<wbr/> This includes all FULL level devices.<wbr/> +LEGACY devices will always only support FAST mode.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if lens shading correction control is +available on the camera device,<wbr/> but the underlying implementation can be the same for +both modes.<wbr/> That is,<wbr/> if the highest quality implementation on the camera device does not +slow down capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_statistics" class="section">statistics</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.statistics.faceDetectMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Do not include face detection statistics in capture +results.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SIMPLE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Return face rectangle and confidence values only.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FULL</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Return all face +metadata.<wbr/></p> +<p>In this mode,<wbr/> face rectangles,<wbr/> scores,<wbr/> landmarks,<wbr/> and face IDs are all valid.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operating mode for the face detector +unit.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.statistics.info.availableFaceDetectModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Whether face detection is enabled,<wbr/> and whether it +should output just the basic fields or the full set of +fields.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>SIMPLE mode must fill in <a href="#dynamic_android.statistics.faceRectangles">android.<wbr/>statistics.<wbr/>face<wbr/>Rectangles</a> and +<a href="#dynamic_android.statistics.faceScores">android.<wbr/>statistics.<wbr/>face<wbr/>Scores</a>.<wbr/> +FULL mode must also fill in <a href="#dynamic_android.statistics.faceIds">android.<wbr/>statistics.<wbr/>face<wbr/>Ids</a>,<wbr/> and +<a href="#dynamic_android.statistics.faceLandmarks">android.<wbr/>statistics.<wbr/>face<wbr/>Landmarks</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.statistics.histogramMode"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>statistics.<wbr/>histogram<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [system as boolean]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operating mode for histogram +generation</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.statistics.sharpnessMapMode"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>statistics.<wbr/>sharpness<wbr/>Map<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [system as boolean]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operating mode for sharpness map +generation</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.statistics.hotPixelMapMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Hot pixel map production is disabled.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Hot pixel map production is enabled.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operating mode for hot pixel map generation.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.statistics.info.availableHotPixelMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Map<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If set to <code>true</code>,<wbr/> a hot pixel map is returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/> +If set to <code>false</code>,<wbr/> no hot pixel map will be returned.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.statistics.lensShadingMapMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Do not include a lens shading map in the capture result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Include a lens shading map in the capture result.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether the camera device will output the lens +shading map in output result metadata.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.statistics.info.availableLensShadingMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Lens<wbr/>Shading<wbr/>Map<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to ON,<wbr/> +<a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> will be provided in +the output result metadata.<wbr/></p> +<p>ON is always supported on devices with the RAW capability.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + + + <tr class="entry" id="static_android.statistics.info.availableFaceDetectModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">List of enums from android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of face detection modes for <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> that are +supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>OFF is always supported.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.statistics.info.histogramBucketCount"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>statistics.<wbr/>info.<wbr/>histogram<wbr/>Bucket<wbr/>Count + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Number of histogram buckets +supported</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>>= 64</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.statistics.info.maxFaceCount"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Face<wbr/>Count + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum number of simultaneously detectable +faces.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>0 for cameras without available face detection; otherwise: +<code>>=4</code> for LIMITED or FULL hwlevel devices or +<code>>0</code> for LEGACY devices.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.statistics.info.maxHistogramCount"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Histogram<wbr/>Count + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Maximum value possible for a histogram +bucket</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.statistics.info.maxSharpnessMapValue"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Sharpness<wbr/>Map<wbr/>Value + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [system]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Maximum value possible for a sharpness map +region.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.statistics.info.sharpnessMapSize"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>statistics.<wbr/>info.<wbr/>sharpness<wbr/>Map<wbr/>Size + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 + </span> + <span class="entry_type_visibility"> [system as size]</span> + + + + + <div class="entry_type_notes">width x height</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Dimensions of the sharpness +map</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Must be at least 32 x 32</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.statistics.info.availableHotPixelMapModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Map<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as boolean]</span> + + + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of hot pixel map output modes for <a href="#controls_android.statistics.hotPixelMapMode">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode</a> that are +supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.statistics.hotPixelMapMode">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If no hotpixel map output is available for this camera device,<wbr/> this will contain only +<code>false</code>.<wbr/></p> +<p>ON is always supported on devices with the RAW capability.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.statistics.info.availableLensShadingMapModes"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Lens<wbr/>Shading<wbr/>Map<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of lens shading map output modes for <a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> that +are supported by this camera device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If no lens shading map output is available for this camera device,<wbr/> this key will +contain only OFF.<wbr/></p> +<p>ON is always supported on devices with the RAW capability.<wbr/> +LEGACY mode devices will always only support OFF.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.statistics.faceDetectMode"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Do not include face detection statistics in capture +results.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">SIMPLE</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Return face rectangle and confidence values only.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FULL</span> + <span class="entry_type_enum_optional">[optional]</span> + <span class="entry_type_enum_notes"><p>Return all face +metadata.<wbr/></p> +<p>In this mode,<wbr/> face rectangles,<wbr/> scores,<wbr/> landmarks,<wbr/> and face IDs are all valid.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operating mode for the face detector +unit.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.statistics.info.availableFaceDetectModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Whether face detection is enabled,<wbr/> and whether it +should output just the basic fields or the full set of +fields.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>SIMPLE mode must fill in <a href="#dynamic_android.statistics.faceRectangles">android.<wbr/>statistics.<wbr/>face<wbr/>Rectangles</a> and +<a href="#dynamic_android.statistics.faceScores">android.<wbr/>statistics.<wbr/>face<wbr/>Scores</a>.<wbr/> +FULL mode must also fill in <a href="#dynamic_android.statistics.faceIds">android.<wbr/>statistics.<wbr/>face<wbr/>Ids</a>,<wbr/> and +<a href="#dynamic_android.statistics.faceLandmarks">android.<wbr/>statistics.<wbr/>face<wbr/>Landmarks</a>.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.faceIds"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>face<wbr/>Ids + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of unique IDs for detected faces.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Each detected face is given a unique ID that is valid for as long as the face is visible +to the camera device.<wbr/> A face that leaves the field of view and later returns may be +assigned a new ID.<wbr/></p> +<p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> == FULL</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.faceLandmarks"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>face<wbr/>Landmarks + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 6 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">(leftEyeX,<wbr/> leftEyeY,<wbr/> rightEyeX,<wbr/> rightEyeY,<wbr/> mouthX,<wbr/> mouthY)</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of landmarks for detected +faces.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The coordinate system is that of <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with +<code>(0,<wbr/> 0)</code> being the top-left pixel of the active array.<wbr/></p> +<p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> == FULL</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.faceRectangles"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>face<wbr/>Rectangles + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 4 + </span> + <span class="entry_type_visibility"> [ndk_public as rectangle]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + <div class="entry_type_notes">(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax).<wbr/> (0,<wbr/>0) is top-left of active pixel area</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of the bounding rectangles for detected +faces.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The coordinate system is that of <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with +<code>(0,<wbr/> 0)</code> being the top-left pixel of the active array.<wbr/></p> +<p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> != OFF</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.faceScores"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>statistics.<wbr/>face<wbr/>Scores + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of the face confidence scores for +detected faces</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>1-100</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_BC">BC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> != OFF.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The value should be meaningful (for example,<wbr/> setting 100 at +all times is illegal).<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.faces"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>faces + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [java_public as face]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[legacy] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of the faces detected through camera face detection +in this capture.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> <code>!=</code> OFF.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.histogram"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>histogram + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 3 + </span> + <span class="entry_type_visibility"> [system]</span> + + + + + <div class="entry_type_notes">count of pixels for each color channel that fall into each histogram bucket,<wbr/> scaled to be between 0 and maxHistogramCount</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A 3-channel histogram based on the raw +sensor data</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The k'th bucket (0-based) covers the input range +(with w = <a href="#static_android.sensor.info.whiteLevel">android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level</a>) of [ k * w/<wbr/>N,<wbr/> +(k + 1) * w /<wbr/> N ).<wbr/> If only a monochrome sharpness map is +supported,<wbr/> all channels should have the same data</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.histogramMode"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>statistics.<wbr/>histogram<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [system as boolean]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operating mode for histogram +generation</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.sharpnessMap"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>sharpness<wbr/>Map + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x m x 3 + </span> + <span class="entry_type_visibility"> [system]</span> + + + + + <div class="entry_type_notes">estimated sharpness for each region of the input image.<wbr/> Normalized to be between 0 and maxSharpnessMapValue.<wbr/> Higher values mean sharper (better focused)</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A 3-channel sharpness map,<wbr/> based on the raw +sensor data</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If only a monochrome sharpness map is supported,<wbr/> +all channels should have the same data</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.sharpnessMapMode"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>statistics.<wbr/>sharpness<wbr/>Map<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [system as boolean]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operating mode for sharpness map +generation</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_FUTURE">FUTURE</a></li> + </ul> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.lensShadingCorrectionMap"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + + <span class="entry_type_visibility"> [java_public as lensShadingMap]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The shading map is a low-resolution floating-point map +that lists the coefficients used to correct for vignetting,<wbr/> for each +Bayer color channel.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Each gain factor is >= 1</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The map provided here is the same map that is used by the camera device to +correct both color shading and vignetting for output non-RAW images.<wbr/></p> +<p>When there is no lens shading correction applied to RAW +output images (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> <code>==</code> +false),<wbr/> this map is the complete lens shading correction +map; when there is some lens shading correction applied to +the RAW output image (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a><code>==</code> true),<wbr/> this map reports the remaining lens shading +correction map that needs to be applied to get shading +corrected images that match the camera device's output for +non-RAW formats.<wbr/></p> +<p>For a complete shading correction map,<wbr/> the least shaded +section of the image will have a gain factor of 1; all +other sections will have gains above 1.<wbr/></p> +<p>When <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> = TRANSFORM_<wbr/>MATRIX,<wbr/> the map +will take into account the colorCorrection settings.<wbr/></p> +<p>The shading map is for the entire active pixel array,<wbr/> and is not +affected by the crop region specified in the request.<wbr/> Each shading map +entry is the value of the shading compensation map over a specific +pixel on the sensor.<wbr/> Specifically,<wbr/> with a (N x M) resolution shading +map,<wbr/> and an active pixel array size (W x H),<wbr/> shading map entry +(x,<wbr/>y) ϵ (0 ...<wbr/> N-1,<wbr/> 0 ...<wbr/> M-1) is the value of the shading map at +pixel ( ((W-1)/<wbr/>(N-1)) * x,<wbr/> ((H-1)/<wbr/>(M-1)) * y) for the four color channels.<wbr/> +The map is assumed to be bilinearly interpolated between the sample points.<wbr/></p> +<p>The channel order is [R,<wbr/> Geven,<wbr/> Godd,<wbr/> B],<wbr/> where Geven is the green +channel for the even rows of a Bayer pattern,<wbr/> and Godd is the odd rows.<wbr/> +The shading map is stored in a fully interleaved format.<wbr/></p> +<p>The shading map will generally have on the order of 30-40 rows and columns,<wbr/> +and will be smaller than 64x64.<wbr/></p> +<p>As an example,<wbr/> given a very small map defined as:</p> +<pre><code>width,<wbr/>height = [ 4,<wbr/> 3 ] +values = +[ 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> + 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>3,<wbr/> + 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>2,<wbr/> + 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/> + 1.<wbr/>2,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3 ] +</code></pre> +<p>The low-resolution scaling map images for each channel are +(displayed using nearest-neighbor interpolation):</p> +<p><img alt="Red lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png"/> +<img alt="Green (even rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png"/> +<img alt="Green (odd rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png"/> +<img alt="Blue lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png"/></p> +<p>As a visualization only,<wbr/> inverting the full-color map to recover an +image of a gray wall (using bicubic interpolation for visual quality) as captured by the sensor gives:</p> +<p><img alt="Image of a uniform white wall (inverse shading map)" src="images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png"/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.lensShadingMap"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 x n x m + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">2D array of float gain factors per channel to correct lens shading</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The shading map is a low-resolution floating-point map +that lists the coefficients used to correct for vignetting and color shading,<wbr/> +for each Bayer color channel of RAW image data.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Each gain factor is >= 1</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The map provided here is the same map that is used by the camera device to +correct both color shading and vignetting for output non-RAW images.<wbr/></p> +<p>When there is no lens shading correction applied to RAW +output images (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> <code>==</code> +false),<wbr/> this map is the complete lens shading correction +map; when there is some lens shading correction applied to +the RAW output image (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a><code>==</code> true),<wbr/> this map reports the remaining lens shading +correction map that needs to be applied to get shading +corrected images that match the camera device's output for +non-RAW formats.<wbr/></p> +<p>For a complete shading correction map,<wbr/> the least shaded +section of the image will have a gain factor of 1; all +other sections will have gains above 1.<wbr/></p> +<p>When <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> = TRANSFORM_<wbr/>MATRIX,<wbr/> the map +will take into account the colorCorrection settings.<wbr/></p> +<p>The shading map is for the entire active pixel array,<wbr/> and is not +affected by the crop region specified in the request.<wbr/> Each shading map +entry is the value of the shading compensation map over a specific +pixel on the sensor.<wbr/> Specifically,<wbr/> with a (N x M) resolution shading +map,<wbr/> and an active pixel array size (W x H),<wbr/> shading map entry +(x,<wbr/>y) ϵ (0 ...<wbr/> N-1,<wbr/> 0 ...<wbr/> M-1) is the value of the shading map at +pixel ( ((W-1)/<wbr/>(N-1)) * x,<wbr/> ((H-1)/<wbr/>(M-1)) * y) for the four color channels.<wbr/> +The map is assumed to be bilinearly interpolated between the sample points.<wbr/></p> +<p>The channel order is [R,<wbr/> Geven,<wbr/> Godd,<wbr/> B],<wbr/> where Geven is the green +channel for the even rows of a Bayer pattern,<wbr/> and Godd is the odd rows.<wbr/> +The shading map is stored in a fully interleaved format,<wbr/> and its size +is provided in the camera static metadata by <a href="#static_android.lens.info.shadingMapSize">android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size</a>.<wbr/></p> +<p>The shading map will generally have on the order of 30-40 rows and columns,<wbr/> +and will be smaller than 64x64.<wbr/></p> +<p>As an example,<wbr/> given a very small map defined as:</p> +<pre><code><a href="#static_android.lens.info.shadingMapSize">android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size</a> = [ 4,<wbr/> 3 ] +<a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> = +[ 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> + 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>3,<wbr/> + 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/> + 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>2,<wbr/> + 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/> + 1.<wbr/>2,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3 ] +</code></pre> +<p>The low-resolution scaling map images for each channel are +(displayed using nearest-neighbor interpolation):</p> +<p><img alt="Red lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png"/> +<img alt="Green (even rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png"/> +<img alt="Green (odd rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png"/> +<img alt="Blue lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png"/></p> +<p>As a visualization only,<wbr/> inverting the full-color map to recover an +image of a gray wall (using bicubic interpolation for visual quality) +as captured by the sensor gives:</p> +<p><img alt="Image of a uniform white wall (inverse shading map)" src="images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png"/></p> +<p>Note that the RAW image data might be subject to lens shading +correction not reported on this map.<wbr/> Query +<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> to see if RAW image data has subject +to lens shading correction.<wbr/> If <a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> +is TRUE,<wbr/> the RAW image data is subject to partial or full lens shading +correction.<wbr/> In the case full lens shading correction is applied to RAW +images,<wbr/> the gain factor map reported in this key will contain all 1.<wbr/>0 gains.<wbr/> +In other words,<wbr/> the map reported in this key is the remaining lens shading +that needs to be applied on the RAW image to get images without lens shading +artifacts.<wbr/> See <a href="#static_android.request.maxNumOutputRaw">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Raw</a> for a list of RAW image +formats.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The lens shading map calculation may depend on exposure and white balance statistics.<wbr/> +When AE and AWB are in AUTO modes +(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF and <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>!=</code> OFF),<wbr/> the HAL +may have all the information it need to generate most accurate lens shading map.<wbr/> When +AE or AWB are in manual mode +(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>==</code> OFF or <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>==</code> OFF),<wbr/> the shading map +may be adversely impacted by manual exposure or white balance parameters.<wbr/> To avoid +generating unreliable shading map data,<wbr/> the HAL may choose to lock the shading map with +the latest known good map generated when the AE and AWB are in AUTO modes.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.predictedColorGains"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>statistics.<wbr/>predicted<wbr/>Color<wbr/>Gains + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 + </span> + <span class="entry_type_visibility"> [hidden]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + <div class="entry_type_notes">A 1D array of floats for 4 color channel gains</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The best-fit color channel gains calculated +by the camera device's statistics units for the current output frame.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This may be different than the gains used for this frame,<wbr/> +since statistics processing on data from a new frame +typically completes after the transform has already been +applied to that frame.<wbr/></p> +<p>The 4 channel gains are defined in Bayer domain,<wbr/> +see <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> for details.<wbr/></p> +<p>This value should always be calculated by the auto-white balance (AWB) block,<wbr/> +regardless of the android.<wbr/>control.<wbr/>* current values.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.predictedColorTransform"> + <td class="entry_name + entry_name_deprecated + " rowspan="3"> + android.<wbr/>statistics.<wbr/>predicted<wbr/>Color<wbr/>Transform + </td> + <td class="entry_type"> + <span class="entry_type_name">rational</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 3 x 3 + </span> + <span class="entry_type_visibility"> [hidden]</span> + + + + <span class="entry_type_deprecated">[deprecated] </span> + + <div class="entry_type_notes">3x3 rational matrix in row-major order</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The best-fit color transform matrix estimate +calculated by the camera device's statistics units for the current +output frame.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The camera device will provide the estimate from its +statistics unit on the white balance transforms to use +for the next frame.<wbr/> These are the values the camera device believes +are the best fit for the current output frame.<wbr/> This may +be different than the transform used for this frame,<wbr/> since +statistics processing on data from a new frame typically +completes after the transform has already been applied to +that frame.<wbr/></p> +<p>These estimates must be provided for all frames,<wbr/> even if +capture settings and color transforms are set by the application.<wbr/></p> +<p>This value should always be calculated by the auto-white balance (AWB) block,<wbr/> +regardless of the android.<wbr/>control.<wbr/>* current values.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.sceneFlicker"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>scene<wbr/>Flicker + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">NONE</span> + <span class="entry_type_enum_notes"><p>The camera device does not detect any flickering illumination +in the current scene.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">50HZ</span> + <span class="entry_type_enum_notes"><p>The camera device detects illumination flickering at 50Hz +in the current scene.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">60HZ</span> + <span class="entry_type_enum_notes"><p>The camera device detects illumination flickering at 60Hz +in the current scene.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The camera device estimated scene illumination lighting +frequency.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Many light sources,<wbr/> such as most fluorescent lights,<wbr/> flicker at a rate +that depends on the local utility power standards.<wbr/> This flicker must be +accounted for by auto-exposure routines to avoid artifacts in captured images.<wbr/> +The camera device uses this entry to tell the application what the scene +illuminant frequency is.<wbr/></p> +<p>When manual exposure control is enabled +(<code><a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> == OFF</code> or <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == +OFF</code>),<wbr/> the <a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> doesn't perform +antibanding,<wbr/> and the application can ensure it selects +exposure times that do not cause banding issues by looking +into this metadata field.<wbr/> See +<a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> for more details.<wbr/></p> +<p>Reports NONE if there doesn't appear to be flickering illumination.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.hotPixelMapMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Hot pixel map production is disabled.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Hot pixel map production is enabled.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Operating mode for hot pixel map generation.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.statistics.info.availableHotPixelMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Map<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If set to <code>true</code>,<wbr/> a hot pixel map is returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/> +If set to <code>false</code>,<wbr/> no hot pixel map will be returned.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.hotPixelMap"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 2 x n + </span> + <span class="entry_type_visibility"> [public as point]</span> + + + + + <div class="entry_type_notes">list of coordinates based on android.<wbr/>sensor.<wbr/>pixel<wbr/>Array<wbr/>Size</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of <code>(x,<wbr/> y)</code> coordinates of hot/<wbr/>defective pixels on the sensor.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>n <= number of pixels on the sensor.<wbr/> +The <code>(x,<wbr/> y)</code> coordinates must be bounded by +<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>A coordinate <code>(x,<wbr/> y)</code> must lie between <code>(0,<wbr/> 0)</code>,<wbr/> and +<code>(width - 1,<wbr/> height - 1)</code> (inclusive),<wbr/> which are the top-left and +bottom-right of the pixel array,<wbr/> respectively.<wbr/> The width and +height dimensions are given in <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/> +This may include hot pixels that lie outside of the active array +bounds given by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>A hotpixel map contains the coordinates of pixels on the camera +sensor that do report valid values (usually due to defects in +the camera sensor).<wbr/> This includes pixels that are stuck at certain +values,<wbr/> or have a response that does not accuractly encode the +incoming light from the scene.<wbr/></p> +<p>To avoid performance issues,<wbr/> there should be significantly fewer hot +pixels than actual pixels on the camera sensor.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.statistics.lensShadingMapMode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + <span class="entry_type_enum_notes"><p>Do not include a lens shading map in the capture result.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + <span class="entry_type_enum_notes"><p>Include a lens shading map in the capture result.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether the camera device will output the lens +shading map in output result metadata.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.statistics.info.availableLensShadingMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Lens<wbr/>Shading<wbr/>Map<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_RAW">RAW</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to ON,<wbr/> +<a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> will be provided in +the output result metadata.<wbr/></p> +<p>ON is always supported on devices with the RAW capability.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_tonemap" class="section">tonemap</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.tonemap.curveBlue"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>curve<wbr/>Blue + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 2 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the blue +channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +CONTRAST_<wbr/>CURVE.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.tonemap.curveGreen"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>curve<wbr/>Green + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 2 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the green +channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +CONTRAST_<wbr/>CURVE.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.tonemap.curveRed"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>tonemap.<wbr/>curve<wbr/>Red + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 2 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the red +channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +CONTRAST_<wbr/>CURVE.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>0-1 on both input and output coordinates,<wbr/> normalized +as a floating-point value such that 0 == black and 1 == white.<wbr/></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Each channel's curve is defined by an array of control points:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = + [ P0in,<wbr/> P0out,<wbr/> P1in,<wbr/> P1out,<wbr/> P2in,<wbr/> P2out,<wbr/> P3in,<wbr/> P3out,<wbr/> ...,<wbr/> PNin,<wbr/> PNout ] +2 <= N <= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre> +<p>These are sorted in order of increasing <code>Pin</code>; it is +required that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to +define a complete mapping.<wbr/> For input values between control points,<wbr/> +the camera device must linearly interpolate between the control +points.<wbr/></p> +<p>Each curve can have an independent number of points,<wbr/> and the number +of points can be less than max (that is,<wbr/> the request doesn't have to +always provide a curve with number of points equivalent to +<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p> +<p>A few examples,<wbr/> and their corresponding graphical mappings; these +only specify the red channel and the precision is limited to 4 +digits,<wbr/> for conciseness.<wbr/></p> +<p>Linear mapping:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ] +</code></pre> +<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p> +<p>Invert mapping:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 0 ] +</code></pre> +<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p> +<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ + 0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2920,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4002,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4812,<wbr/> + 0.<wbr/>2667,<wbr/> 0.<wbr/>5484,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6069,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6594,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7072,<wbr/> + 0.<wbr/>5333,<wbr/> 0.<wbr/>7515,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7928,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8317,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8685,<wbr/> + 0.<wbr/>8000,<wbr/> 0.<wbr/>9035,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9370,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9691,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ] +</code></pre> +<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p> +<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ + 0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2864,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4007,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4845,<wbr/> + 0.<wbr/>2667,<wbr/> 0.<wbr/>5532,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6125,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6652,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7130,<wbr/> + 0.<wbr/>5333,<wbr/> 0.<wbr/>7569,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7977,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8360,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8721,<wbr/> + 0.<wbr/>8000,<wbr/> 0.<wbr/>9063,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9389,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9701,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ] +</code></pre> +<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For good quality of mapping,<wbr/> at least 128 control points are +preferred.<wbr/></p> +<p>A typical use case of this would be a gamma-1/<wbr/>2.<wbr/>2 curve,<wbr/> with as many +control points used as are available.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.tonemap.curve"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>tonemap.<wbr/>curve + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [java_public as tonemapCurve]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> +is CONTRAST_<wbr/>CURVE.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The tonemapCurve consist of three curves for each of red,<wbr/> green,<wbr/> and blue +channels respectively.<wbr/> The following example uses the red channel as an +example.<wbr/> The same logic applies to green and blue channel.<wbr/> +Each channel's curve is defined by an array of control points:</p> +<pre><code>curveRed = + [ P0(in,<wbr/> out),<wbr/> P1(in,<wbr/> out),<wbr/> P2(in,<wbr/> out),<wbr/> P3(in,<wbr/> out),<wbr/> ...,<wbr/> PN(in,<wbr/> out) ] +2 <= N <= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre> +<p>These are sorted in order of increasing <code>Pin</code>; it is always +guaranteed that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to +define a complete mapping.<wbr/> For input values between control points,<wbr/> +the camera device must linearly interpolate between the control +points.<wbr/></p> +<p>Each curve can have an independent number of points,<wbr/> and the number +of points can be less than max (that is,<wbr/> the request doesn't have to +always provide a curve with number of points equivalent to +<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p> +<p>A few examples,<wbr/> and their corresponding graphical mappings; these +only specify the red channel and the precision is limited to 4 +digits,<wbr/> for conciseness.<wbr/></p> +<p>Linear mapping:</p> +<pre><code>curveRed = [ (0,<wbr/> 0),<wbr/> (1.<wbr/>0,<wbr/> 1.<wbr/>0) ] +</code></pre> +<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p> +<p>Invert mapping:</p> +<pre><code>curveRed = [ (0,<wbr/> 1.<wbr/>0),<wbr/> (1.<wbr/>0,<wbr/> 0) ] +</code></pre> +<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p> +<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p> +<pre><code>curveRed = [ + (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2920),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4002),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4812),<wbr/> + (0.<wbr/>2667,<wbr/> 0.<wbr/>5484),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6069),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6594),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7072),<wbr/> + (0.<wbr/>5333,<wbr/> 0.<wbr/>7515),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7928),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8317),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8685),<wbr/> + (0.<wbr/>8000,<wbr/> 0.<wbr/>9035),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9370),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9691),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ] +</code></pre> +<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p> +<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p> +<pre><code>curveRed = [ + (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2864),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4007),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4845),<wbr/> + (0.<wbr/>2667,<wbr/> 0.<wbr/>5532),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6125),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6652),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7130),<wbr/> + (0.<wbr/>5333,<wbr/> 0.<wbr/>7569),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7977),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8360),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8721),<wbr/> + (0.<wbr/>8000,<wbr/> 0.<wbr/>9063),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9389),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9701),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ] +</code></pre> +<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry is created by the framework from the curveRed,<wbr/> curveGreen and +curveBlue entries.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.tonemap.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">CONTRAST_CURVE</span> + <span class="entry_type_enum_notes"><p>Use the tone mapping curve specified in +the <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>* entries.<wbr/></p> +<p>All color enhancement and tonemapping must be disabled,<wbr/> except +for applying the tonemapping curve specified by +<a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/></p> +<p>Must not slow down frame rate relative to raw +sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Advanced gamma mapping and color enhancement may be applied,<wbr/> without +reducing frame rate compared to raw sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>High-quality gamma mapping and color enhancement will be applied,<wbr/> at +the cost of possibly reduced frame rate compared to raw sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">GAMMA_VALUE</span> + <span class="entry_type_enum_notes"><p>Use the gamma value specified in <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a> to peform +tonemapping.<wbr/></p> +<p>All color enhancement and tonemapping must be disabled,<wbr/> except +for applying the tonemapping curve specified by <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a>.<wbr/></p> +<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PRESET_CURVE</span> + <span class="entry_type_enum_notes"><p>Use the preset tonemapping curve specified in +<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a> to peform tonemapping.<wbr/></p> +<p>All color enhancement and tonemapping must be disabled,<wbr/> except +for applying the tonemapping curve specified by +<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a>.<wbr/></p> +<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>High-level global contrast/<wbr/>gamma/<wbr/>tonemapping control.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.tonemap.availableToneMapModes">android.<wbr/>tonemap.<wbr/>available<wbr/>Tone<wbr/>Map<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When switching to an application-defined contrast curve by setting +<a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> to CONTRAST_<wbr/>CURVE,<wbr/> the curve is defined +per-channel with a set of <code>(in,<wbr/> out)</code> points that specify the +mapping from input high-bit-depth pixel value to the output +low-bit-depth value.<wbr/> Since the actual pixel ranges of both input +and output may change depending on the camera pipeline,<wbr/> the values +are specified by normalized floating-point numbers.<wbr/></p> +<p>More-complex color mapping operations such as 3D color look-up +tables,<wbr/> selective chroma enhancement,<wbr/> or other non-linear color +transforms will be disabled when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +CONTRAST_<wbr/>CURVE.<wbr/></p> +<p>When using either FAST or HIGH_<wbr/>QUALITY,<wbr/> the camera device will +emit its own tonemap curve in <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/> +These values are always available,<wbr/> and as close as possible to the +actually used nonlinear/<wbr/>nonglobal transforms.<wbr/></p> +<p>If a request is sent with CONTRAST_<wbr/>CURVE with the camera device's +provided curve in FAST or HIGH_<wbr/>QUALITY,<wbr/> the image's tonemap will be +roughly the same.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.tonemap.gamma"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>gamma + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +GAMMA_<wbr/>VALUE</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The tonemap curve will be defined the following formula: +* OUT = pow(IN,<wbr/> 1.<wbr/>0 /<wbr/> gamma) +where IN and OUT is the input pixel value scaled to range [0.<wbr/>0,<wbr/> 1.<wbr/>0],<wbr/> +pow is the power function and gamma is the gamma value specified by this +key.<wbr/></p> +<p>The same curve will be applied to all color channels.<wbr/> The camera device +may clip the input gamma value to its supported range.<wbr/> The actual applied +value will be returned in capture result.<wbr/></p> +<p>The valid range of gamma value varies on different devices,<wbr/> but values +within [1.<wbr/>0,<wbr/> 5.<wbr/>0] are guaranteed not to be clipped.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="controls_android.tonemap.presetCurve"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">SRGB</span> + <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by sRGB</p></span> + </li> + <li> + <span class="entry_type_enum_name">REC709</span> + <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by ITU-R BT.<wbr/>709</p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +PRESET_<wbr/>CURVE</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The tonemap curve will be defined by specified standard.<wbr/></p> +<p>sRGB (approximated by 16 control points):</p> +<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p> +<p>Rec.<wbr/> 709 (approximated by 16 control points):</p> +<p><img alt="Rec. 709 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png"/></p> +<p>Note that above figures show a 16 control points approximation of preset +curves.<wbr/> Camera devices may apply a different approximation to the curve.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.tonemap.maxCurvePoints"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Maximum number of supported points in the +tonemap curve that can be used for <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If the actual number of points provided by the application (in <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>*) is +less than this maximum,<wbr/> the camera device will resample the curve to its internal +representation,<wbr/> using linear interpolation.<wbr/></p> +<p>The output curves in the result metadata may have a different number +of points than the input curves,<wbr/> and will represent the actual +hardware curves used as closely as possible when linearly interpolated.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This value must be at least 64.<wbr/> This should be at least 128.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.tonemap.availableToneMapModes"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>tonemap.<wbr/>available<wbr/>Tone<wbr/>Map<wbr/>Modes + </td> + <td class="entry_type"> + <span class="entry_type_name">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [public as enumList]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">list of enums</div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>List of tonemapping modes for <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> that are supported by this camera +device.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Any value listed in <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always contain +at least one of below mode combinations:</p> +<ul> +<li>CONTRAST_<wbr/>CURVE,<wbr/> FAST and HIGH_<wbr/>QUALITY</li> +<li>GAMMA_<wbr/>VALUE,<wbr/> PRESET_<wbr/>CURVE,<wbr/> FAST and HIGH_<wbr/>QUALITY</li> +</ul> +<p>This includes all FULL level devices.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if automatic tonemap control is available +on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/> +That is,<wbr/> if the highest quality implementation on the camera device does not slow down +capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.tonemap.curveBlue"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>curve<wbr/>Blue + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 2 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the blue +channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +CONTRAST_<wbr/>CURVE.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.tonemap.curveGreen"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>curve<wbr/>Green + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 2 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the green +channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +CONTRAST_<wbr/>CURVE.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.tonemap.curveRed"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>tonemap.<wbr/>curve<wbr/>Red + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 2 + </span> + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div> + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the red +channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +CONTRAST_<wbr/>CURVE.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>0-1 on both input and output coordinates,<wbr/> normalized +as a floating-point value such that 0 == black and 1 == white.<wbr/></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Each channel's curve is defined by an array of control points:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = + [ P0in,<wbr/> P0out,<wbr/> P1in,<wbr/> P1out,<wbr/> P2in,<wbr/> P2out,<wbr/> P3in,<wbr/> P3out,<wbr/> ...,<wbr/> PNin,<wbr/> PNout ] +2 <= N <= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre> +<p>These are sorted in order of increasing <code>Pin</code>; it is +required that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to +define a complete mapping.<wbr/> For input values between control points,<wbr/> +the camera device must linearly interpolate between the control +points.<wbr/></p> +<p>Each curve can have an independent number of points,<wbr/> and the number +of points can be less than max (that is,<wbr/> the request doesn't have to +always provide a curve with number of points equivalent to +<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p> +<p>A few examples,<wbr/> and their corresponding graphical mappings; these +only specify the red channel and the precision is limited to 4 +digits,<wbr/> for conciseness.<wbr/></p> +<p>Linear mapping:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ] +</code></pre> +<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p> +<p>Invert mapping:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 0 ] +</code></pre> +<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p> +<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ + 0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2920,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4002,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4812,<wbr/> + 0.<wbr/>2667,<wbr/> 0.<wbr/>5484,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6069,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6594,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7072,<wbr/> + 0.<wbr/>5333,<wbr/> 0.<wbr/>7515,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7928,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8317,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8685,<wbr/> + 0.<wbr/>8000,<wbr/> 0.<wbr/>9035,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9370,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9691,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ] +</code></pre> +<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p> +<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p> +<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ + 0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2864,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4007,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4845,<wbr/> + 0.<wbr/>2667,<wbr/> 0.<wbr/>5532,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6125,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6652,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7130,<wbr/> + 0.<wbr/>5333,<wbr/> 0.<wbr/>7569,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7977,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8360,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8721,<wbr/> + 0.<wbr/>8000,<wbr/> 0.<wbr/>9063,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9389,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9701,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ] +</code></pre> +<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For good quality of mapping,<wbr/> at least 128 control points are +preferred.<wbr/></p> +<p>A typical use case of this would be a gamma-1/<wbr/>2.<wbr/>2 curve,<wbr/> with as many +control points used as are available.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.tonemap.curve"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>tonemap.<wbr/>curve + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [java_public as tonemapCurve]</span> + + <span class="entry_type_synthetic">[synthetic] </span> + + <span class="entry_type_hwlevel">[full] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> +is CONTRAST_<wbr/>CURVE.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The tonemapCurve consist of three curves for each of red,<wbr/> green,<wbr/> and blue +channels respectively.<wbr/> The following example uses the red channel as an +example.<wbr/> The same logic applies to green and blue channel.<wbr/> +Each channel's curve is defined by an array of control points:</p> +<pre><code>curveRed = + [ P0(in,<wbr/> out),<wbr/> P1(in,<wbr/> out),<wbr/> P2(in,<wbr/> out),<wbr/> P3(in,<wbr/> out),<wbr/> ...,<wbr/> PN(in,<wbr/> out) ] +2 <= N <= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre> +<p>These are sorted in order of increasing <code>Pin</code>; it is always +guaranteed that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to +define a complete mapping.<wbr/> For input values between control points,<wbr/> +the camera device must linearly interpolate between the control +points.<wbr/></p> +<p>Each curve can have an independent number of points,<wbr/> and the number +of points can be less than max (that is,<wbr/> the request doesn't have to +always provide a curve with number of points equivalent to +<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p> +<p>A few examples,<wbr/> and their corresponding graphical mappings; these +only specify the red channel and the precision is limited to 4 +digits,<wbr/> for conciseness.<wbr/></p> +<p>Linear mapping:</p> +<pre><code>curveRed = [ (0,<wbr/> 0),<wbr/> (1.<wbr/>0,<wbr/> 1.<wbr/>0) ] +</code></pre> +<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p> +<p>Invert mapping:</p> +<pre><code>curveRed = [ (0,<wbr/> 1.<wbr/>0),<wbr/> (1.<wbr/>0,<wbr/> 0) ] +</code></pre> +<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p> +<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p> +<pre><code>curveRed = [ + (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2920),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4002),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4812),<wbr/> + (0.<wbr/>2667,<wbr/> 0.<wbr/>5484),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6069),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6594),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7072),<wbr/> + (0.<wbr/>5333,<wbr/> 0.<wbr/>7515),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7928),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8317),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8685),<wbr/> + (0.<wbr/>8000,<wbr/> 0.<wbr/>9035),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9370),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9691),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ] +</code></pre> +<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p> +<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p> +<pre><code>curveRed = [ + (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2864),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4007),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4845),<wbr/> + (0.<wbr/>2667,<wbr/> 0.<wbr/>5532),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6125),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6652),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7130),<wbr/> + (0.<wbr/>5333,<wbr/> 0.<wbr/>7569),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7977),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8360),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8721),<wbr/> + (0.<wbr/>8000,<wbr/> 0.<wbr/>9063),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9389),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9701),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ] +</code></pre> +<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This entry is created by the framework from the curveRed,<wbr/> curveGreen and +curveBlue entries.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.tonemap.mode"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>mode + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">CONTRAST_CURVE</span> + <span class="entry_type_enum_notes"><p>Use the tone mapping curve specified in +the <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>* entries.<wbr/></p> +<p>All color enhancement and tonemapping must be disabled,<wbr/> except +for applying the tonemapping curve specified by +<a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/></p> +<p>Must not slow down frame rate relative to raw +sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FAST</span> + <span class="entry_type_enum_notes"><p>Advanced gamma mapping and color enhancement may be applied,<wbr/> without +reducing frame rate compared to raw sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">HIGH_QUALITY</span> + <span class="entry_type_enum_notes"><p>High-quality gamma mapping and color enhancement will be applied,<wbr/> at +the cost of possibly reduced frame rate compared to raw sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">GAMMA_VALUE</span> + <span class="entry_type_enum_notes"><p>Use the gamma value specified in <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a> to peform +tonemapping.<wbr/></p> +<p>All color enhancement and tonemapping must be disabled,<wbr/> except +for applying the tonemapping curve specified by <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a>.<wbr/></p> +<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">PRESET_CURVE</span> + <span class="entry_type_enum_notes"><p>Use the preset tonemapping curve specified in +<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a> to peform tonemapping.<wbr/></p> +<p>All color enhancement and tonemapping must be disabled,<wbr/> except +for applying the tonemapping curve specified by +<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a>.<wbr/></p> +<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>High-level global contrast/<wbr/>gamma/<wbr/>tonemapping control.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p><a href="#static_android.tonemap.availableToneMapModes">android.<wbr/>tonemap.<wbr/>available<wbr/>Tone<wbr/>Map<wbr/>Modes</a></p> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When switching to an application-defined contrast curve by setting +<a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> to CONTRAST_<wbr/>CURVE,<wbr/> the curve is defined +per-channel with a set of <code>(in,<wbr/> out)</code> points that specify the +mapping from input high-bit-depth pixel value to the output +low-bit-depth value.<wbr/> Since the actual pixel ranges of both input +and output may change depending on the camera pipeline,<wbr/> the values +are specified by normalized floating-point numbers.<wbr/></p> +<p>More-complex color mapping operations such as 3D color look-up +tables,<wbr/> selective chroma enhancement,<wbr/> or other non-linear color +transforms will be disabled when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +CONTRAST_<wbr/>CURVE.<wbr/></p> +<p>When using either FAST or HIGH_<wbr/>QUALITY,<wbr/> the camera device will +emit its own tonemap curve in <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/> +These values are always available,<wbr/> and as close as possible to the +actually used nonlinear/<wbr/>nonglobal transforms.<wbr/></p> +<p>If a request is sent with CONTRAST_<wbr/>CURVE with the camera device's +provided curve in FAST or HIGH_<wbr/>QUALITY,<wbr/> the image's tonemap will be +roughly the same.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.tonemap.gamma"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>gamma + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +GAMMA_<wbr/>VALUE</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The tonemap curve will be defined the following formula: +* OUT = pow(IN,<wbr/> 1.<wbr/>0 /<wbr/> gamma) +where IN and OUT is the input pixel value scaled to range [0.<wbr/>0,<wbr/> 1.<wbr/>0],<wbr/> +pow is the power function and gamma is the gamma value specified by this +key.<wbr/></p> +<p>The same curve will be applied to all color channels.<wbr/> The camera device +may clip the input gamma value to its supported range.<wbr/> The actual applied +value will be returned in capture result.<wbr/></p> +<p>The valid range of gamma value varies on different devices,<wbr/> but values +within [1.<wbr/>0,<wbr/> 5.<wbr/>0] are guaranteed not to be clipped.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="dynamic_android.tonemap.presetCurve"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">SRGB</span> + <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by sRGB</p></span> + </li> + <li> + <span class="entry_type_enum_name">REC709</span> + <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by ITU-R BT.<wbr/>709</p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is +PRESET_<wbr/>CURVE</p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The tonemap curve will be defined by specified standard.<wbr/></p> +<p>sRGB (approximated by 16 control points):</p> +<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p> +<p>Rec.<wbr/> 709 (approximated by 16 control points):</p> +<p><img alt="Rec. 709 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png"/></p> +<p>Note that above figures show a 16 control points approximation of preset +curves.<wbr/> Camera devices may apply a different approximation to the curve.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_led" class="section">led</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.led.transmit"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>led.<wbr/>transmit + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [hidden as boolean]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>This LED is nominally used to indicate to the user +that the camera is powered on and may be streaming images back to the +Application Processor.<wbr/> In certain rare circumstances,<wbr/> the OS may +disable this when video is processed locally and not transmitted to +any untrusted applications.<wbr/></p> +<p>In particular,<wbr/> the LED <em>must</em> always be on when the data could be +transmitted off the device.<wbr/> The LED <em>should</em> always be on whenever +data is stored locally on the device.<wbr/></p> +<p>The LED <em>may</em> be off if a trusted application is using the data that +doesn't violate the above rules.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.led.transmit"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>led.<wbr/>transmit + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [hidden as boolean]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>This LED is nominally used to indicate to the user +that the camera is powered on and may be streaming images back to the +Application Processor.<wbr/> In certain rare circumstances,<wbr/> the OS may +disable this when video is processed locally and not transmitted to +any untrusted applications.<wbr/></p> +<p>In particular,<wbr/> the LED <em>must</em> always be on when the data could be +transmitted off the device.<wbr/> The LED <em>should</em> always be on whenever +data is stored locally on the device.<wbr/></p> +<p>The LED <em>may</em> be off if a trusted application is using the data that +doesn't violate the above rules.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.led.availableLeds"> + <td class="entry_name + " rowspan="1"> + android.<wbr/>led.<wbr/>available<wbr/>Leds + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n + </span> + <span class="entry_type_visibility"> [hidden]</span> + + + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">TRANSMIT</span> + <span class="entry_type_enum_notes"><p><a href="#controls_android.led.transmit">android.<wbr/>led.<wbr/>transmit</a> control is used.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>A list of camera LEDs that are available on this system.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_info" class="section">info</td></tr> + + + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.info.supportedHardwareLevel"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">LIMITED</span> + <span class="entry_type_enum_notes"><p>This camera device does not have enough capabilities to qualify as a <code>FULL</code> device or +better.<wbr/></p> +<p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code> tables in the +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a> documentation are guaranteed to be supported.<wbr/></p> +<p>All <code>LIMITED</code> devices support the <code>BACKWARDS_<wbr/>COMPATIBLE</code> capability,<wbr/> indicating basic +support for color image capture.<wbr/> The only exception is that the device may +alternatively support only the <code>DEPTH_<wbr/>OUTPUT</code> capability,<wbr/> if it can only output depth +measurements and not color images.<wbr/></p> +<p><code>LIMITED</code> devices and above require the use of <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> +to lock exposure metering (and calculate flash power,<wbr/> for cameras with flash) before +capturing a high-quality still image.<wbr/></p> +<p>A <code>LIMITED</code> device that only lists the <code>BACKWARDS_<wbr/>COMPATIBLE</code> capability is only +required to support full-automatic operation and post-processing (<code>OFF</code> is not +supported for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>,<wbr/> or +<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>)</p> +<p>Additional capabilities may optionally be supported by a <code>LIMITED</code>-level device,<wbr/> and +can be checked for in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">FULL</span> + <span class="entry_type_enum_notes"><p>This camera device is capable of supporting advanced imaging applications.<wbr/></p> +<p>The stream configurations listed in the <code>FULL</code>,<wbr/> <code>LEGACY</code> and <code>LIMITED</code> tables in the +<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a> documentation are guaranteed to be supported.<wbr/></p> +<p>A <code>FULL</code> device will support below capabilities:</p> +<ul> +<li><code>BURST_<wbr/>CAPTURE</code> capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains + <code>BURST_<wbr/>CAPTURE</code>)</li> +<li>Per frame control (<a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> <code>==</code> PER_<wbr/>FRAME_<wbr/>CONTROL)</li> +<li>Manual sensor control (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains <code>MANUAL_<wbr/>SENSOR</code>)</li> +<li>Manual post-processing control (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains + <code>MANUAL_<wbr/>POST_<wbr/>PROCESSING</code>)</li> +<li>The required exposure time range defined in <a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></li> +<li>The required maxFrameDuration defined in <a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a></li> +</ul> +<p>Note: +Pre-API level 23,<wbr/> FULL devices also supported arbitrary cropping region +(<a href="#static_android.scaler.croppingType">android.<wbr/>scaler.<wbr/>cropping<wbr/>Type</a> <code>== FREEFORM</code>); this requirement was relaxed in API level +23,<wbr/> and <code>FULL</code> devices may only support <code>CENTERED</code> cropping.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">LEGACY</span> + <span class="entry_type_enum_notes"><p>This camera device is running in backward compatibility mode.<wbr/></p> +<p>Only the stream configurations listed in the <code>LEGACY</code> table in the <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a> +documentation are supported.<wbr/></p> +<p>A <code>LEGACY</code> device does not support per-frame control,<wbr/> manual sensor control,<wbr/> manual +post-processing,<wbr/> arbitrary cropping regions,<wbr/> and has relaxed performance constraints.<wbr/> +No additional capabilities beyond <code>BACKWARD_<wbr/>COMPATIBLE</code> will ever be listed by a +<code>LEGACY</code> device in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p> +<p>In addition,<wbr/> the <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is not functional on <code>LEGACY</code> +devices.<wbr/> Instead,<wbr/> every request that includes a JPEG-format output target is treated +as triggering a still capture,<wbr/> internally executing a precapture trigger.<wbr/> This may +fire the flash for flash power metering during precapture,<wbr/> and then fire the flash +for the final capture,<wbr/> if a flash is available on the device and the AE mode is set to +enable the flash.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">3</span> + <span class="entry_type_enum_notes"><p>This camera device is capable of YUV reprocessing and RAW data capture,<wbr/> in addition to +FULL-level capabilities.<wbr/></p> +<p>The stream configurations listed in the <code>LEVEL_<wbr/>3</code>,<wbr/> <code>RAW</code>,<wbr/> <code>FULL</code>,<wbr/> <code>LEGACY</code> and +<code>LIMITED</code> tables in the <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a> +documentation are guaranteed to be supported.<wbr/></p> +<p>The following additional capabilities are guaranteed to be supported:</p> +<ul> +<li><code>YUV_<wbr/>REPROCESSING</code> capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains + <code>YUV_<wbr/>REPROCESSING</code>)</li> +<li><code>RAW</code> capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains + <code>RAW</code>)</li> +</ul></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Generally classifies the overall set of the camera device functionality.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The supported hardware level is a high-level description of the camera device's +capabilities,<wbr/> summarizing several capabilities into one field.<wbr/> Each level adds additional +features to the previous one,<wbr/> and is always a strict superset of the previous level.<wbr/> +The ordering is <code>LEGACY < LIMITED < FULL < LEVEL_<wbr/>3</code>.<wbr/></p> +<p>Starting from <code>LEVEL_<wbr/>3</code>,<wbr/> the level enumerations are guaranteed to be in increasing +numerical value as well.<wbr/> To check if a given device is at least at a given hardware level,<wbr/> +the following code snippet can be used:</p> +<pre><code>//<wbr/> Returns true if the device supports the required hardware level,<wbr/> or better.<wbr/> +boolean isHardwareLevelSupported(CameraCharacteristics c,<wbr/> int requiredLevel) { + int deviceLevel = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>INFO_<wbr/>SUPPORTED_<wbr/>HARDWARE_<wbr/>LEVEL); + if (deviceLevel == Camera<wbr/>Characteristics.<wbr/>INFO_<wbr/>SUPPORTED_<wbr/>HARDWARE_<wbr/>LEVEL_<wbr/>LEGACY) { + return requiredLevel == deviceLevel; + } + //<wbr/> deviceLevel is not LEGACY,<wbr/> can use numerical sort + return requiredLevel <= deviceLevel; +} +</code></pre> +<p>At a high level,<wbr/> the levels are:</p> +<ul> +<li><code>LEGACY</code> devices operate in a backwards-compatibility mode for older + Android devices,<wbr/> and have very limited capabilities.<wbr/></li> +<li><code>LIMITED</code> devices represent the + baseline feature set,<wbr/> and may also include additional capabilities that are + subsets of <code>FULL</code>.<wbr/></li> +<li><code>FULL</code> devices additionally support per-frame manual control of sensor,<wbr/> flash,<wbr/> lens and + post-processing settings,<wbr/> and image capture at a high rate.<wbr/></li> +<li><code>LEVEL_<wbr/>3</code> devices additionally support YUV reprocessing and RAW image capture,<wbr/> along + with additional output stream configurations.<wbr/></li> +</ul> +<p>See the individual level enums for full descriptions of the supported capabilities.<wbr/> The +<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> entry describes the device's capabilities at a +finer-grain level,<wbr/> if needed.<wbr/> In addition,<wbr/> many controls have their available settings or +ranges defined in individual <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a> entries.<wbr/></p> +<p>Some features are not part of any particular hardware level or capability and must be +queried separately.<wbr/> These include:</p> +<ul> +<li>Calibrated timestamps (<a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> REALTIME)</li> +<li>Precision lens control (<a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a> <code>==</code> CALIBRATED)</li> +<li>Face detection (<a href="#static_android.statistics.info.availableFaceDetectModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes</a>)</li> +<li>Optical or electrical image stabilization + (<a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a>,<wbr/> + <a href="#static_android.control.availableVideoStabilizationModes">android.<wbr/>control.<wbr/>available<wbr/>Video<wbr/>Stabilization<wbr/>Modes</a>)</li> +</ul> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The camera 3 HAL device can implement one of three possible operational modes; LIMITED,<wbr/> +FULL,<wbr/> and LEVEL_<wbr/>3.<wbr/></p> +<p>FULL support or better is expected from new higher-end devices.<wbr/> Limited +mode has hardware requirements roughly in line with those for a camera HAL device v1 +implementation,<wbr/> and is expected from older or inexpensive devices.<wbr/> Each level is a strict +superset of the previous level,<wbr/> and they share the same essential operational flow.<wbr/></p> +<p>For full details refer to "S3.<wbr/> Operational Modes" in camera3.<wbr/>h</p> +<p>Camera HAL3+ must not implement LEGACY mode.<wbr/> It is there for backwards compatibility in +the <code>android.<wbr/>hardware.<wbr/>camera2</code> user-facing API only on HALv1 devices,<wbr/> and is implemented +by the camera framework code.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_blackLevel" class="section">blackLevel</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.blackLevel.lock"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>black<wbr/>Level.<wbr/>lock + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether black-level compensation is locked +to its current values,<wbr/> or is free to vary.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_HAL2">HAL2</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When set to <code>true</code> (ON),<wbr/> the values used for black-level +compensation will not change until the lock is set to +<code>false</code> (OFF).<wbr/></p> +<p>Since changes to certain capture parameters (such as +exposure time) may require resetting of black level +compensation,<wbr/> the camera device must report whether setting +the black level lock was successful in the output result +metadata.<wbr/></p> +<p>For example,<wbr/> if a sequence of requests is as follows:</p> +<ul> +<li>Request 1: Exposure = 10ms,<wbr/> Black level lock = OFF</li> +<li>Request 2: Exposure = 10ms,<wbr/> Black level lock = ON</li> +<li>Request 3: Exposure = 10ms,<wbr/> Black level lock = ON</li> +<li>Request 4: Exposure = 20ms,<wbr/> Black level lock = ON</li> +<li>Request 5: Exposure = 20ms,<wbr/> Black level lock = ON</li> +<li>Request 6: Exposure = 20ms,<wbr/> Black level lock = ON</li> +</ul> +<p>And the exposure change in Request 4 requires the camera +device to reset the black level offsets,<wbr/> then the output +result metadata is expected to be:</p> +<ul> +<li>Result 1: Exposure = 10ms,<wbr/> Black level lock = OFF</li> +<li>Result 2: Exposure = 10ms,<wbr/> Black level lock = ON</li> +<li>Result 3: Exposure = 10ms,<wbr/> Black level lock = ON</li> +<li>Result 4: Exposure = 20ms,<wbr/> Black level lock = OFF</li> +<li>Result 5: Exposure = 20ms,<wbr/> Black level lock = ON</li> +<li>Result 6: Exposure = 20ms,<wbr/> Black level lock = ON</li> +</ul> +<p>This indicates to the application that on frame 4,<wbr/> black +levels were reset due to exposure value changes,<wbr/> and pixel +values may not be consistent across captures.<wbr/></p> +<p>The camera device will maintain the lock to the extent +possible,<wbr/> only overriding the lock to OFF when changes to +other request parameters require a black level recalculation +or reset.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If for some reason black level locking is no longer possible +(for example,<wbr/> the analog gain has changed,<wbr/> which forces +black level offsets to be recalculated),<wbr/> then the HAL must +override this request (and it must report 'OFF' when this +does happen) until the next capture for which locking is +possible again.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.blackLevel.lock"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>black<wbr/>Level.<wbr/>lock + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[full] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OFF</span> + </li> + <li> + <span class="entry_type_enum_name">ON</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Whether black-level compensation is locked +to its current values,<wbr/> or is free to vary.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_HAL2">HAL2</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Whether the black level offset was locked for this frame.<wbr/> Should be +ON if <a href="#controls_android.blackLevel.lock">android.<wbr/>black<wbr/>Level.<wbr/>lock</a> was ON in the capture request,<wbr/> unless +a change in other capture settings forced the camera device to +perform a black level reset.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If for some reason black level locking is no longer possible +(for example,<wbr/> the analog gain has changed,<wbr/> which forces +black level offsets to be recalculated),<wbr/> then the HAL must +override this request (and it must report 'OFF' when this +does happen) until the next capture for which locking is +possible again.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_sync" class="section">sync</td></tr> + + + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.sync.frameNumber"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sync.<wbr/>frame<wbr/>Number + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">int64</span> + + <span class="entry_type_visibility"> [ndk_public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">CONVERGING</span> + <span class="entry_type_enum_value">-1</span> + <span class="entry_type_enum_notes"><p>The current result is not yet fully synchronized to any request.<wbr/></p> +<p>Synchronization is in progress,<wbr/> and reading metadata from this +result may include a mix of data that have taken effect since the +last synchronization time.<wbr/></p> +<p>In some future result,<wbr/> within <a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> frames,<wbr/> +this value will update to the actual frame number frame number +the result is guaranteed to be synchronized to (as long as the +request settings remain constant).<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">UNKNOWN</span> + <span class="entry_type_enum_value">-2</span> + <span class="entry_type_enum_notes"><p>The current result's synchronization status is unknown.<wbr/></p> +<p>The result may have already converged,<wbr/> or it may be in +progress.<wbr/> Reading from this result may include some mix +of settings from past requests.<wbr/></p> +<p>After a settings change,<wbr/> the new settings will eventually all +take effect for the output buffers and results.<wbr/> However,<wbr/> this +value will not change when that happens.<wbr/> Altering settings +rapidly may provide outcomes using mixes of settings from recent +requests.<wbr/></p> +<p>This value is intended primarily for backwards compatibility with +the older camera implementations (for android.<wbr/>hardware.<wbr/>Camera).<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The frame number corresponding to the last request +with which the output result (metadata + buffers) has been fully +synchronized.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + <p>Either a non-negative value corresponding to a +<code>frame_<wbr/>number</code>,<wbr/> or one of the two enums (CONVERGING /<wbr/> UNKNOWN).<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>When a request is submitted to the camera device,<wbr/> there is usually a +delay of several frames before the controls get applied.<wbr/> A camera +device may either choose to account for this delay by implementing a +pipeline and carefully submit well-timed atomic control updates,<wbr/> or +it may start streaming control changes that span over several frame +boundaries.<wbr/></p> +<p>In the latter case,<wbr/> whenever a request's settings change relative to +the previous submitted request,<wbr/> the full set of changes may take +multiple frame durations to fully take effect.<wbr/> Some settings may +take effect sooner (in less frame durations) than others.<wbr/></p> +<p>While a set of control changes are being propagated,<wbr/> this value +will be CONVERGING.<wbr/></p> +<p>Once it is fully known that a set of control changes have been +finished propagating,<wbr/> and the resulting updated control settings +have been read back by the camera device,<wbr/> this value will be set +to a non-negative frame number (corresponding to the request to +which the results have synchronized to).<wbr/></p> +<p>Older camera device implementations may not have a way to detect +when all camera controls have been applied,<wbr/> and will always set this +value to UNKNOWN.<wbr/></p> +<p>FULL capability devices will always have this value set to the +frame number of the request corresponding to this result.<wbr/></p> +<p><em>Further details</em>:</p> +<ul> +<li>Whenever a request differs from the last request,<wbr/> any future +results not yet returned may have this value set to CONVERGING (this +could include any in-progress captures not yet returned by the camera +device,<wbr/> for more details see pipeline considerations below).<wbr/></li> +<li>Submitting a series of multiple requests that differ from the +previous request (e.<wbr/>g.<wbr/> r1,<wbr/> r2,<wbr/> r3 s.<wbr/>t.<wbr/> r1 != r2 != r3) +moves the new synchronization frame to the last non-repeating +request (using the smallest frame number from the contiguous list of +repeating requests).<wbr/></li> +<li>Submitting the same request repeatedly will not change this value +to CONVERGING,<wbr/> if it was already a non-negative value.<wbr/></li> +<li>When this value changes to non-negative,<wbr/> that means that all of the +metadata controls from the request have been applied,<wbr/> all of the +metadata controls from the camera device have been read to the +updated values (into the result),<wbr/> and all of the graphics buffers +corresponding to this result are also synchronized to the request.<wbr/></li> +</ul> +<p><em>Pipeline considerations</em>:</p> +<p>Submitting a request with updated controls relative to the previously +submitted requests may also invalidate the synchronization state +of all the results corresponding to currently in-flight requests.<wbr/></p> +<p>In other words,<wbr/> results for this current request and up to +<a href="#static_android.request.pipelineMaxDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth</a> prior requests may have their +<a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> change to CONVERGING.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>Using UNKNOWN here is illegal unless <a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> +is also UNKNOWN.<wbr/></p> +<p>FULL capability devices should simply set this value to the +<code>frame_<wbr/>number</code> of the request this result corresponds to.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.sync.maxLatency"> + <td class="entry_name + " rowspan="5"> + android.<wbr/>sync.<wbr/>max<wbr/>Latency + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">int32</span> + + <span class="entry_type_visibility"> [public]</span> + + + <span class="entry_type_hwlevel">[legacy] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">PER_FRAME_CONTROL</span> + <span class="entry_type_enum_value">0</span> + <span class="entry_type_enum_notes"><p>Every frame has the requests immediately applied.<wbr/></p> +<p>Changing controls over multiple requests one after another will +produce results that have those controls applied atomically +each frame.<wbr/></p> +<p>All FULL capability devices will have this as their maxLatency.<wbr/></p></span> + </li> + <li> + <span class="entry_type_enum_name">UNKNOWN</span> + <span class="entry_type_enum_value">-1</span> + <span class="entry_type_enum_notes"><p>Each new frame has some subset (potentially the entire set) +of the past requests applied to the camera settings.<wbr/></p> +<p>By submitting a series of identical requests,<wbr/> the camera device +will eventually have the camera settings applied,<wbr/> but it is +unknown when that exact point will be.<wbr/></p> +<p>All LEGACY capability devices will have this as their maxLatency.<wbr/></p></span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximum number of frames that can occur after a request +(different than the previous) has been submitted,<wbr/> and before the +result's state becomes synchronized.<wbr/></p> + </td> + + <td class="entry_units"> + Frame counts + </td> + + <td class="entry_range"> + <p>A positive value,<wbr/> PER_<wbr/>FRAME_<wbr/>CONTROL,<wbr/> or UNKNOWN.<wbr/></p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_V1">V1</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This defines the maximum distance (in number of metadata results),<wbr/> +between the frame number of the request that has new controls to apply +and the frame number of the result that has all the controls applied.<wbr/></p> +<p>In other words this acts as an upper boundary for how many frames +must occur before the camera device knows for a fact that the new +submitted camera settings have been applied in outgoing frames.<wbr/></p> + </td> + </tr> + + <tr class="entries_header"> + <th class="th_details" colspan="5">HAL Implementation Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>For example if maxLatency was 2,<wbr/></p> +<pre><code>initial request = X (repeating) +request1 = X +request2 = Y +request3 = Y +request4 = Y + +where requestN has frameNumber N,<wbr/> and the first of the repeating +initial request's has frameNumber F (and F < 1).<wbr/> + +initial result = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == F } +result1 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == F } +result2 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == CONVERGING } +result3 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == CONVERGING } +result4 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == 2 } + +where resultN has frameNumber N.<wbr/> +</code></pre> +<p>Since <code>result4</code> has a <code>frameNumber == 4</code> and +<code><a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == 2</code>,<wbr/> the distance is clearly +<code>4 - 2 = 2</code>.<wbr/></p> +<p>Use <code>frame_<wbr/>count</code> from camera3_<wbr/>request_<wbr/>t instead of +<a href="#controls_android.request.frameCount">android.<wbr/>request.<wbr/>frame<wbr/>Count</a> or +<code><a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html#getFrameNumber">CaptureResult#getFrameNumber</a></code>.<wbr/></p> +<p>LIMITED devices are strongly encouraged to use a non-negative +value.<wbr/> If UNKNOWN is used here then app developers do not have a way +to know when sensor settings have been applied.<wbr/></p> + </td> + </tr> + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_reprocess" class="section">reprocess</td></tr> + + + <tr><td colspan="6" class="kind">controls</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="controls_android.reprocess.effectiveExposureFactor"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [java_public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The amount of exposure time increase factor applied to the original output +frame by the application processing before sending for reprocessing.<wbr/></p> + </td> + + <td class="entry_units"> + Relative exposure time increase factor.<wbr/> + </td> + + <td class="entry_range"> + <p>>= 1.<wbr/>0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is optional,<wbr/> and will be supported if the camera device supports YUV_<wbr/>REPROCESSING +capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains YUV_<wbr/>REPROCESSING).<wbr/></p> +<p>For some YUV reprocessing use cases,<wbr/> the application may choose to filter the original +output frames to effectively reduce the noise to the same level as a frame that was +captured with longer exposure time.<wbr/> To be more specific,<wbr/> assuming the original captured +images were captured with a sensitivity of S and an exposure time of T,<wbr/> the model in +the camera device is that the amount of noise in the image would be approximately what +would be expected if the original capture parameters had been a sensitivity of +S/<wbr/>effectiveExposureFactor and an exposure time of T*effectiveExposureFactor,<wbr/> rather +than S and T respectively.<wbr/> If the captured images were processed by the application +before being sent for reprocessing,<wbr/> then the application may have used image processing +algorithms and/<wbr/>or multi-frame image fusion to reduce the noise in the +application-processed images (input images).<wbr/> By using the effectiveExposureFactor +control,<wbr/> the application can communicate to the camera device the actual noise level +improvement in the application-processed image.<wbr/> With this information,<wbr/> the camera +device can select appropriate noise reduction and edge enhancement parameters to avoid +excessive noise reduction (<a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a>) and insufficient edge +enhancement (<a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a>) being applied to the reprocessed frames.<wbr/></p> +<p>For example,<wbr/> for multi-frame image fusion use case,<wbr/> the application may fuse +multiple output frames together to a final frame for reprocessing.<wbr/> When N image are +fused into 1 image for reprocessing,<wbr/> the exposure time increase factor could be up to +square root of N (based on a simple photon shot noise model).<wbr/> The camera device will +adjust the reprocessing noise reduction and edge enhancement parameters accordingly to +produce the best quality images.<wbr/></p> +<p>This is relative factor,<wbr/> 1.<wbr/>0 indicates the application hasn't processed the input +buffer in a way that affects its effective exposure time.<wbr/></p> +<p>This control is only effective for YUV reprocessing capture request.<wbr/> For noise +reduction reprocessing,<wbr/> it is only effective when <code><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a> != OFF</code>.<wbr/> +Similarly,<wbr/> for edge enhancement reprocessing,<wbr/> it is only effective when +<code><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a> != OFF</code>.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">dynamic</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="dynamic_android.reprocess.effectiveExposureFactor"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor + </td> + <td class="entry_type"> + <span class="entry_type_name">float</span> + + <span class="entry_type_visibility"> [java_public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The amount of exposure time increase factor applied to the original output +frame by the application processing before sending for reprocessing.<wbr/></p> + </td> + + <td class="entry_units"> + Relative exposure time increase factor.<wbr/> + </td> + + <td class="entry_range"> + <p>>= 1.<wbr/>0</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This is optional,<wbr/> and will be supported if the camera device supports YUV_<wbr/>REPROCESSING +capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains YUV_<wbr/>REPROCESSING).<wbr/></p> +<p>For some YUV reprocessing use cases,<wbr/> the application may choose to filter the original +output frames to effectively reduce the noise to the same level as a frame that was +captured with longer exposure time.<wbr/> To be more specific,<wbr/> assuming the original captured +images were captured with a sensitivity of S and an exposure time of T,<wbr/> the model in +the camera device is that the amount of noise in the image would be approximately what +would be expected if the original capture parameters had been a sensitivity of +S/<wbr/>effectiveExposureFactor and an exposure time of T*effectiveExposureFactor,<wbr/> rather +than S and T respectively.<wbr/> If the captured images were processed by the application +before being sent for reprocessing,<wbr/> then the application may have used image processing +algorithms and/<wbr/>or multi-frame image fusion to reduce the noise in the +application-processed images (input images).<wbr/> By using the effectiveExposureFactor +control,<wbr/> the application can communicate to the camera device the actual noise level +improvement in the application-processed image.<wbr/> With this information,<wbr/> the camera +device can select appropriate noise reduction and edge enhancement parameters to avoid +excessive noise reduction (<a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a>) and insufficient edge +enhancement (<a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a>) being applied to the reprocessed frames.<wbr/></p> +<p>For example,<wbr/> for multi-frame image fusion use case,<wbr/> the application may fuse +multiple output frames together to a final frame for reprocessing.<wbr/> When N image are +fused into 1 image for reprocessing,<wbr/> the exposure time increase factor could be up to +square root of N (based on a simple photon shot noise model).<wbr/> The camera device will +adjust the reprocessing noise reduction and edge enhancement parameters accordingly to +produce the best quality images.<wbr/></p> +<p>This is relative factor,<wbr/> 1.<wbr/>0 indicates the application hasn't processed the input +buffer in a way that affects its effective exposure time.<wbr/></p> +<p>This control is only effective for YUV reprocessing capture request.<wbr/> For noise +reduction reprocessing,<wbr/> it is only effective when <code><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a> != OFF</code>.<wbr/> +Similarly,<wbr/> for edge enhancement reprocessing,<wbr/> it is only effective when +<code><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a> != OFF</code>.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.reprocess.maxCaptureStall"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>reprocess.<wbr/>max<wbr/>Capture<wbr/>Stall + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [java_public]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The maximal camera capture pipeline stall (in unit of frame count) introduced by a +reprocess capture request.<wbr/></p> + </td> + + <td class="entry_units"> + Number of frames.<wbr/> + </td> + + <td class="entry_range"> + <p><= 4</p> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_REPROC">REPROC</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>The key describes the maximal interference that one reprocess (input) request +can introduce to the camera simultaneous streaming of regular (output) capture +requests,<wbr/> including repeating requests.<wbr/></p> +<p>When a reprocessing capture request is submitted while a camera output repeating request +(e.<wbr/>g.<wbr/> preview) is being served by the camera device,<wbr/> it may preempt the camera capture +pipeline for at least one frame duration so that the camera device is unable to process +the following capture request in time for the next sensor start of exposure boundary.<wbr/> +When this happens,<wbr/> the application may observe a capture time gap (longer than one frame +duration) between adjacent capture output frames,<wbr/> which usually exhibits as preview +glitch if the repeating request output targets include a preview surface.<wbr/> This key gives +the worst-case number of frame stall introduced by one reprocess request with any kind of +formats/<wbr/>sizes combination.<wbr/></p> +<p>If this key reports 0,<wbr/> it means a reprocess request doesn't introduce any glitch to the +ongoing camera repeating request outputs,<wbr/> as if this reprocess request is never issued.<wbr/></p> +<p>This key is supported if the camera device supports PRIVATE or YUV reprocessing ( +i.<wbr/>e.<wbr/> <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains PRIVATE_<wbr/>REPROCESSING or +YUV_<wbr/>REPROCESSING).<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> + <tr><td colspan="6" id="section_depth" class="section">depth</td></tr> + + + <tr><td colspan="6" class="kind">static</td></tr> + + <thead class="entries_header"> + <tr> + <th class="th_name">Property Name</th> + <th class="th_type">Type</th> + <th class="th_description">Description</th> + <th class="th_units">Units</th> + <th class="th_range">Range</th> + <th class="th_tags">Tags</th> + </tr> + </thead> + + <tbody> + + + + + + + + + + + <tr class="entry" id="static_android.depth.maxDepthSamples"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>depth.<wbr/>max<wbr/>Depth<wbr/>Samples + </td> + <td class="entry_type"> + <span class="entry_type_name">int32</span> + + <span class="entry_type_visibility"> [system]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Maximum number of points that a depth point cloud may contain.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If a camera device supports outputting depth range data in the form of a depth point +cloud (<a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#DEPTH_POINT_CLOUD">Image<wbr/>Format#DEPTH_<wbr/>POINT_<wbr/>CLOUD</a>),<wbr/> this is the maximum +number of points an output buffer may contain.<wbr/></p> +<p>Any given buffer may contain between 0 and maxDepthSamples points,<wbr/> inclusive.<wbr/> +If output in the depth point cloud format is not supported,<wbr/> this entry will +not be defined.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.depth.availableDepthStreamConfigurations"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stream<wbr/>Configurations + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">int32</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + n x 4 + </span> + <span class="entry_type_visibility"> [ndk_public as streamConfiguration]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">OUTPUT</span> + </li> + <li> + <span class="entry_type_enum_name">INPUT</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>The available depth dataspace stream +configurations that this camera device supports +(i.<wbr/>e.<wbr/> format,<wbr/> width,<wbr/> height,<wbr/> output/<wbr/>input stream).<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>These are output stream configurations for use with +dataSpace HAL_<wbr/>DATASPACE_<wbr/>DEPTH.<wbr/> The configurations are +listed as <code>(format,<wbr/> width,<wbr/> height,<wbr/> input?)</code> tuples.<wbr/></p> +<p>Only devices that support depth output for at least +the HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>Y16 dense depth map may include +this entry.<wbr/></p> +<p>A device that also supports the HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>BLOB +sparse depth point cloud must report a single entry for +the format in this list as <code>(HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>BLOB,<wbr/> +<a href="#static_android.depth.maxDepthSamples">android.<wbr/>depth.<wbr/>max<wbr/>Depth<wbr/>Samples</a>,<wbr/> 1,<wbr/> OUTPUT)</code> in addition to +the entries for HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>Y16.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.depth.availableDepthMinFrameDurations"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Min<wbr/>Frame<wbr/>Durations + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 x n + </span> + <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>This lists the minimum frame duration for each +format/<wbr/>size combination for depth output formats.<wbr/></p> + </td> + + <td class="entry_units"> + (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>This should correspond to the frame duration when only that +stream is active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode) +set to either OFF or FAST.<wbr/></p> +<p>When multiple streams are used in a request,<wbr/> the minimum frame +duration will be max(individual stream min durations).<wbr/></p> +<p>The minimum frame duration of a stream (of a particular format,<wbr/> size) +is the same regardless of whether the stream is input or output.<wbr/></p> +<p>See <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> and +<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> for more details about +calculating the max frame rate.<wbr/></p> +<p>(Keep in sync with <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>)</p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.depth.availableDepthStallDurations"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stall<wbr/>Durations + </td> + <td class="entry_type"> + <span class="entry_type_name">int64</span> + <span class="entry_type_container">x</span> + + <span class="entry_type_array"> + 4 x n + </span> + <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>This lists the maximum stall duration for each +output format/<wbr/>size combination for depth streams.<wbr/></p> + </td> + + <td class="entry_units"> + (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + <ul class="entry_tags"> + <li><a href="#tag_DEPTH">DEPTH</a></li> + </ul> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>A stall duration is how much extra time would get added +to the normal minimum frame duration for a repeating request +that has streams with non-zero stall.<wbr/></p> +<p>This functions similarly to +<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> for depth +streams.<wbr/></p> +<p>All depth output stream formats may have a nonzero stall +duration.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + <tr class="entry" id="static_android.depth.depthIsExclusive"> + <td class="entry_name + " rowspan="3"> + android.<wbr/>depth.<wbr/>depth<wbr/>Is<wbr/>Exclusive + </td> + <td class="entry_type"> + <span class="entry_type_name entry_type_name_enum">byte</span> + + <span class="entry_type_visibility"> [public as boolean]</span> + + + <span class="entry_type_hwlevel">[limited] </span> + + + + <ul class="entry_type_enum"> + <li> + <span class="entry_type_enum_name">FALSE</span> + </li> + <li> + <span class="entry_type_enum_name">TRUE</span> + </li> + </ul> + + </td> <!-- entry_type --> + + <td class="entry_description"> + <p>Indicates whether a capture request may target both a +DEPTH16 /<wbr/> DEPTH_<wbr/>POINT_<wbr/>CLOUD output,<wbr/> and normal color outputs (such as +YUV_<wbr/>420_<wbr/>888,<wbr/> JPEG,<wbr/> or RAW) simultaneously.<wbr/></p> + </td> + + <td class="entry_units"> + </td> + + <td class="entry_range"> + </td> + + <td class="entry_tags"> + </td> + + </tr> + <tr class="entries_header"> + <th class="th_details" colspan="5">Details</th> + </tr> + <tr class="entry_cont"> + <td class="entry_details" colspan="5"> + <p>If TRUE,<wbr/> including both depth and color outputs in a single +capture request is not supported.<wbr/> An application must interleave color +and depth requests.<wbr/> If FALSE,<wbr/> a single request can target both types +of output.<wbr/></p> +<p>Typically,<wbr/> this restriction exists on camera devices that +need to emit a specific pattern or wavelength of light to +measure depth values,<wbr/> which causes the color image to be +corrupted during depth measurement.<wbr/></p> + </td> + </tr> + + + <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr> + <!-- end of entry --> + + + + <!-- end of kind --> + </tbody> + + <!-- end of section --> +<!-- </namespace> --> + </table> + + <div class="tags" id="tag_index"> + <h2>Tags</h2> + <ul> + <li id="tag_BC">BC - + Needed for backwards compatibility with old Java API + + <ul class="tags_entries"> + <li><a href="#controls_android.control.aeAntibandingMode">android.control.aeAntibandingMode</a> (controls)</li> + <li><a href="#controls_android.control.aeExposureCompensation">android.control.aeExposureCompensation</a> (controls)</li> + <li><a href="#controls_android.control.aeLock">android.control.aeLock</a> (controls)</li> + <li><a href="#controls_android.control.aeMode">android.control.aeMode</a> (controls)</li> + <li><a href="#controls_android.control.aeRegions">android.control.aeRegions</a> (controls)</li> + <li><a href="#controls_android.control.aeTargetFpsRange">android.control.aeTargetFpsRange</a> (controls)</li> + <li><a href="#controls_android.control.aePrecaptureTrigger">android.control.aePrecaptureTrigger</a> (controls)</li> + <li><a href="#controls_android.control.afMode">android.control.afMode</a> (controls)</li> + <li><a href="#controls_android.control.afRegions">android.control.afRegions</a> (controls)</li> + <li><a href="#controls_android.control.afTrigger">android.control.afTrigger</a> (controls)</li> + <li><a href="#controls_android.control.awbLock">android.control.awbLock</a> (controls)</li> + <li><a href="#controls_android.control.awbMode">android.control.awbMode</a> (controls)</li> + <li><a href="#controls_android.control.awbRegions">android.control.awbRegions</a> (controls)</li> + <li><a href="#controls_android.control.captureIntent">android.control.captureIntent</a> (controls)</li> + <li><a href="#controls_android.control.effectMode">android.control.effectMode</a> (controls)</li> + <li><a href="#controls_android.control.mode">android.control.mode</a> (controls)</li> + <li><a href="#controls_android.control.sceneMode">android.control.sceneMode</a> (controls)</li> + <li><a href="#controls_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a> (controls)</li> + <li><a href="#static_android.control.aeAvailableAntibandingModes">android.control.aeAvailableAntibandingModes</a> (static)</li> + <li><a href="#static_android.control.aeAvailableModes">android.control.aeAvailableModes</a> (static)</li> + <li><a href="#static_android.control.aeAvailableTargetFpsRanges">android.control.aeAvailableTargetFpsRanges</a> (static)</li> + <li><a href="#static_android.control.aeCompensationRange">android.control.aeCompensationRange</a> (static)</li> + <li><a href="#static_android.control.aeCompensationStep">android.control.aeCompensationStep</a> (static)</li> + <li><a href="#static_android.control.afAvailableModes">android.control.afAvailableModes</a> (static)</li> + <li><a href="#static_android.control.availableEffects">android.control.availableEffects</a> (static)</li> + <li><a href="#static_android.control.availableSceneModes">android.control.availableSceneModes</a> (static)</li> + <li><a href="#static_android.control.availableVideoStabilizationModes">android.control.availableVideoStabilizationModes</a> (static)</li> + <li><a href="#static_android.control.awbAvailableModes">android.control.awbAvailableModes</a> (static)</li> + <li><a href="#static_android.control.maxRegions">android.control.maxRegions</a> (static)</li> + <li><a href="#static_android.control.sceneModeOverrides">android.control.sceneModeOverrides</a> (static)</li> + <li><a href="#static_android.control.aeLockAvailable">android.control.aeLockAvailable</a> (static)</li> + <li><a href="#static_android.control.awbLockAvailable">android.control.awbLockAvailable</a> (static)</li> + <li><a href="#controls_android.flash.mode">android.flash.mode</a> (controls)</li> + <li><a href="#static_android.flash.info.available">android.flash.info.available</a> (static)</li> + <li><a href="#controls_android.jpeg.gpsCoordinates">android.jpeg.gpsCoordinates</a> (controls)</li> + <li><a href="#controls_android.jpeg.gpsProcessingMethod">android.jpeg.gpsProcessingMethod</a> (controls)</li> + <li><a href="#controls_android.jpeg.gpsTimestamp">android.jpeg.gpsTimestamp</a> (controls)</li> + <li><a href="#controls_android.jpeg.orientation">android.jpeg.orientation</a> (controls)</li> + <li><a href="#controls_android.jpeg.quality">android.jpeg.quality</a> (controls)</li> + <li><a href="#controls_android.jpeg.thumbnailQuality">android.jpeg.thumbnailQuality</a> (controls)</li> + <li><a href="#controls_android.jpeg.thumbnailSize">android.jpeg.thumbnailSize</a> (controls)</li> + <li><a href="#static_android.jpeg.availableThumbnailSizes">android.jpeg.availableThumbnailSizes</a> (static)</li> + <li><a href="#controls_android.lens.focusDistance">android.lens.focusDistance</a> (controls)</li> + <li><a href="#static_android.lens.info.availableFocalLengths">android.lens.info.availableFocalLengths</a> (static)</li> + <li><a href="#dynamic_android.lens.focusRange">android.lens.focusRange</a> (dynamic)</li> + <li><a href="#static_android.request.maxNumOutputStreams">android.request.maxNumOutputStreams</a> (static)</li> + <li><a href="#controls_android.scaler.cropRegion">android.scaler.cropRegion</a> (controls)</li> + <li><a href="#static_android.scaler.availableFormats">android.scaler.availableFormats</a> (static)</li> + <li><a href="#static_android.scaler.availableJpegMinDurations">android.scaler.availableJpegMinDurations</a> (static)</li> + <li><a href="#static_android.scaler.availableJpegSizes">android.scaler.availableJpegSizes</a> (static)</li> + <li><a href="#static_android.scaler.availableMaxDigitalZoom">android.scaler.availableMaxDigitalZoom</a> (static)</li> + <li><a href="#static_android.scaler.availableProcessedMinDurations">android.scaler.availableProcessedMinDurations</a> (static)</li> + <li><a href="#static_android.scaler.availableProcessedSizes">android.scaler.availableProcessedSizes</a> (static)</li> + <li><a href="#static_android.scaler.availableRawMinDurations">android.scaler.availableRawMinDurations</a> (static)</li> + <li><a href="#static_android.sensor.info.sensitivityRange">android.sensor.info.sensitivityRange</a> (static)</li> + <li><a href="#static_android.sensor.info.physicalSize">android.sensor.info.physicalSize</a> (static)</li> + <li><a href="#static_android.sensor.info.pixelArraySize">android.sensor.info.pixelArraySize</a> (static)</li> + <li><a href="#static_android.sensor.orientation">android.sensor.orientation</a> (static)</li> + <li><a href="#dynamic_android.sensor.timestamp">android.sensor.timestamp</a> (dynamic)</li> + <li><a href="#controls_android.statistics.faceDetectMode">android.statistics.faceDetectMode</a> (controls)</li> + <li><a href="#static_android.statistics.info.maxFaceCount">android.statistics.info.maxFaceCount</a> (static)</li> + <li><a href="#dynamic_android.statistics.faceIds">android.statistics.faceIds</a> (dynamic)</li> + <li><a href="#dynamic_android.statistics.faceLandmarks">android.statistics.faceLandmarks</a> (dynamic)</li> + <li><a href="#dynamic_android.statistics.faceRectangles">android.statistics.faceRectangles</a> (dynamic)</li> + <li><a href="#dynamic_android.statistics.faceScores">android.statistics.faceScores</a> (dynamic)</li> + <li><a href="#dynamic_android.lens.focalLength">android.lens.focalLength</a> (dynamic)</li> + <li><a href="#dynamic_android.lens.focusDistance">android.lens.focusDistance</a> (dynamic)</li> + </ul> + </li> <!-- tag_BC --> + <li id="tag_V1">V1 - + New features for first camera 2 release (API1) + + <ul class="tags_entries"> + <li><a href="#static_android.colorCorrection.availableAberrationModes">android.colorCorrection.availableAberrationModes</a> (static)</li> + <li><a href="#static_android.control.availableHighSpeedVideoConfigurations">android.control.availableHighSpeedVideoConfigurations</a> (static)</li> + <li><a href="#controls_android.edge.mode">android.edge.mode</a> (controls)</li> + <li><a href="#static_android.edge.availableEdgeModes">android.edge.availableEdgeModes</a> (static)</li> + <li><a href="#controls_android.hotPixel.mode">android.hotPixel.mode</a> (controls)</li> + <li><a href="#static_android.hotPixel.availableHotPixelModes">android.hotPixel.availableHotPixelModes</a> (static)</li> + <li><a href="#controls_android.lens.aperture">android.lens.aperture</a> (controls)</li> + <li><a href="#controls_android.lens.filterDensity">android.lens.filterDensity</a> (controls)</li> + <li><a href="#controls_android.lens.focalLength">android.lens.focalLength</a> (controls)</li> + <li><a href="#controls_android.lens.focusDistance">android.lens.focusDistance</a> (controls)</li> + <li><a href="#controls_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a> (controls)</li> + <li><a href="#static_android.lens.info.availableApertures">android.lens.info.availableApertures</a> (static)</li> + <li><a href="#static_android.lens.info.availableFilterDensities">android.lens.info.availableFilterDensities</a> (static)</li> + <li><a href="#static_android.lens.info.availableFocalLengths">android.lens.info.availableFocalLengths</a> (static)</li> + <li><a href="#static_android.lens.info.availableOpticalStabilization">android.lens.info.availableOpticalStabilization</a> (static)</li> + <li><a href="#static_android.lens.info.minimumFocusDistance">android.lens.info.minimumFocusDistance</a> (static)</li> + <li><a href="#static_android.lens.info.shadingMapSize">android.lens.info.shadingMapSize</a> (static)</li> + <li><a href="#static_android.lens.info.focusDistanceCalibration">android.lens.info.focusDistanceCalibration</a> (static)</li> + <li><a href="#dynamic_android.lens.state">android.lens.state</a> (dynamic)</li> + <li><a href="#controls_android.noiseReduction.mode">android.noiseReduction.mode</a> (controls)</li> + <li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.noiseReduction.availableNoiseReductionModes</a> (static)</li> + <li><a href="#controls_android.request.id">android.request.id</a> (controls)</li> + <li><a href="#static_android.scaler.availableMinFrameDurations">android.scaler.availableMinFrameDurations</a> (static)</li> + <li><a href="#static_android.scaler.availableStallDurations">android.scaler.availableStallDurations</a> (static)</li> + <li><a href="#controls_android.sensor.exposureTime">android.sensor.exposureTime</a> (controls)</li> + <li><a href="#controls_android.sensor.frameDuration">android.sensor.frameDuration</a> (controls)</li> + <li><a href="#controls_android.sensor.sensitivity">android.sensor.sensitivity</a> (controls)</li> + <li><a href="#static_android.sensor.info.sensitivityRange">android.sensor.info.sensitivityRange</a> (static)</li> + <li><a href="#static_android.sensor.info.exposureTimeRange">android.sensor.info.exposureTimeRange</a> (static)</li> + <li><a href="#static_android.sensor.info.maxFrameDuration">android.sensor.info.maxFrameDuration</a> (static)</li> + <li><a href="#static_android.sensor.info.physicalSize">android.sensor.info.physicalSize</a> (static)</li> + <li><a href="#static_android.sensor.info.timestampSource">android.sensor.info.timestampSource</a> (static)</li> + <li><a href="#static_android.sensor.maxAnalogSensitivity">android.sensor.maxAnalogSensitivity</a> (static)</li> + <li><a href="#dynamic_android.sensor.rollingShutterSkew">android.sensor.rollingShutterSkew</a> (dynamic)</li> + <li><a href="#controls_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a> (controls)</li> + <li><a href="#static_android.statistics.info.availableHotPixelMapModes">android.statistics.info.availableHotPixelMapModes</a> (static)</li> + <li><a href="#dynamic_android.statistics.hotPixelMap">android.statistics.hotPixelMap</a> (dynamic)</li> + <li><a href="#dynamic_android.sync.frameNumber">android.sync.frameNumber</a> (dynamic)</li> + <li><a href="#static_android.sync.maxLatency">android.sync.maxLatency</a> (static)</li> + <li><a href="#dynamic_android.edge.mode">android.edge.mode</a> (dynamic)</li> + <li><a href="#dynamic_android.hotPixel.mode">android.hotPixel.mode</a> (dynamic)</li> + <li><a href="#dynamic_android.lens.aperture">android.lens.aperture</a> (dynamic)</li> + <li><a href="#dynamic_android.lens.filterDensity">android.lens.filterDensity</a> (dynamic)</li> + <li><a href="#dynamic_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a> (dynamic)</li> + <li><a href="#dynamic_android.noiseReduction.mode">android.noiseReduction.mode</a> (dynamic)</li> + </ul> + </li> <!-- tag_V1 --> + <li id="tag_RAW">RAW - + Needed for useful RAW image processing and DNG file support + + <ul class="tags_entries"> + <li><a href="#controls_android.hotPixel.mode">android.hotPixel.mode</a> (controls)</li> + <li><a href="#static_android.hotPixel.availableHotPixelModes">android.hotPixel.availableHotPixelModes</a> (static)</li> + <li><a href="#static_android.sensor.info.activeArraySize">android.sensor.info.activeArraySize</a> (static)</li> + <li><a href="#static_android.sensor.info.colorFilterArrangement">android.sensor.info.colorFilterArrangement</a> (static)</li> + <li><a href="#static_android.sensor.info.pixelArraySize">android.sensor.info.pixelArraySize</a> (static)</li> + <li><a href="#static_android.sensor.info.whiteLevel">android.sensor.info.whiteLevel</a> (static)</li> + <li><a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.sensor.info.preCorrectionActiveArraySize</a> (static)</li> + <li><a href="#static_android.sensor.referenceIlluminant1">android.sensor.referenceIlluminant1</a> (static)</li> + <li><a href="#static_android.sensor.referenceIlluminant2">android.sensor.referenceIlluminant2</a> (static)</li> + <li><a href="#static_android.sensor.calibrationTransform1">android.sensor.calibrationTransform1</a> (static)</li> + <li><a href="#static_android.sensor.calibrationTransform2">android.sensor.calibrationTransform2</a> (static)</li> + <li><a href="#static_android.sensor.colorTransform1">android.sensor.colorTransform1</a> (static)</li> + <li><a href="#static_android.sensor.colorTransform2">android.sensor.colorTransform2</a> (static)</li> + <li><a href="#static_android.sensor.forwardMatrix1">android.sensor.forwardMatrix1</a> (static)</li> + <li><a href="#static_android.sensor.forwardMatrix2">android.sensor.forwardMatrix2</a> (static)</li> + <li><a href="#static_android.sensor.blackLevelPattern">android.sensor.blackLevelPattern</a> (static)</li> + <li><a href="#static_android.sensor.profileHueSatMapDimensions">android.sensor.profileHueSatMapDimensions</a> (static)</li> + <li><a href="#dynamic_android.sensor.neutralColorPoint">android.sensor.neutralColorPoint</a> (dynamic)</li> + <li><a href="#dynamic_android.sensor.noiseProfile">android.sensor.noiseProfile</a> (dynamic)</li> + <li><a href="#dynamic_android.sensor.profileHueSatMap">android.sensor.profileHueSatMap</a> (dynamic)</li> + <li><a href="#dynamic_android.sensor.profileToneCurve">android.sensor.profileToneCurve</a> (dynamic)</li> + <li><a href="#dynamic_android.sensor.greenSplit">android.sensor.greenSplit</a> (dynamic)</li> + <li><a href="#dynamic_android.sensor.dynamicBlackLevel">android.sensor.dynamicBlackLevel</a> (dynamic)</li> + <li><a href="#dynamic_android.sensor.dynamicWhiteLevel">android.sensor.dynamicWhiteLevel</a> (dynamic)</li> + <li><a href="#controls_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a> (controls)</li> + <li><a href="#static_android.statistics.info.availableHotPixelMapModes">android.statistics.info.availableHotPixelMapModes</a> (static)</li> + <li><a href="#dynamic_android.statistics.hotPixelMap">android.statistics.hotPixelMap</a> (dynamic)</li> + <li><a href="#controls_android.statistics.lensShadingMapMode">android.statistics.lensShadingMapMode</a> (controls)</li> + <li><a href="#dynamic_android.hotPixel.mode">android.hotPixel.mode</a> (dynamic)</li> + </ul> + </li> <!-- tag_RAW --> + <li id="tag_HAL2">HAL2 - + Entry is only used by camera device HAL 2.x + + <ul class="tags_entries"> + <li><a href="#controls_android.request.inputStreams">android.request.inputStreams</a> (controls)</li> + <li><a href="#controls_android.request.outputStreams">android.request.outputStreams</a> (controls)</li> + <li><a href="#controls_android.request.type">android.request.type</a> (controls)</li> + <li><a href="#static_android.request.maxNumReprocessStreams">android.request.maxNumReprocessStreams</a> (static)</li> + <li><a href="#controls_android.blackLevel.lock">android.blackLevel.lock</a> (controls)</li> + </ul> + </li> <!-- tag_HAL2 --> + <li id="tag_FULL">FULL - + Entry is required for full hardware level devices, and optional for other hardware levels + + <ul class="tags_entries"> + <li><a href="#static_android.sensor.maxAnalogSensitivity">android.sensor.maxAnalogSensitivity</a> (static)</li> + </ul> + </li> <!-- tag_FULL --> + <li id="tag_DEPTH">DEPTH - + Entry is required for the depth capability. + + <ul class="tags_entries"> + <li><a href="#static_android.lens.poseRotation">android.lens.poseRotation</a> (static)</li> + <li><a href="#static_android.lens.poseTranslation">android.lens.poseTranslation</a> (static)</li> + <li><a href="#static_android.lens.intrinsicCalibration">android.lens.intrinsicCalibration</a> (static)</li> + <li><a href="#static_android.lens.radialDistortion">android.lens.radialDistortion</a> (static)</li> + <li><a href="#static_android.depth.maxDepthSamples">android.depth.maxDepthSamples</a> (static)</li> + <li><a href="#static_android.depth.availableDepthStreamConfigurations">android.depth.availableDepthStreamConfigurations</a> (static)</li> + <li><a href="#static_android.depth.availableDepthMinFrameDurations">android.depth.availableDepthMinFrameDurations</a> (static)</li> + <li><a href="#static_android.depth.availableDepthStallDurations">android.depth.availableDepthStallDurations</a> (static)</li> + </ul> + </li> <!-- tag_DEPTH --> + <li id="tag_REPROC">REPROC - + Entry is required for the YUV or PRIVATE reprocessing capability. + + <ul class="tags_entries"> + <li><a href="#controls_android.edge.mode">android.edge.mode</a> (controls)</li> + <li><a href="#static_android.edge.availableEdgeModes">android.edge.availableEdgeModes</a> (static)</li> + <li><a href="#controls_android.noiseReduction.mode">android.noiseReduction.mode</a> (controls)</li> + <li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.noiseReduction.availableNoiseReductionModes</a> (static)</li> + <li><a href="#static_android.request.maxNumInputStreams">android.request.maxNumInputStreams</a> (static)</li> + <li><a href="#static_android.scaler.availableInputOutputFormatsMap">android.scaler.availableInputOutputFormatsMap</a> (static)</li> + <li><a href="#controls_android.reprocess.effectiveExposureFactor">android.reprocess.effectiveExposureFactor</a> (controls)</li> + <li><a href="#static_android.reprocess.maxCaptureStall">android.reprocess.maxCaptureStall</a> (static)</li> + <li><a href="#dynamic_android.edge.mode">android.edge.mode</a> (dynamic)</li> + <li><a href="#dynamic_android.noiseReduction.mode">android.noiseReduction.mode</a> (dynamic)</li> + </ul> + </li> <!-- tag_REPROC --> + <li id="tag_FUTURE">FUTURE - + Entry is under-specified and is not required for now. This is for book-keeping purpose, + do not implement or use it, it may be revised for future. + + <ul class="tags_entries"> + <li><a href="#controls_android.demosaic.mode">android.demosaic.mode</a> (controls)</li> + <li><a href="#controls_android.edge.strength">android.edge.strength</a> (controls)</li> + <li><a href="#controls_android.flash.firingPower">android.flash.firingPower</a> (controls)</li> + <li><a href="#controls_android.flash.firingTime">android.flash.firingTime</a> (controls)</li> + <li><a href="#static_android.flash.info.chargeDuration">android.flash.info.chargeDuration</a> (static)</li> + <li><a href="#static_android.flash.colorTemperature">android.flash.colorTemperature</a> (static)</li> + <li><a href="#static_android.flash.maxEnergy">android.flash.maxEnergy</a> (static)</li> + <li><a href="#dynamic_android.jpeg.size">android.jpeg.size</a> (dynamic)</li> + <li><a href="#controls_android.noiseReduction.strength">android.noiseReduction.strength</a> (controls)</li> + <li><a href="#controls_android.request.metadataMode">android.request.metadataMode</a> (controls)</li> + <li><a href="#static_android.sensor.baseGainFactor">android.sensor.baseGainFactor</a> (static)</li> + <li><a href="#dynamic_android.sensor.temperature">android.sensor.temperature</a> (dynamic)</li> + <li><a href="#controls_android.shading.strength">android.shading.strength</a> (controls)</li> + <li><a href="#controls_android.statistics.histogramMode">android.statistics.histogramMode</a> (controls)</li> + <li><a href="#controls_android.statistics.sharpnessMapMode">android.statistics.sharpnessMapMode</a> (controls)</li> + <li><a href="#static_android.statistics.info.histogramBucketCount">android.statistics.info.histogramBucketCount</a> (static)</li> + <li><a href="#static_android.statistics.info.maxHistogramCount">android.statistics.info.maxHistogramCount</a> (static)</li> + <li><a href="#static_android.statistics.info.maxSharpnessMapValue">android.statistics.info.maxSharpnessMapValue</a> (static)</li> + <li><a href="#static_android.statistics.info.sharpnessMapSize">android.statistics.info.sharpnessMapSize</a> (static)</li> + <li><a href="#dynamic_android.statistics.histogram">android.statistics.histogram</a> (dynamic)</li> + <li><a href="#dynamic_android.statistics.sharpnessMap">android.statistics.sharpnessMap</a> (dynamic)</li> + </ul> + </li> <!-- tag_FUTURE --> + </ul> + </div> + + [ <a href="#">top</a> ] + +</body> +</html>
diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal new file mode 100644 index 0000000..2b4b287 --- /dev/null +++ b/camera/metadata/3.2/types.hal
@@ -0,0 +1,1325 @@ +/* + * Copyright (C) 2016 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.camera.metadata@3.2; + +/** TODO(b/33012412): + * - The following information should be code-generated from: + * system/media/camera/docs/metadata_properties.xml + * - Some enum below should be signed: + * - metadata section/key should be unsigned + * - matadata value enum should be signed + */ + +/** + * Top level hierarchy definitions for camera metadata. *_INFO sections are for + * the static metadata that can be retrived without opening the camera device. + * New sections must be added right before ANDROID_SECTION_COUNT to maintain + * existing enumerations. + */ +enum CameraMetadataSection : uint32_t { + ANDROID_COLOR_CORRECTION, + + ANDROID_CONTROL, + + ANDROID_DEMOSAIC, + + ANDROID_EDGE, + + ANDROID_FLASH, + + ANDROID_FLASH_INFO, + + ANDROID_HOT_PIXEL, + + ANDROID_JPEG, + + ANDROID_LENS, + + ANDROID_LENS_INFO, + + ANDROID_NOISE_REDUCTION, + + ANDROID_QUIRKS, + + ANDROID_REQUEST, + + ANDROID_SCALER, + + ANDROID_SENSOR, + + ANDROID_SENSOR_INFO, + + ANDROID_SHADING, + + ANDROID_STATISTICS, + + ANDROID_STATISTICS_INFO, + + ANDROID_TONEMAP, + + ANDROID_LED, + + ANDROID_INFO, + + ANDROID_BLACK_LEVEL, + + ANDROID_SYNC, + + ANDROID_REPROCESS, + + ANDROID_DEPTH, + + ANDROID_SECTION_COUNT, + + VENDOR_SECTION = 0x8000, + +}; + +/** + * Hierarchy positions in enum space. All vendor extension tags must be + * defined with tag >= VENDOR_SECTION_START + */ +enum CameraMetadataSectionStart : uint32_t { + ANDROID_COLOR_CORRECTION_START = CameraMetadataSection:ANDROID_COLOR_CORRECTION << 16, + + ANDROID_CONTROL_START = CameraMetadataSection:ANDROID_CONTROL << 16, + + ANDROID_DEMOSAIC_START = CameraMetadataSection:ANDROID_DEMOSAIC << 16, + + ANDROID_EDGE_START = CameraMetadataSection:ANDROID_EDGE << 16, + + ANDROID_FLASH_START = CameraMetadataSection:ANDROID_FLASH << 16, + + ANDROID_FLASH_INFO_START = CameraMetadataSection:ANDROID_FLASH_INFO << 16, + + ANDROID_HOT_PIXEL_START = CameraMetadataSection:ANDROID_HOT_PIXEL << 16, + + ANDROID_JPEG_START = CameraMetadataSection:ANDROID_JPEG << 16, + + ANDROID_LENS_START = CameraMetadataSection:ANDROID_LENS << 16, + + ANDROID_LENS_INFO_START = CameraMetadataSection:ANDROID_LENS_INFO << 16, + + ANDROID_NOISE_REDUCTION_START = CameraMetadataSection:ANDROID_NOISE_REDUCTION << 16, + + ANDROID_QUIRKS_START = CameraMetadataSection:ANDROID_QUIRKS << 16, + + ANDROID_REQUEST_START = CameraMetadataSection:ANDROID_REQUEST << 16, + + ANDROID_SCALER_START = CameraMetadataSection:ANDROID_SCALER << 16, + + ANDROID_SENSOR_START = CameraMetadataSection:ANDROID_SENSOR << 16, + + ANDROID_SENSOR_INFO_START = CameraMetadataSection:ANDROID_SENSOR_INFO << 16, + + ANDROID_SHADING_START = CameraMetadataSection:ANDROID_SHADING << 16, + + ANDROID_STATISTICS_START = CameraMetadataSection:ANDROID_STATISTICS << 16, + + ANDROID_STATISTICS_INFO_START = CameraMetadataSection:ANDROID_STATISTICS_INFO << 16, + + ANDROID_TONEMAP_START = CameraMetadataSection:ANDROID_TONEMAP << 16, + + ANDROID_LED_START = CameraMetadataSection:ANDROID_LED << 16, + + ANDROID_INFO_START = CameraMetadataSection:ANDROID_INFO << 16, + + ANDROID_BLACK_LEVEL_START = CameraMetadataSection:ANDROID_BLACK_LEVEL << 16, + + ANDROID_SYNC_START = CameraMetadataSection:ANDROID_SYNC << 16, + + ANDROID_REPROCESS_START = CameraMetadataSection:ANDROID_REPROCESS << 16, + + ANDROID_DEPTH_START = CameraMetadataSection:ANDROID_DEPTH << 16, + + VENDOR_SECTION_START = CameraMetadataSection:VENDOR_SECTION << 16, + +}; + +/** + * Main enum for defining camera metadata tags. New entries must always go + * before the section _END tag to preserve existing enumeration values. In + * addition, the name and type of the tag needs to be added to + * system/media/camera/src/camera_metadata_tag_info.c + */ +enum CameraMetadataTag : uint32_t { + ANDROID_COLOR_CORRECTION_MODE = CameraMetadataSectionStart:ANDROID_COLOR_CORRECTION_START, + + ANDROID_COLOR_CORRECTION_TRANSFORM, + + ANDROID_COLOR_CORRECTION_GAINS, + + ANDROID_COLOR_CORRECTION_ABERRATION_MODE, + + ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, + + ANDROID_COLOR_CORRECTION_END, + + ANDROID_CONTROL_AE_ANTIBANDING_MODE = CameraMetadataSectionStart:ANDROID_CONTROL_START, + + ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, + + ANDROID_CONTROL_AE_LOCK, + + ANDROID_CONTROL_AE_MODE, + + ANDROID_CONTROL_AE_REGIONS, + + ANDROID_CONTROL_AE_TARGET_FPS_RANGE, + + ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, + + ANDROID_CONTROL_AF_MODE, + + ANDROID_CONTROL_AF_REGIONS, + + ANDROID_CONTROL_AF_TRIGGER, + + ANDROID_CONTROL_AWB_LOCK, + + ANDROID_CONTROL_AWB_MODE, + + ANDROID_CONTROL_AWB_REGIONS, + + ANDROID_CONTROL_CAPTURE_INTENT, + + ANDROID_CONTROL_EFFECT_MODE, + + ANDROID_CONTROL_MODE, + + ANDROID_CONTROL_SCENE_MODE, + + ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, + + ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, + + ANDROID_CONTROL_AE_AVAILABLE_MODES, + + ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, + + ANDROID_CONTROL_AE_COMPENSATION_RANGE, + + ANDROID_CONTROL_AE_COMPENSATION_STEP, + + ANDROID_CONTROL_AF_AVAILABLE_MODES, + + ANDROID_CONTROL_AVAILABLE_EFFECTS, + + ANDROID_CONTROL_AVAILABLE_SCENE_MODES, + + ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, + + ANDROID_CONTROL_AWB_AVAILABLE_MODES, + + ANDROID_CONTROL_MAX_REGIONS, + + ANDROID_CONTROL_SCENE_MODE_OVERRIDES, + + ANDROID_CONTROL_AE_PRECAPTURE_ID, + + ANDROID_CONTROL_AE_STATE, + + ANDROID_CONTROL_AF_STATE, + + ANDROID_CONTROL_AF_TRIGGER_ID, + + ANDROID_CONTROL_AWB_STATE, + + ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, + + ANDROID_CONTROL_AE_LOCK_AVAILABLE, + + ANDROID_CONTROL_AWB_LOCK_AVAILABLE, + + ANDROID_CONTROL_AVAILABLE_MODES, + + ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, + + ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, + + ANDROID_CONTROL_ENABLE_ZSL, + + ANDROID_CONTROL_END, + + ANDROID_DEMOSAIC_MODE = CameraMetadataSectionStart:ANDROID_DEMOSAIC_START, + + ANDROID_DEMOSAIC_END, + + ANDROID_EDGE_MODE = CameraMetadataSectionStart:ANDROID_EDGE_START, + + ANDROID_EDGE_STRENGTH, + + ANDROID_EDGE_AVAILABLE_EDGE_MODES, + + ANDROID_EDGE_END, + + ANDROID_FLASH_FIRING_POWER = CameraMetadataSectionStart:ANDROID_FLASH_START, + + ANDROID_FLASH_FIRING_TIME, + + ANDROID_FLASH_MODE, + + ANDROID_FLASH_COLOR_TEMPERATURE, + + ANDROID_FLASH_MAX_ENERGY, + + ANDROID_FLASH_STATE, + + ANDROID_FLASH_END, + + ANDROID_FLASH_INFO_AVAILABLE = CameraMetadataSectionStart:ANDROID_FLASH_INFO_START, + + ANDROID_FLASH_INFO_CHARGE_DURATION, + + ANDROID_FLASH_INFO_END, + + ANDROID_HOT_PIXEL_MODE = CameraMetadataSectionStart:ANDROID_HOT_PIXEL_START, + + ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, + + ANDROID_HOT_PIXEL_END, + + ANDROID_JPEG_GPS_COORDINATES = CameraMetadataSectionStart:ANDROID_JPEG_START, + + ANDROID_JPEG_GPS_PROCESSING_METHOD, + + ANDROID_JPEG_GPS_TIMESTAMP, + + ANDROID_JPEG_ORIENTATION, + + ANDROID_JPEG_QUALITY, + + ANDROID_JPEG_THUMBNAIL_QUALITY, + + ANDROID_JPEG_THUMBNAIL_SIZE, + + ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, + + ANDROID_JPEG_MAX_SIZE, + + ANDROID_JPEG_SIZE, + + ANDROID_JPEG_END, + + ANDROID_LENS_APERTURE = CameraMetadataSectionStart:ANDROID_LENS_START, + + ANDROID_LENS_FILTER_DENSITY, + + ANDROID_LENS_FOCAL_LENGTH, + + ANDROID_LENS_FOCUS_DISTANCE, + + ANDROID_LENS_OPTICAL_STABILIZATION_MODE, + + ANDROID_LENS_FACING, + + ANDROID_LENS_POSE_ROTATION, + + ANDROID_LENS_POSE_TRANSLATION, + + ANDROID_LENS_FOCUS_RANGE, + + ANDROID_LENS_STATE, + + ANDROID_LENS_INTRINSIC_CALIBRATION, + + ANDROID_LENS_RADIAL_DISTORTION, + + ANDROID_LENS_END, + + ANDROID_LENS_INFO_AVAILABLE_APERTURES = CameraMetadataSectionStart:ANDROID_LENS_INFO_START, + + ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES, + + ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, + + ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION, + + ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE, + + ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, + + ANDROID_LENS_INFO_SHADING_MAP_SIZE, + + ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, + + ANDROID_LENS_INFO_END, + + ANDROID_NOISE_REDUCTION_MODE = CameraMetadataSectionStart:ANDROID_NOISE_REDUCTION_START, + + ANDROID_NOISE_REDUCTION_STRENGTH, + + ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, + + ANDROID_NOISE_REDUCTION_END, + + ANDROID_QUIRKS_METERING_CROP_REGION = CameraMetadataSectionStart:ANDROID_QUIRKS_START, + + ANDROID_QUIRKS_TRIGGER_AF_WITH_AUTO, + + ANDROID_QUIRKS_USE_ZSL_FORMAT, + + ANDROID_QUIRKS_USE_PARTIAL_RESULT, + + ANDROID_QUIRKS_PARTIAL_RESULT, + + ANDROID_QUIRKS_END, + + ANDROID_REQUEST_FRAME_COUNT = CameraMetadataSectionStart:ANDROID_REQUEST_START, + + ANDROID_REQUEST_ID, + + ANDROID_REQUEST_INPUT_STREAMS, + + ANDROID_REQUEST_METADATA_MODE, + + ANDROID_REQUEST_OUTPUT_STREAMS, + + ANDROID_REQUEST_TYPE, + + ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, + + ANDROID_REQUEST_MAX_NUM_REPROCESS_STREAMS, + + ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, + + ANDROID_REQUEST_PIPELINE_DEPTH, + + ANDROID_REQUEST_PIPELINE_MAX_DEPTH, + + ANDROID_REQUEST_PARTIAL_RESULT_COUNT, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES, + + ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, + + ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, + + ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, + + ANDROID_REQUEST_END, + + ANDROID_SCALER_CROP_REGION = CameraMetadataSectionStart:ANDROID_SCALER_START, + + ANDROID_SCALER_AVAILABLE_FORMATS, + + ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS, + + ANDROID_SCALER_AVAILABLE_JPEG_SIZES, + + ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, + + ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS, + + ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, + + ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS, + + ANDROID_SCALER_AVAILABLE_RAW_SIZES, + + ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP, + + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + + ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, + + ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, + + ANDROID_SCALER_CROPPING_TYPE, + + ANDROID_SCALER_END, + + ANDROID_SENSOR_EXPOSURE_TIME = CameraMetadataSectionStart:ANDROID_SENSOR_START, + + ANDROID_SENSOR_FRAME_DURATION, + + ANDROID_SENSOR_SENSITIVITY, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT2, + + ANDROID_SENSOR_CALIBRATION_TRANSFORM1, + + ANDROID_SENSOR_CALIBRATION_TRANSFORM2, + + ANDROID_SENSOR_COLOR_TRANSFORM1, + + ANDROID_SENSOR_COLOR_TRANSFORM2, + + ANDROID_SENSOR_FORWARD_MATRIX1, + + ANDROID_SENSOR_FORWARD_MATRIX2, + + ANDROID_SENSOR_BASE_GAIN_FACTOR, + + ANDROID_SENSOR_BLACK_LEVEL_PATTERN, + + ANDROID_SENSOR_MAX_ANALOG_SENSITIVITY, + + ANDROID_SENSOR_ORIENTATION, + + ANDROID_SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS, + + ANDROID_SENSOR_TIMESTAMP, + + ANDROID_SENSOR_TEMPERATURE, + + ANDROID_SENSOR_NEUTRAL_COLOR_POINT, + + ANDROID_SENSOR_NOISE_PROFILE, + + ANDROID_SENSOR_PROFILE_HUE_SAT_MAP, + + ANDROID_SENSOR_PROFILE_TONE_CURVE, + + ANDROID_SENSOR_GREEN_SPLIT, + + ANDROID_SENSOR_TEST_PATTERN_DATA, + + ANDROID_SENSOR_TEST_PATTERN_MODE, + + ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, + + ANDROID_SENSOR_ROLLING_SHUTTER_SKEW, + + ANDROID_SENSOR_OPTICAL_BLACK_REGIONS, + + ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL, + + ANDROID_SENSOR_DYNAMIC_WHITE_LEVEL, + + ANDROID_SENSOR_OPAQUE_RAW_SIZE, + + ANDROID_SENSOR_END, + + ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE = CameraMetadataSectionStart:ANDROID_SENSOR_INFO_START, + + ANDROID_SENSOR_INFO_SENSITIVITY_RANGE, + + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, + + ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE, + + ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, + + ANDROID_SENSOR_INFO_PHYSICAL_SIZE, + + ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, + + ANDROID_SENSOR_INFO_WHITE_LEVEL, + + ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, + + ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED, + + ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, + + ANDROID_SENSOR_INFO_END, + + ANDROID_SHADING_MODE = CameraMetadataSectionStart:ANDROID_SHADING_START, + + ANDROID_SHADING_STRENGTH, + + ANDROID_SHADING_AVAILABLE_MODES, + + ANDROID_SHADING_END, + + ANDROID_STATISTICS_FACE_DETECT_MODE = CameraMetadataSectionStart:ANDROID_STATISTICS_START, + + ANDROID_STATISTICS_HISTOGRAM_MODE, + + ANDROID_STATISTICS_SHARPNESS_MAP_MODE, + + ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE, + + ANDROID_STATISTICS_FACE_IDS, + + ANDROID_STATISTICS_FACE_LANDMARKS, + + ANDROID_STATISTICS_FACE_RECTANGLES, + + ANDROID_STATISTICS_FACE_SCORES, + + ANDROID_STATISTICS_HISTOGRAM, + + ANDROID_STATISTICS_SHARPNESS_MAP, + + ANDROID_STATISTICS_LENS_SHADING_CORRECTION_MAP, + + ANDROID_STATISTICS_LENS_SHADING_MAP, + + ANDROID_STATISTICS_PREDICTED_COLOR_GAINS, + + ANDROID_STATISTICS_PREDICTED_COLOR_TRANSFORM, + + ANDROID_STATISTICS_SCENE_FLICKER, + + ANDROID_STATISTICS_HOT_PIXEL_MAP, + + ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, + + ANDROID_STATISTICS_END, + + ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES = + CameraMetadataSectionStart:ANDROID_STATISTICS_INFO_START, + + ANDROID_STATISTICS_INFO_HISTOGRAM_BUCKET_COUNT, + + ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, + + ANDROID_STATISTICS_INFO_MAX_HISTOGRAM_COUNT, + + ANDROID_STATISTICS_INFO_MAX_SHARPNESS_MAP_VALUE, + + ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE, + + ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, + + ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, + + ANDROID_STATISTICS_INFO_END, + + ANDROID_TONEMAP_CURVE_BLUE = CameraMetadataSectionStart:ANDROID_TONEMAP_START, + + ANDROID_TONEMAP_CURVE_GREEN, + + ANDROID_TONEMAP_CURVE_RED, + + ANDROID_TONEMAP_MODE, + + ANDROID_TONEMAP_MAX_CURVE_POINTS, + + ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES, + + ANDROID_TONEMAP_GAMMA, + + ANDROID_TONEMAP_PRESET_CURVE, + + ANDROID_TONEMAP_END, + + ANDROID_LED_TRANSMIT = CameraMetadataSectionStart:ANDROID_LED_START, + + ANDROID_LED_AVAILABLE_LEDS, + + ANDROID_LED_END, + + ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL = CameraMetadataSectionStart:ANDROID_INFO_START, + + ANDROID_INFO_END, + + ANDROID_BLACK_LEVEL_LOCK = CameraMetadataSectionStart:ANDROID_BLACK_LEVEL_START, + + ANDROID_BLACK_LEVEL_END, + + ANDROID_SYNC_FRAME_NUMBER = CameraMetadataSectionStart:ANDROID_SYNC_START, + + ANDROID_SYNC_MAX_LATENCY, + + ANDROID_SYNC_END, + + ANDROID_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR = CameraMetadataSectionStart:ANDROID_REPROCESS_START, + + ANDROID_REPROCESS_MAX_CAPTURE_STALL, + + ANDROID_REPROCESS_END, + + ANDROID_DEPTH_MAX_DEPTH_SAMPLES = CameraMetadataSectionStart:ANDROID_DEPTH_START, + + ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, + + ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS, + + ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS, + + ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE, + + ANDROID_DEPTH_END, + +}; + +/** + * Enumeration definitions for the various entries that need them + */ +enum CameraMetadataEnumAndroidColorCorrectionMode : uint32_t { + ANDROID_COLOR_CORRECTION_MODE_TRANSFORM_MATRIX, + + ANDROID_COLOR_CORRECTION_MODE_FAST, + + ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY, + +}; + +enum CameraMetadataEnumAndroidColorCorrectionAberrationMode : uint32_t { + ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF, + + ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST, + + ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY, + +}; + +enum CameraMetadataEnumAndroidControlAeAntibandingMode : uint32_t { + ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF, + + ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ, + + ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ, + + ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO, + +}; + +enum CameraMetadataEnumAndroidControlAeLock : uint32_t { + ANDROID_CONTROL_AE_LOCK_OFF, + + ANDROID_CONTROL_AE_LOCK_ON, + +}; + +enum CameraMetadataEnumAndroidControlAeMode : uint32_t { + ANDROID_CONTROL_AE_MODE_OFF, + + ANDROID_CONTROL_AE_MODE_ON, + + ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH, + + ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH, + + ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE, + +}; + +enum CameraMetadataEnumAndroidControlAePrecaptureTrigger : uint32_t { + ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE, + + ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START, + + ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL, + +}; + +enum CameraMetadataEnumAndroidControlAfMode : uint32_t { + ANDROID_CONTROL_AF_MODE_OFF, + + ANDROID_CONTROL_AF_MODE_AUTO, + + ANDROID_CONTROL_AF_MODE_MACRO, + + ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO, + + ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE, + + ANDROID_CONTROL_AF_MODE_EDOF, + +}; + +enum CameraMetadataEnumAndroidControlAfTrigger : uint32_t { + ANDROID_CONTROL_AF_TRIGGER_IDLE, + + ANDROID_CONTROL_AF_TRIGGER_START, + + ANDROID_CONTROL_AF_TRIGGER_CANCEL, + +}; + +enum CameraMetadataEnumAndroidControlAwbLock : uint32_t { + ANDROID_CONTROL_AWB_LOCK_OFF, + + ANDROID_CONTROL_AWB_LOCK_ON, + +}; + +enum CameraMetadataEnumAndroidControlAwbMode : uint32_t { + ANDROID_CONTROL_AWB_MODE_OFF, + + ANDROID_CONTROL_AWB_MODE_AUTO, + + ANDROID_CONTROL_AWB_MODE_INCANDESCENT, + + ANDROID_CONTROL_AWB_MODE_FLUORESCENT, + + ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT, + + ANDROID_CONTROL_AWB_MODE_DAYLIGHT, + + ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT, + + ANDROID_CONTROL_AWB_MODE_TWILIGHT, + + ANDROID_CONTROL_AWB_MODE_SHADE, + +}; + +enum CameraMetadataEnumAndroidControlCaptureIntent : uint32_t { + ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM, + + ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW, + + ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE, + + ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD, + + ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT, + + ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG, + + ANDROID_CONTROL_CAPTURE_INTENT_MANUAL, + +}; + +enum CameraMetadataEnumAndroidControlEffectMode : uint32_t { + ANDROID_CONTROL_EFFECT_MODE_OFF, + + ANDROID_CONTROL_EFFECT_MODE_MONO, + + ANDROID_CONTROL_EFFECT_MODE_NEGATIVE, + + ANDROID_CONTROL_EFFECT_MODE_SOLARIZE, + + ANDROID_CONTROL_EFFECT_MODE_SEPIA, + + ANDROID_CONTROL_EFFECT_MODE_POSTERIZE, + + ANDROID_CONTROL_EFFECT_MODE_WHITEBOARD, + + ANDROID_CONTROL_EFFECT_MODE_BLACKBOARD, + + ANDROID_CONTROL_EFFECT_MODE_AQUA, + +}; + +enum CameraMetadataEnumAndroidControlMode : uint32_t { + ANDROID_CONTROL_MODE_OFF, + + ANDROID_CONTROL_MODE_AUTO, + + ANDROID_CONTROL_MODE_USE_SCENE_MODE, + + ANDROID_CONTROL_MODE_OFF_KEEP_STATE, + +}; + +enum CameraMetadataEnumAndroidControlSceneMode : uint32_t { + ANDROID_CONTROL_SCENE_MODE_DISABLED = 0, + + ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY, + + ANDROID_CONTROL_SCENE_MODE_ACTION, + + ANDROID_CONTROL_SCENE_MODE_PORTRAIT, + + ANDROID_CONTROL_SCENE_MODE_LANDSCAPE, + + ANDROID_CONTROL_SCENE_MODE_NIGHT, + + ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT, + + ANDROID_CONTROL_SCENE_MODE_THEATRE, + + ANDROID_CONTROL_SCENE_MODE_BEACH, + + ANDROID_CONTROL_SCENE_MODE_SNOW, + + ANDROID_CONTROL_SCENE_MODE_SUNSET, + + ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO, + + ANDROID_CONTROL_SCENE_MODE_FIREWORKS, + + ANDROID_CONTROL_SCENE_MODE_SPORTS, + + ANDROID_CONTROL_SCENE_MODE_PARTY, + + ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT, + + ANDROID_CONTROL_SCENE_MODE_BARCODE, + + ANDROID_CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO, + + ANDROID_CONTROL_SCENE_MODE_HDR, + + ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY_LOW_LIGHT, + + ANDROID_CONTROL_SCENE_MODE_DEVICE_CUSTOM_START = 100, + + ANDROID_CONTROL_SCENE_MODE_DEVICE_CUSTOM_END = 127, + +}; + +enum CameraMetadataEnumAndroidControlVideoStabilizationMode : uint32_t { + ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF, + + ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON, + +}; + +enum CameraMetadataEnumAndroidControlAeState : uint32_t { + ANDROID_CONTROL_AE_STATE_INACTIVE, + + ANDROID_CONTROL_AE_STATE_SEARCHING, + + ANDROID_CONTROL_AE_STATE_CONVERGED, + + ANDROID_CONTROL_AE_STATE_LOCKED, + + ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED, + + ANDROID_CONTROL_AE_STATE_PRECAPTURE, + +}; + +enum CameraMetadataEnumAndroidControlAfState : uint32_t { + ANDROID_CONTROL_AF_STATE_INACTIVE, + + ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN, + + ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED, + + ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN, + + ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED, + + ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED, + + ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED, + +}; + +enum CameraMetadataEnumAndroidControlAwbState : uint32_t { + ANDROID_CONTROL_AWB_STATE_INACTIVE, + + ANDROID_CONTROL_AWB_STATE_SEARCHING, + + ANDROID_CONTROL_AWB_STATE_CONVERGED, + + ANDROID_CONTROL_AWB_STATE_LOCKED, + +}; + +enum CameraMetadataEnumAndroidControlAeLockAvailable : uint32_t { + ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE, + + ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE, + +}; + +enum CameraMetadataEnumAndroidControlAwbLockAvailable : uint32_t { + ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE, + + ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE, + +}; + +enum CameraMetadataEnumAndroidControlEnableZsl : uint32_t { + ANDROID_CONTROL_ENABLE_ZSL_FALSE, + + ANDROID_CONTROL_ENABLE_ZSL_TRUE, + +}; + +enum CameraMetadataEnumAndroidDemosaicMode : uint32_t { + ANDROID_DEMOSAIC_MODE_FAST, + + ANDROID_DEMOSAIC_MODE_HIGH_QUALITY, + +}; + +enum CameraMetadataEnumAndroidEdgeMode : uint32_t { + ANDROID_EDGE_MODE_OFF, + + ANDROID_EDGE_MODE_FAST, + + ANDROID_EDGE_MODE_HIGH_QUALITY, + + ANDROID_EDGE_MODE_ZERO_SHUTTER_LAG, + +}; + +enum CameraMetadataEnumAndroidFlashMode : uint32_t { + ANDROID_FLASH_MODE_OFF, + + ANDROID_FLASH_MODE_SINGLE, + + ANDROID_FLASH_MODE_TORCH, + +}; + +enum CameraMetadataEnumAndroidFlashState : uint32_t { + ANDROID_FLASH_STATE_UNAVAILABLE, + + ANDROID_FLASH_STATE_CHARGING, + + ANDROID_FLASH_STATE_READY, + + ANDROID_FLASH_STATE_FIRED, + + ANDROID_FLASH_STATE_PARTIAL, + +}; + +enum CameraMetadataEnumAndroidFlashInfoAvailable : uint32_t { + ANDROID_FLASH_INFO_AVAILABLE_FALSE, + + ANDROID_FLASH_INFO_AVAILABLE_TRUE, + +}; + +enum CameraMetadataEnumAndroidHotPixelMode : uint32_t { + ANDROID_HOT_PIXEL_MODE_OFF, + + ANDROID_HOT_PIXEL_MODE_FAST, + + ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY, + +}; + +enum CameraMetadataEnumAndroidLensOpticalStabilizationMode : uint32_t { + ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF, + + ANDROID_LENS_OPTICAL_STABILIZATION_MODE_ON, + +}; + +enum CameraMetadataEnumAndroidLensFacing : uint32_t { + ANDROID_LENS_FACING_FRONT, + + ANDROID_LENS_FACING_BACK, + + ANDROID_LENS_FACING_EXTERNAL, + +}; + +enum CameraMetadataEnumAndroidLensState : uint32_t { + ANDROID_LENS_STATE_STATIONARY, + + ANDROID_LENS_STATE_MOVING, + +}; + +enum CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration : uint32_t { + ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED, + + ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE, + + ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED, + +}; + +enum CameraMetadataEnumAndroidNoiseReductionMode : uint32_t { + ANDROID_NOISE_REDUCTION_MODE_OFF, + + ANDROID_NOISE_REDUCTION_MODE_FAST, + + ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY, + + ANDROID_NOISE_REDUCTION_MODE_MINIMAL, + + ANDROID_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG, + +}; + +enum CameraMetadataEnumAndroidQuirksPartialResult : uint32_t { + ANDROID_QUIRKS_PARTIAL_RESULT_FINAL, + + ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL, + +}; + +enum CameraMetadataEnumAndroidRequestMetadataMode : uint32_t { + ANDROID_REQUEST_METADATA_MODE_NONE, + + ANDROID_REQUEST_METADATA_MODE_FULL, + +}; + +enum CameraMetadataEnumAndroidRequestType : uint32_t { + ANDROID_REQUEST_TYPE_CAPTURE, + + ANDROID_REQUEST_TYPE_REPROCESS, + +}; + +enum CameraMetadataEnumAndroidRequestAvailableCapabilities : uint32_t { + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT, + + ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO, + +}; + +enum CameraMetadataEnumAndroidScalerAvailableFormats : uint32_t { + ANDROID_SCALER_AVAILABLE_FORMATS_RAW16 = 0x20, + + ANDROID_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE = 0x24, + + ANDROID_SCALER_AVAILABLE_FORMATS_YV12 = 0x32315659, + + ANDROID_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP = 0x11, + + ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED = 0x22, + + ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888 = 0x23, + + ANDROID_SCALER_AVAILABLE_FORMATS_BLOB = 0x21, + +}; + +enum CameraMetadataEnumAndroidScalerAvailableStreamConfigurations : uint32_t { + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT, + + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT, + +}; + +enum CameraMetadataEnumAndroidScalerCroppingType : uint32_t { + ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY, + + ANDROID_SCALER_CROPPING_TYPE_FREEFORM, + +}; + +enum CameraMetadataEnumAndroidSensorReferenceIlluminant1 : uint32_t { + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT = 1, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FLUORESCENT = 2, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_TUNGSTEN = 3, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FLASH = 4, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FINE_WEATHER = 9, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_CLOUDY_WEATHER = 10, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_SHADE = 11, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT_FLUORESCENT = 12, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAY_WHITE_FLUORESCENT = 13, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_COOL_WHITE_FLUORESCENT = 14, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_WHITE_FLUORESCENT = 15, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_A = 17, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_B = 18, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_C = 19, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D55 = 20, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D65 = 21, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D75 = 22, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D50 = 23, + + ANDROID_SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN = 24, + +}; + +enum CameraMetadataEnumAndroidSensorTestPatternMode : uint32_t { + ANDROID_SENSOR_TEST_PATTERN_MODE_OFF, + + ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR, + + ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS, + + ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY, + + ANDROID_SENSOR_TEST_PATTERN_MODE_PN9, + + ANDROID_SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256, + +}; + +enum CameraMetadataEnumAndroidSensorInfoColorFilterArrangement : uint32_t { + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB, + + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG, + + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG, + + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR, + + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB, + +}; + +enum CameraMetadataEnumAndroidSensorInfoTimestampSource : uint32_t { + ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN, + + ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME, + +}; + +enum CameraMetadataEnumAndroidSensorInfoLensShadingApplied : uint32_t { + ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED_FALSE, + + ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED_TRUE, + +}; + +enum CameraMetadataEnumAndroidShadingMode : uint32_t { + ANDROID_SHADING_MODE_OFF, + + ANDROID_SHADING_MODE_FAST, + + ANDROID_SHADING_MODE_HIGH_QUALITY, + +}; + +enum CameraMetadataEnumAndroidStatisticsFaceDetectMode : uint32_t { + ANDROID_STATISTICS_FACE_DETECT_MODE_OFF, + + ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE, + + ANDROID_STATISTICS_FACE_DETECT_MODE_FULL, + +}; + +enum CameraMetadataEnumAndroidStatisticsHistogramMode : uint32_t { + ANDROID_STATISTICS_HISTOGRAM_MODE_OFF, + + ANDROID_STATISTICS_HISTOGRAM_MODE_ON, + +}; + +enum CameraMetadataEnumAndroidStatisticsSharpnessMapMode : uint32_t { + ANDROID_STATISTICS_SHARPNESS_MAP_MODE_OFF, + + ANDROID_STATISTICS_SHARPNESS_MAP_MODE_ON, + +}; + +enum CameraMetadataEnumAndroidStatisticsHotPixelMapMode : uint32_t { + ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF, + + ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_ON, + +}; + +enum CameraMetadataEnumAndroidStatisticsSceneFlicker : uint32_t { + ANDROID_STATISTICS_SCENE_FLICKER_NONE, + + ANDROID_STATISTICS_SCENE_FLICKER_50HZ, + + ANDROID_STATISTICS_SCENE_FLICKER_60HZ, + +}; + +enum CameraMetadataEnumAndroidStatisticsLensShadingMapMode : uint32_t { + ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF, + + ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON, + +}; + +enum CameraMetadataEnumAndroidTonemapMode : uint32_t { + ANDROID_TONEMAP_MODE_CONTRAST_CURVE, + + ANDROID_TONEMAP_MODE_FAST, + + ANDROID_TONEMAP_MODE_HIGH_QUALITY, + + ANDROID_TONEMAP_MODE_GAMMA_VALUE, + + ANDROID_TONEMAP_MODE_PRESET_CURVE, + +}; + +enum CameraMetadataEnumAndroidTonemapPresetCurve : uint32_t { + ANDROID_TONEMAP_PRESET_CURVE_SRGB, + + ANDROID_TONEMAP_PRESET_CURVE_REC709, + +}; + +enum CameraMetadataEnumAndroidLedTransmit : uint32_t { + ANDROID_LED_TRANSMIT_OFF, + + ANDROID_LED_TRANSMIT_ON, + +}; + +enum CameraMetadataEnumAndroidLedAvailableLeds : uint32_t { + ANDROID_LED_AVAILABLE_LEDS_TRANSMIT, + +}; + +enum CameraMetadataEnumAndroidInfoSupportedHardwareLevel : uint32_t { + ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED, + + ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL, + + ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY, + + ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3, + +}; + +enum CameraMetadataEnumAndroidBlackLevelLock : uint32_t { + ANDROID_BLACK_LEVEL_LOCK_OFF, + + ANDROID_BLACK_LEVEL_LOCK_ON, + +}; + +enum CameraMetadataEnumAndroidSyncFrameNumber : uint32_t { + ANDROID_SYNC_FRAME_NUMBER_CONVERGING = -1, + + ANDROID_SYNC_FRAME_NUMBER_UNKNOWN = -2, + +}; + +enum CameraMetadataEnumAndroidSyncMaxLatency : uint32_t { + ANDROID_SYNC_MAX_LATENCY_PER_FRAME_CONTROL = 0, + + ANDROID_SYNC_MAX_LATENCY_UNKNOWN = -1, + +}; + +enum CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations : uint32_t { + ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT, + + ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_INPUT, + +}; + +enum CameraMetadataEnumAndroidDepthDepthIsExclusive : uint32_t { + ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_FALSE, + + ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_TRUE, + +};
diff --git a/camera/metadata/README.md b/camera/metadata/README.md new file mode 100644 index 0000000..752973d --- /dev/null +++ b/camera/metadata/README.md
@@ -0,0 +1,19 @@ +## Camera Metadata Interface ## +--- + +## Overview: ## + +The camera.metadata interface is used by the Android camera service, +camera provider and camera devices to retrieve static camera information and issue +camera capture controls. + +See the docs.html for each version for the detailed description of each metadata +specification. +## Version history: ## + +### @3.2: + +HIDL version of the baseline camera metadata interface, required by +camera.provider@2.4 and camera.device@3.2 onwards. + +
diff --git a/camera/provider/2.4/Android.bp b/camera/provider/2.4/Android.bp new file mode 100644 index 0000000..3369a3c --- /dev/null +++ b/camera/provider/2.4/Android.bp
@@ -0,0 +1,72 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.camera.provider@2.4_hal", + srcs: [ + "ICameraProvider.hal", + "ICameraProviderCallback.hal", + ], +} + +genrule { + name: "android.hardware.camera.provider@2.4_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.provider@2.4", + srcs: [ + ":android.hardware.camera.provider@2.4_hal", + ], + out: [ + "android/hardware/camera/provider/2.4/CameraProviderAll.cpp", + "android/hardware/camera/provider/2.4/CameraProviderCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.camera.provider@2.4_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.camera.provider@2.4", + srcs: [ + ":android.hardware.camera.provider@2.4_hal", + ], + out: [ + "android/hardware/camera/provider/2.4/ICameraProvider.h", + "android/hardware/camera/provider/2.4/IHwCameraProvider.h", + "android/hardware/camera/provider/2.4/BnHwCameraProvider.h", + "android/hardware/camera/provider/2.4/BpHwCameraProvider.h", + "android/hardware/camera/provider/2.4/BsCameraProvider.h", + "android/hardware/camera/provider/2.4/ICameraProviderCallback.h", + "android/hardware/camera/provider/2.4/IHwCameraProviderCallback.h", + "android/hardware/camera/provider/2.4/BnHwCameraProviderCallback.h", + "android/hardware/camera/provider/2.4/BpHwCameraProviderCallback.h", + "android/hardware/camera/provider/2.4/BsCameraProviderCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.camera.provider@2.4", + generated_sources: ["android.hardware.camera.provider@2.4_genc++"], + generated_headers: ["android.hardware.camera.provider@2.4_genc++_headers"], + export_generated_headers: ["android.hardware.camera.provider@2.4_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.camera.common@1.0", + "android.hardware.camera.device@1.0", + "android.hardware.camera.device@3.2", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.camera.common@1.0", + "android.hardware.camera.device@1.0", + "android.hardware.camera.device@3.2", + "android.hidl.base@1.0", + ], +}
diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal new file mode 100644 index 0000000..3015b7d --- /dev/null +++ b/camera/provider/2.4/ICameraProvider.hal
@@ -0,0 +1,188 @@ +/* + * Copyright (C) 2016 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.camera.provider@2.4; + +import ICameraProviderCallback; +import android.hardware.camera.common@1.0::types; +import android.hardware.camera.device@1.0::ICameraDevice; +import android.hardware.camera.device@3.2::ICameraDevice; + +/** + * Camera provider HAL, which enumerates the available individual camera devices + * known to the provider, and provides updates about changes to device status, + * such as connection, disconnection, or torch mode enable/disable. + * + * The provider is responsible for generating a list of camera device service + * names that can then be opened via the hardware service manager. + * + * Multiple camera provider HALs may be present in a single system. + * For discovery, the service names, and process names, must be of the form + * "android.hardware.camera.provider@<major>.<minor>/<type>/<instance>" + * where + * - <major>/<minor> is the provider HAL HIDL version, + * - <type> is the type of devices this provider knows about, such as + * "internal", "legacy", "usb", or "remote" + * - <instance> is a non-negative integer starting from 0 to disambiguate + * between multiple HALs of the same type. + * + * The "legacy" type is only used for passthrough legacy HAL mode, and must + * not be used by a standalone binderized HAL. + * + * The device instance names enumerated by the provider must be of the form + * "device@<major>.<minor>/<type>/<id>" where + * <major>/<minor> is the HIDL version of the interface. <id> is either a small + * incrementing integer for "internal" device types, with 0 being the main + * back-facing camera and 1 being the main front-facing camera, if they exist. + * Or, for external devices such as type "usb", a unique serial number that can + * be used to identify the device reliably when it is disconnected and + * reconnected. Multiple providers may not enumerate the same device ID. + * + */ +interface ICameraProvider { + + /** + * setCallback: + * + * Provide a callback interface to the HAL provider to inform framework of + * asynchronous camera events. The framework must call this function once + * during camera service startup, before any other calls to the provider + * (note that in case the camera service restarts, this method must be + * invoked again during its startup). + * + * @param callback + * A non-null callback interface to invoke when camera events occur. + * @return status + * Status code for the operation, one of: + * OK: + * On success + * INTERNAL_ERROR: + * An unexpected internal error occurred while setting the callbacks + * ILLEGAL_ARGUMENT: + * The callback argument is invalid (for example, null). + * + */ + setCallback(ICameraProviderCallback callback) generates (Status status); + + /** + * getVendorTags: + * + * Retrieve all vendor tags supported by devices discoverable through this + * provider. The tags are grouped into sections. + * + * @return status + * Status code for the operation, one of: + * OK: + * On success + * INTERNAL_ERROR: + * An unexpected internal error occurred while setting the callbacks + * @return sections + * The supported vendor tag sections; empty if there are no supported + * vendor tags, or status is not OK. + * + */ + getVendorTags() generates (Status status, vec<VendorTagSection> sections); + + /** + * getCameraDeviceList: + * + * Returns the list of internal camera device interfaces known to this + * camera provider. These devices can then be accessed via the hardware + * service manager. + * + * External camera devices (camera facing EXTERNAL) must be reported through + * the device status change callback, not in this list. Only devices with + * facing BACK or FRONT must be listed here. + * + * @return status Status code for the operation, one of: + * OK: + * On a succesful generation of camera ID list + * INTERNAL_ERROR: + * A camera ID list cannot be created. This may be due to + * a failure to initialize the camera subsystem, for example. + * @return cameraDeviceServiceNames The vector of internal camera device + * names known to this provider. + */ + getCameraIdList() + generates (Status status, vec<string> cameraDeviceNames); + + /** + * isSetTorchModeSupported: + * + * Returns if the camera devices known to this camera provider support + * setTorchMode API or not. If the provider does not support setTorchMode + * API, calling to setTorchMode will return METHOD_NOT_SUPPORTED. + * + * Note that not every camera device has a flash unit, so even this API + * returns true, setTorchMode call might still fail due to the camera device + * does not have a flash unit. In such case, the returned status will be + * OPERATION_NOT_SUPPORTED. + * + * @return status Status code for the operation, one of: + * OK: + * On a succesful call + * INTERNAL_ERROR: + * Torch API support cannot be queried. This may be due to + * a failure to initialize the camera subsystem, for example. + * @return support Whether the camera devices known to this provider + * supports setTorchMode API or not. + * + */ + isSetTorchModeSupported() generates (Status status, bool support); + + /** + * getCameraDeviceInterface_VN_x: + * + * Return a android.hardware.camera.device@N.x/ICameraDevice interface for + * the requested device name. This does not power on the camera device, but + * simply acquires the interface for querying the device static information, + * or to additionally open the device for active use. + * + * A separate method is required for each major revision of the camera device + * HAL interface, since they are not compatible with each other. + * + * Valid device names for this provider can be obtained via either + * getCameraIdList(), or via availability callbacks from + * ICameraProviderCallback::cameraDeviceStatusChange(). + * + * The returned interface must be of the highest defined minor version for + * the major version; it's the responsibility of the HAL client to ensure + * they do not use methods/etc that are not valid for the actual minor + * version of the device. + * + * @param cameraDeviceName the name of the device to get an interface to. + * @return status Status code for the operation, one of: + * OK: + * On a succesful generation of camera ID list + * ILLEGAL_ARGUMENT: + * This device name is unknown, or has been disconnected + * OPERATION_NOT_SUPPORTED: + * The specified device does not support this major version of the + * HAL interface. + * INTERNAL_ERROR: + * A camera interface cannot be returned due to an unexpected + * internal error. + * @return device The inteface to this camera device, or null in case of + * error. + */ + getCameraDeviceInterface_V1_x(string cameraDeviceName) generates + (Status status, + android.hardware.camera.device@1.0::ICameraDevice device); + getCameraDeviceInterface_V3_x(string cameraDeviceName) generates + (Status status, + android.hardware.camera.device@3.2::ICameraDevice device); + +};
diff --git a/camera/provider/2.4/ICameraProviderCallback.hal b/camera/provider/2.4/ICameraProviderCallback.hal new file mode 100644 index 0000000..63dd3c5 --- /dev/null +++ b/camera/provider/2.4/ICameraProviderCallback.hal
@@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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.camera.provider@2.4; + +import android.hardware.camera.common@1.0::types; + +/** + * Callback functions for a camera provider HAL to use to inform the camera + * service of changes to the camera subsystem. + */ +interface ICameraProviderCallback { + + /** + * cameraDeviceStatusChange: + * + * Callback to the camera service to indicate that the state of a specific + * camera device has changed. + * + * On camera service startup, when ICameraProvider::setCallback is invoked, + * the camera service must assume that all internal camera devices are in + * the CAMERA_DEVICE_STATUS_PRESENT state. + * + * The provider must call this method to inform the camera service of any + * initially NOT_PRESENT devices, and of any external camera devices that + * are already present, as soon as the callbacks are available through + * setCallback. + * + * @param cameraDeviceServiceName The name of the camera device that has a + * new status. + * @param newStatus The new status that device is in. + * + */ + cameraDeviceStatusChange(string cameraDeviceName, + CameraDeviceStatus newStatus); + + /** + * torchModeStatusChange: + * + * Callback to the camera service to indicate that the state of the torch + * mode of the flash unit associated with a specific camera device has + * changed. At provider registration time, the camera service must assume + * the torch modes are in the TORCH_MODE_STATUS_AVAILABLE_OFF state if + * android.flash.info.available is reported as true via the + * ICameraDevice::getCameraCharacteristics call. + * + * @param cameraDeviceServiceName The name of the camera device that has a + * new status. + * @param newStatus The new status that device is in. + * + */ + torchModeStatusChange(string cameraDeviceName, + TorchModeStatus newStatus); + +};
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp new file mode 100644 index 0000000..42dec4d --- /dev/null +++ b/camera/provider/2.4/default/Android.bp
@@ -0,0 +1,45 @@ +cc_library_shared { + name: "android.hardware.camera.provider@2.4-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["CameraProvider.cpp"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libutils", + "libcutils", + "android.hardware.camera.device@1.0", + "android.hardware.camera.device@3.2", + "camera.device@1.0-impl", + "camera.device@3.2-impl", + "android.hardware.camera.provider@2.4", + "android.hardware.camera.common@1.0", + "liblog", + "libhardware", + "libcamera_metadata" + ], + static_libs: [ + "android.hardware.camera.common@1.0-helper" + ] +} + +cc_binary { + name: "android.hardware.camera.provider@2.4-service", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["service.cpp"], + compile_multilib: "32", + init_rc: ["android.hardware.camera.provider@2.4-service.rc"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + "android.hardware.camera.device@1.0", + "android.hardware.camera.device@3.2", + "android.hardware.camera.provider@2.4", + "android.hardware.camera.common@1.0", + ], +}
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp new file mode 100644 index 0000000..ad9f0b8 --- /dev/null +++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -0,0 +1,458 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "CamProvider@2.4-impl" +#include <android/log.h> + +#include "CameraProvider.h" +#include "CameraDevice_1_0.h" +#include "CameraDevice_3_2.h" +#include <string.h> +#include <utils/Trace.h> + + +namespace android { +namespace hardware { +namespace camera { +namespace provider { +namespace V2_4 { +namespace implementation { + +namespace { +const char *kLegacyProviderName = "legacy/0"; +// "device@<version>/legacy/<id>" +const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)"); +const char *kHAL3_2 = "3.2"; +const char *kHAL1_0 = "1.0"; +const int kMaxCameraDeviceNameLen = 128; +const int kMaxCameraIdLen = 16; + +} // anonymous namespace + +using ::android::hardware::camera::common::V1_0::CameraMetadataType; +using ::android::hardware::camera::common::V1_0::Status; + +/** + * static callback forwarding methods from HAL to instance + */ +void CameraProvider::sCameraDeviceStatusChange( + const struct camera_module_callbacks* callbacks, + int camera_id, + int new_status) { + CameraProvider* cp = const_cast<CameraProvider*>( + static_cast<const CameraProvider*>(callbacks)); + + if (cp == nullptr) { + ALOGE("%s: callback ops is null", __FUNCTION__); + return; + } + + Mutex::Autolock _l(cp->mCbLock); + char cameraId[kMaxCameraIdLen]; + snprintf(cameraId, sizeof(cameraId), "%d", camera_id); + std::string cameraIdStr(cameraId); + cp->mCameraStatusMap[cameraIdStr] = (camera_device_status_t) new_status; + if (cp->mCallbacks != nullptr) { + CameraDeviceStatus status = (CameraDeviceStatus) new_status; + for (auto const& deviceNamePair : cp->mCameraDeviceNames) { + if (cameraIdStr.compare(deviceNamePair.first) == 0) { + cp->mCallbacks->cameraDeviceStatusChange( + deviceNamePair.second, status); + } + } + } +} + +void CameraProvider::sTorchModeStatusChange( + const struct camera_module_callbacks* callbacks, + const char* camera_id, + int new_status) { + CameraProvider* cp = const_cast<CameraProvider*>( + static_cast<const CameraProvider*>(callbacks)); + + if (cp == nullptr) { + ALOGE("%s: callback ops is null", __FUNCTION__); + return; + } + + Mutex::Autolock _l(cp->mCbLock); + if (cp->mCallbacks != nullptr) { + std::string cameraIdStr(camera_id); + TorchModeStatus status = (TorchModeStatus) new_status; + for (auto const& deviceNamePair : cp->mCameraDeviceNames) { + if (cameraIdStr.compare(deviceNamePair.first) == 0) { + cp->mCallbacks->torchModeStatusChange( + deviceNamePair.second, status); + } + } + } +} + +Status CameraProvider::getHidlStatus(int status) { + switch (status) { + case 0: return Status::OK; + case -ENODEV: return Status::INTERNAL_ERROR; + case -EINVAL: return Status::ILLEGAL_ARGUMENT; + default: + ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status); + return Status::INTERNAL_ERROR; + } +} + +bool CameraProvider::matchDeviceName(const hidl_string& deviceName, std::smatch& sm) { + std::string deviceNameStd(deviceName.c_str()); + return std::regex_match(deviceNameStd, sm, kDeviceNameRE); +} + +std::string CameraProvider::getLegacyCameraId(const hidl_string& deviceName) { + std::smatch sm; + bool match = matchDeviceName(deviceName, sm); + if (!match) { + return std::string(""); + } + return sm[2]; +} + +int CameraProvider::getCameraDeviceVersion(const hidl_string& deviceName) { + std::smatch sm; + bool match = matchDeviceName(deviceName, sm); + if (!match) { + return -1; + } + if (sm[1].compare(kHAL3_2) == 0) { + // maybe switched to 3.4 or define the hidl version enum later + return CAMERA_DEVICE_API_VERSION_3_2; + } else if (sm[1].compare(kHAL1_0) == 0) { + return CAMERA_DEVICE_API_VERSION_1_0; + } + return 0; +} + +std::string CameraProvider::getHidlDeviceName( + std::string cameraId, int deviceVersion) { + // Maybe consider create a version check method and SortedVec to speed up? + if (deviceVersion != CAMERA_DEVICE_API_VERSION_1_0 && + deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 && + deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 && + deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 ) { + return hidl_string(""); + } + const char* versionStr = (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) ? kHAL1_0 : kHAL3_2; + char deviceName[kMaxCameraDeviceNameLen]; + snprintf(deviceName, sizeof(deviceName), "device@%s/legacy/%s", + versionStr, cameraId.c_str()); + return deviceName; +} + +CameraProvider::CameraProvider() : + camera_module_callbacks_t({sCameraDeviceStatusChange, + sTorchModeStatusChange}) { + mInitFailed = initialize(); +} + +CameraProvider::~CameraProvider() {} + +bool CameraProvider::initialize() { + camera_module_t *rawModule; + int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID, + (const hw_module_t **)&rawModule); + if (err < 0) { + ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err)); + return true; + } + + mModule = new CameraModule(rawModule); + err = mModule->init(); + if (err != OK) { + ALOGE("Could not initialize camera HAL module: %d (%s)", err, strerror(-err)); + mModule.clear(); + return true; + } + ALOGI("Loaded \"%s\" camera module", mModule->getModuleName()); + + // Setup callback now because we are going to try openLegacy next + err = mModule->setCallbacks(this); + if (err != OK) { + ALOGE("Could not set camera module callback: %d (%s)", err, strerror(-err)); + mModule.clear(); + return true; + } + + mNumberOfLegacyCameras = mModule->getNumberOfCameras(); + for (int i = 0; i < mNumberOfLegacyCameras; i++) { + char cameraId[kMaxCameraIdLen]; + snprintf(cameraId, sizeof(cameraId), "%d", i); + std::string cameraIdStr(cameraId); + mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT; + mCameraIds.add(cameraIdStr); + + // initialize mCameraDeviceNames and mOpenLegacySupported + mOpenLegacySupported[cameraIdStr] = false; + int deviceVersion = mModule->getDeviceVersion(i); + mCameraDeviceNames.add( + std::make_pair(cameraIdStr, + getHidlDeviceName(cameraIdStr, deviceVersion))); + if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 && + mModule->isOpenLegacyDefined()) { + // try open_legacy to see if it actually works + struct hw_device_t* halDev = nullptr; + int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev); + if (ret == 0) { + mOpenLegacySupported[cameraIdStr] = true; + halDev->close(halDev); + mCameraDeviceNames.add( + std::make_pair(cameraIdStr, + getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0))); + } else if (ret == -EBUSY || ret == -EUSERS) { + // Looks like this provider instance is not initialized during + // system startup and there are other camera users already. + // Not a good sign but not fatal. + ALOGW("%s: open_legacy try failed!", __FUNCTION__); + } + } + } + + // Setup vendor tags here so HAL can setup vendor keys in camera characteristics + VendorTagDescriptor::clearGlobalVendorTagDescriptor(); + if (!setUpVendorTags()) { + ALOGE("%s: Vendor tag setup failed, will not be available.", __FUNCTION__); + } + return false; // mInitFailed +} + +bool CameraProvider::setUpVendorTags() { + ATRACE_CALL(); + vendor_tag_ops_t vOps = vendor_tag_ops_t(); + + // Check if vendor operations have been implemented + if (!mModule->isVendorTagDefined()) { + ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__); + return true; + } + + mModule->getVendorTagOps(&vOps); + + // Ensure all vendor operations are present + if (vOps.get_tag_count == nullptr || vOps.get_all_tags == nullptr || + vOps.get_section_name == nullptr || vOps.get_tag_name == nullptr || + vOps.get_tag_type == nullptr) { + ALOGE("%s: Vendor tag operations not fully defined. Ignoring definitions." + , __FUNCTION__); + return false; + } + + // Read all vendor tag definitions into a descriptor + sp<VendorTagDescriptor> desc; + status_t res; + if ((res = VendorTagDescriptor::createDescriptorFromOps(&vOps, /*out*/desc)) + != OK) { + ALOGE("%s: Could not generate descriptor from vendor tag operations," + "received error %s (%d). Camera clients will not be able to use" + "vendor tags", __FUNCTION__, strerror(res), res); + return false; + } + + // Set the global descriptor to use with camera metadata + VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc); + const SortedVector<String8>* sectionNames = desc->getAllSectionNames(); + size_t numSections = sectionNames->size(); + std::vector<std::vector<VendorTag>> tagsBySection(numSections); + int tagCount = desc->getTagCount(); + std::vector<uint32_t> tags(tagCount); + desc->getTagArray(tags.data()); + for (int i = 0; i < tagCount; i++) { + VendorTag vt; + vt.tagId = tags[i]; + vt.tagName = desc->getTagName(tags[i]); + vt.tagType = (CameraMetadataType) desc->getTagType(tags[i]); + ssize_t sectionIdx = desc->getSectionIndex(tags[i]); + tagsBySection[sectionIdx].push_back(vt); + } + mVendorTagSections.resize(numSections); + for (size_t s = 0; s < numSections; s++) { + mVendorTagSections[s].sectionName = (*sectionNames)[s].string(); + mVendorTagSections[s].tags = tagsBySection[s]; + } + return true; +} + +// Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. +Return<Status> CameraProvider::setCallback(const sp<ICameraProviderCallback>& callback) { + Mutex::Autolock _l(mCbLock); + mCallbacks = callback; + return Status::OK; +} + +Return<void> CameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) { + _hidl_cb(Status::OK, mVendorTagSections); + return Void(); +} + +Return<void> CameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) { + std::vector<hidl_string> deviceNameList; + for (auto const& deviceNamePair : mCameraDeviceNames) { + if (mCameraStatusMap[deviceNamePair.first] == CAMERA_DEVICE_STATUS_PRESENT) { + deviceNameList.push_back(deviceNamePair.second); + } + } + hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList); + _hidl_cb(Status::OK, hidlDeviceNameList); + return Void(); +} + +Return<void> CameraProvider::isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) { + bool support = mModule->isSetTorchModeSupported(); + _hidl_cb (Status::OK, support); + return Void(); +} + +Return<void> CameraProvider::getCameraDeviceInterface_V1_x( + const hidl_string& cameraDeviceName, getCameraDeviceInterface_V1_x_cb _hidl_cb) { + std::smatch sm; + bool match = matchDeviceName(cameraDeviceName, sm); + if (!match) { + _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); + return Void(); + } + + std::string cameraId = sm[2]; + std::string deviceVersion = sm[1]; + std::string deviceName(cameraDeviceName.c_str()); + ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName)); + if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch + Status status = Status::OK; + ssize_t idx = mCameraIds.indexOf(cameraId); + if (idx == NAME_NOT_FOUND) { + ALOGE("%s: cannot find camera %s!", __FUNCTION__, cameraId.c_str()); + status = Status::ILLEGAL_ARGUMENT; + } else { // invalid version + ALOGE("%s: camera device %s does not support version %s!", + __FUNCTION__, cameraId.c_str(), deviceVersion.c_str()); + status = Status::OPERATION_NOT_SUPPORTED; + } + _hidl_cb(status, nullptr); + return Void(); + } + + if (mCameraStatusMap.count(cameraId) == 0 || + mCameraStatusMap[cameraId] != CAMERA_DEVICE_STATUS_PRESENT) { + _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); + return Void(); + } + + sp<android::hardware::camera::device::V1_0::implementation::CameraDevice> device = + new android::hardware::camera::device::V1_0::implementation::CameraDevice( + mModule, cameraId, mCameraDeviceNames); + + if (device == nullptr) { + ALOGE("%s: cannot allocate camera device for id %s", __FUNCTION__, cameraId.c_str()); + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } + + if (device->isInitFailed()) { + ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); + device = nullptr; + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } + + _hidl_cb (Status::OK, device); + return Void(); +} + +Return<void> CameraProvider::getCameraDeviceInterface_V3_x( + const hidl_string& cameraDeviceName, getCameraDeviceInterface_V3_x_cb _hidl_cb) { + std::smatch sm; + bool match = matchDeviceName(cameraDeviceName, sm); + if (!match) { + _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); + return Void(); + } + + std::string cameraId = sm[2]; + std::string deviceVersion = sm[1]; + std::string deviceName(cameraDeviceName.c_str()); + ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName)); + if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch + Status status = Status::OK; + ssize_t idx = mCameraIds.indexOf(cameraId); + if (idx == NAME_NOT_FOUND) { + ALOGE("%s: cannot find camera %s!", __FUNCTION__, cameraId.c_str()); + status = Status::ILLEGAL_ARGUMENT; + } else { // invalid version + ALOGE("%s: camera device %s does not support version %s!", + __FUNCTION__, cameraId.c_str(), deviceVersion.c_str()); + status = Status::OPERATION_NOT_SUPPORTED; + } + _hidl_cb(status, nullptr); + return Void(); + } + + if (mCameraStatusMap.count(cameraId) == 0 || + mCameraStatusMap[cameraId] != CAMERA_DEVICE_STATUS_PRESENT) { + _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr); + return Void(); + } + + // TODO: we also need to keep a wp list of all generated devices to notify + // devices of device present status change, but then each device might + // need a sp<provider> to keep provider alive until all device closed? + // Problem: do we have external camera products to test this? + sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> device = + new android::hardware::camera::device::V3_2::implementation::CameraDevice( + mModule, cameraId, mCameraDeviceNames); + + if (device == nullptr) { + ALOGE("%s: cannot allocate camera device for id %s", __FUNCTION__, cameraId.c_str()); + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } + + if (device->isInitFailed()) { + ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str()); + device = nullptr; + _hidl_cb(Status::INTERNAL_ERROR, nullptr); + return Void(); + } + + _hidl_cb (Status::OK, device); + return Void(); +} + +ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) { + if (strcmp(name, kLegacyProviderName) != 0) { + return nullptr; + } + CameraProvider* provider = new CameraProvider(); + if (provider == nullptr) { + ALOGE("%s: cannot allocate camera provider!", __FUNCTION__); + return nullptr; + } + if (provider->isInitFailed()) { + ALOGE("%s: camera provider init failed!", __FUNCTION__); + delete provider; + return nullptr; + } + return provider; +} + +} // namespace implementation +} // namespace V2_4 +} // namespace provider +} // namespace camera +} // namespace hardware +} // namespace android
diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h new file mode 100644 index 0000000..2a43e2f --- /dev/null +++ b/camera/provider/2.4/default/CameraProvider.h
@@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H +#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H + +#include <regex> +#include "hardware/camera_common.h" +#include "utils/Mutex.h" +#include "utils/SortedVector.h" +#include <android/hardware/camera/provider/2.4/ICameraProvider.h> +#include <hidl/Status.h> +#include <hidl/MQDescriptor.h> +#include "CameraModule.h" +#include "VendorTagDescriptor.h" + +namespace android { +namespace hardware { +namespace camera { +namespace provider { +namespace V2_4 { +namespace implementation { + +using ::android::hardware::camera::common::V1_0::CameraDeviceStatus; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::TorchModeStatus; +using ::android::hardware::camera::common::V1_0::VendorTag; +using ::android::hardware::camera::common::V1_0::VendorTagSection; +using ::android::hardware::camera::common::V1_0::helper::CameraModule; +using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptor; +using ::android::hardware::camera::provider::V2_4::ICameraProvider; +using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; +using ::android::Mutex; + +struct CameraProvider : public ICameraProvider, public camera_module_callbacks_t { + CameraProvider(); + ~CameraProvider(); + + // Caller must use this method to check if CameraProvider ctor failed + bool isInitFailed() { return mInitFailed; } + + // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow. + Return<Status> setCallback(const sp<ICameraProviderCallback>& callback) override; + Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override; + Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override; + Return<void> isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override; + Return<void> getCameraDeviceInterface_V1_x( + const hidl_string& cameraDeviceName, + getCameraDeviceInterface_V1_x_cb _hidl_cb) override; + Return<void> getCameraDeviceInterface_V3_x( + const hidl_string& cameraDeviceName, + getCameraDeviceInterface_V3_x_cb _hidl_cb) override; + +private: + Mutex mCbLock; + sp<ICameraProviderCallback> mCallbacks = nullptr; + + sp<CameraModule> mModule; + + int mNumberOfLegacyCameras; + std::map<std::string, camera_device_status_t> mCameraStatusMap; // camera id -> status + std::map<std::string, bool> mOpenLegacySupported; // camera id -> open_legacy HAL1.0 supported + SortedVector<std::string> mCameraIds; // the "0"/"1" legacy camera Ids + // (cameraId string, hidl device name) pairs + SortedVector<std::pair<std::string, std::string>> mCameraDeviceNames; + + // Must be queried before using any APIs. + // APIs will only work when this returns true + bool mInitFailed; + bool initialize(); + + hidl_vec<VendorTagSection> mVendorTagSections; + bool setUpVendorTags(); + + // extract legacy camera ID/device version from a HIDL device name + static bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm); + static std::string getLegacyCameraId(const hidl_string& deviceName); + static int getCameraDeviceVersion(const hidl_string& deviceName); + + // create HIDL device name from camera ID and device version + static std::string getHidlDeviceName(std::string cameraId, int deviceVersion); + + // convert conventional HAL status to HIDL Status + static Status getHidlStatus(int); + + // static callback forwarding methods + static void sCameraDeviceStatusChange( + const struct camera_module_callbacks* callbacks, + int camera_id, + int new_status); + static void sTorchModeStatusChange( + const struct camera_module_callbacks* callbacks, + const char* camera_id, + int new_status); +}; + +extern "C" ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name); + +} // namespace implementation +} // namespace V2_4 +} // namespace provider +} // namespace camera +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc new file mode 100644 index 0000000..192870b --- /dev/null +++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc
@@ -0,0 +1,6 @@ +service camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service + class hal + user cameraserver + group audio camera input drmrpc + ioprio rt 4 + writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks \ No newline at end of file
diff --git a/camera/provider/2.4/default/service.cpp b/camera/provider/2.4/default/service.cpp new file mode 100644 index 0000000..cf66e04 --- /dev/null +++ b/camera/provider/2.4/default/service.cpp
@@ -0,0 +1,29 @@ +/* + * Copyright 2017 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. + */ + +#define LOG_TAG "android.hardware.camera.provider@2.4-service" + +#include <android/hardware/camera/provider/2.4/ICameraProvider.h> +#include <hidl/LegacySupport.h> + +using android::hardware::camera::provider::V2_4::ICameraProvider; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() +{ + ALOGI("Camera provider Service is starting."); + return defaultPassthroughServiceImplementation<ICameraProvider>("legacy/0"); +} \ No newline at end of file
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp new file mode 100644 index 0000000..a0be5cb --- /dev/null +++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -0,0 +1,41 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalCameraProviderV2_4TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalCameraProviderV2_4TargetTest.cpp", + "CameraParameters.cpp" ], + shared_libs: [ + "liblog", + "libhidlbase", + "libhidltransport", + "libcutils", + "libutils", + "android.hardware.camera.provider@2.4", + "android.hardware.camera.device@3.2", + "android.hardware.camera.device@1.0", + "libcamera_metadata", + "libbinder", + "libgui", + "libui" + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +}
diff --git a/camera/provider/2.4/vts/functional/CameraParameters.cpp b/camera/provider/2.4/vts/functional/CameraParameters.cpp new file mode 100644 index 0000000..0285154 --- /dev/null +++ b/camera/provider/2.4/vts/functional/CameraParameters.cpp
@@ -0,0 +1,537 @@ +/* +** +** Copyright 2008, 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. +*/ + +#define LOG_TAG "CameraParams" +#include <utils/Log.h> + +#include <string.h> +#include <stdlib.h> +#include "CameraParameters.h" +#include <system/graphics.h> + +namespace android { +// Parameter keys to communicate between camera application and driver. +const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size"; +const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values"; +const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format"; +const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values"; +const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate"; +const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values"; +const char CameraParameters::KEY_PREVIEW_FPS_RANGE[] = "preview-fps-range"; +const char CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE[] = "preview-fps-range-values"; +const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size"; +const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values"; +const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format"; +const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values"; +const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width"; +const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height"; +const char CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values"; +const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality"; +const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality"; +const char CameraParameters::KEY_ROTATION[] = "rotation"; +const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude"; +const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude"; +const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude"; +const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp"; +const char CameraParameters::KEY_GPS_PROCESSING_METHOD[] = "gps-processing-method"; +const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance"; +const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values"; +const char CameraParameters::KEY_EFFECT[] = "effect"; +const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values"; +const char CameraParameters::KEY_ANTIBANDING[] = "antibanding"; +const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values"; +const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode"; +const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values"; +const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode"; +const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values"; +const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode"; +const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values"; +const char CameraParameters::KEY_MAX_NUM_FOCUS_AREAS[] = "max-num-focus-areas"; +const char CameraParameters::KEY_FOCUS_AREAS[] = "focus-areas"; +const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length"; +const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle"; +const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle"; +const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensation"; +const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation"; +const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation"; +const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step"; +const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock"; +const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported"; +const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock"; +const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "auto-whitebalance-lock-supported"; +const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas"; +const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas"; +const char CameraParameters::KEY_ZOOM[] = "zoom"; +const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom"; +const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios"; +const char CameraParameters::KEY_ZOOM_SUPPORTED[] = "zoom-supported"; +const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported"; +const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances"; +const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format"; +const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size"; +const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values"; +const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video"; +const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw"; +const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw"; +const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint"; +const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported"; +const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization"; +const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported"; +const char CameraParameters::KEY_LIGHTFX[] = "light-fx"; + +const char CameraParameters::TRUE[] = "true"; +const char CameraParameters::FALSE[] = "false"; +const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity"; + +// Values for white balance settings. +const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto"; +const char CameraParameters::WHITE_BALANCE_INCANDESCENT[] = "incandescent"; +const char CameraParameters::WHITE_BALANCE_FLUORESCENT[] = "fluorescent"; +const char CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT[] = "warm-fluorescent"; +const char CameraParameters::WHITE_BALANCE_DAYLIGHT[] = "daylight"; +const char CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT[] = "cloudy-daylight"; +const char CameraParameters::WHITE_BALANCE_TWILIGHT[] = "twilight"; +const char CameraParameters::WHITE_BALANCE_SHADE[] = "shade"; + +// Values for effect settings. +const char CameraParameters::EFFECT_NONE[] = "none"; +const char CameraParameters::EFFECT_MONO[] = "mono"; +const char CameraParameters::EFFECT_NEGATIVE[] = "negative"; +const char CameraParameters::EFFECT_SOLARIZE[] = "solarize"; +const char CameraParameters::EFFECT_SEPIA[] = "sepia"; +const char CameraParameters::EFFECT_POSTERIZE[] = "posterize"; +const char CameraParameters::EFFECT_WHITEBOARD[] = "whiteboard"; +const char CameraParameters::EFFECT_BLACKBOARD[] = "blackboard"; +const char CameraParameters::EFFECT_AQUA[] = "aqua"; + +// Values for antibanding settings. +const char CameraParameters::ANTIBANDING_AUTO[] = "auto"; +const char CameraParameters::ANTIBANDING_50HZ[] = "50hz"; +const char CameraParameters::ANTIBANDING_60HZ[] = "60hz"; +const char CameraParameters::ANTIBANDING_OFF[] = "off"; + +// Values for flash mode settings. +const char CameraParameters::FLASH_MODE_OFF[] = "off"; +const char CameraParameters::FLASH_MODE_AUTO[] = "auto"; +const char CameraParameters::FLASH_MODE_ON[] = "on"; +const char CameraParameters::FLASH_MODE_RED_EYE[] = "red-eye"; +const char CameraParameters::FLASH_MODE_TORCH[] = "torch"; + +// Values for scene mode settings. +const char CameraParameters::SCENE_MODE_AUTO[] = "auto"; +const char CameraParameters::SCENE_MODE_ACTION[] = "action"; +const char CameraParameters::SCENE_MODE_PORTRAIT[] = "portrait"; +const char CameraParameters::SCENE_MODE_LANDSCAPE[] = "landscape"; +const char CameraParameters::SCENE_MODE_NIGHT[] = "night"; +const char CameraParameters::SCENE_MODE_NIGHT_PORTRAIT[] = "night-portrait"; +const char CameraParameters::SCENE_MODE_THEATRE[] = "theatre"; +const char CameraParameters::SCENE_MODE_BEACH[] = "beach"; +const char CameraParameters::SCENE_MODE_SNOW[] = "snow"; +const char CameraParameters::SCENE_MODE_SUNSET[] = "sunset"; +const char CameraParameters::SCENE_MODE_STEADYPHOTO[] = "steadyphoto"; +const char CameraParameters::SCENE_MODE_FIREWORKS[] = "fireworks"; +const char CameraParameters::SCENE_MODE_SPORTS[] = "sports"; +const char CameraParameters::SCENE_MODE_PARTY[] = "party"; +const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight"; +const char CameraParameters::SCENE_MODE_BARCODE[] = "barcode"; +const char CameraParameters::SCENE_MODE_HDR[] = "hdr"; + +const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp"; +const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp"; +const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv"; +const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p"; +const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565"; +const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888"; +const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg"; +const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb"; +const char CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE[] = "android-opaque"; + +// Values for focus mode settings. +const char CameraParameters::FOCUS_MODE_AUTO[] = "auto"; +const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity"; +const char CameraParameters::FOCUS_MODE_MACRO[] = "macro"; +const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed"; +const char CameraParameters::FOCUS_MODE_EDOF[] = "edof"; +const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video"; +const char CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE[] = "continuous-picture"; + +// Values for light fx settings +const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light"; +const char CameraParameters::LIGHTFX_HDR[] = "high-dynamic-range"; + +CameraParameters::CameraParameters() + : mMap() +{ +} + +CameraParameters::~CameraParameters() +{ +} + +String8 CameraParameters::flatten() const +{ + String8 flattened(""); + size_t size = mMap.size(); + + for (size_t i = 0; i < size; i++) { + String8 k, v; + k = mMap.keyAt(i); + v = mMap.valueAt(i); + + flattened += k; + flattened += "="; + flattened += v; + if (i != size-1) + flattened += ";"; + } + + return flattened; +} + +void CameraParameters::unflatten(const String8 ¶ms) +{ + const char *a = params.string(); + const char *b; + + mMap.clear(); + + for (;;) { + // Find the bounds of the key name. + b = strchr(a, '='); + if (b == 0) + break; + + // Create the key string. + String8 k(a, (size_t)(b-a)); + + // Find the value. + a = b+1; + b = strchr(a, ';'); + if (b == 0) { + // If there's no semicolon, this is the last item. + String8 v(a); + mMap.add(k, v); + break; + } + + String8 v(a, (size_t)(b-a)); + mMap.add(k, v); + a = b+1; + } +} + + +void CameraParameters::set(const char *key, const char *value) +{ + // i think i can do this with strspn() + if (strchr(key, '=') || strchr(key, ';')) { + // ALOGE("Key \"%s\"contains invalid character (= or ;)", key); + return; + } + + if (strchr(value, '=') || strchr(value, ';')) { + // ALOGE("Value \"%s\"contains invalid character (= or ;)", value); + return; + } + + mMap.replaceValueFor(String8(key), String8(value)); +} + +void CameraParameters::set(const char *key, int value) +{ + char str[16]; + sprintf(str, "%d", value); + set(key, str); +} + +void CameraParameters::setFloat(const char *key, float value) +{ + char str[16]; // 14 should be enough. We overestimate to be safe. + snprintf(str, sizeof(str), "%g", value); + set(key, str); +} + +const char *CameraParameters::get(const char *key) const +{ + String8 v = mMap.valueFor(String8(key)); + if (v.length() == 0) + return 0; + return v.string(); +} + +int CameraParameters::getInt(const char *key) const +{ + const char *v = get(key); + if (v == 0) + return -1; + return strtol(v, 0, 0); +} + +float CameraParameters::getFloat(const char *key) const +{ + const char *v = get(key); + if (v == 0) return -1; + return strtof(v, 0); +} + +void CameraParameters::remove(const char *key) +{ + mMap.removeItem(String8(key)); +} + +// Parse string like "640x480" or "10000,20000" +static int parse_pair(const char *str, int *first, int *second, char delim, + char **endptr = NULL) +{ + // Find the first integer. + char *end; + int w = (int)strtol(str, &end, 10); + // If a delimeter does not immediately follow, give up. + if (*end != delim) { + ALOGE("Cannot find delimeter (%c) in str=%s", delim, str); + return -1; + } + + // Find the second integer, immediately after the delimeter. + int h = (int)strtol(end+1, &end, 10); + + *first = w; + *second = h; + + if (endptr) { + *endptr = end; + } + + return 0; +} + +static void parseSizesList(const char *sizesStr, Vector<Size> &sizes) +{ + if (sizesStr == 0) { + return; + } + + char *sizeStartPtr = (char *)sizesStr; + + while (true) { + int width, height; + int success = parse_pair(sizeStartPtr, &width, &height, 'x', + &sizeStartPtr); + if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) { + ALOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr); + return; + } + sizes.push(Size(width, height)); + + if (*sizeStartPtr == '\0') { + return; + } + sizeStartPtr++; + } +} + +void CameraParameters::setPreviewSize(int width, int height) +{ + char str[32]; + sprintf(str, "%dx%d", width, height); + set(KEY_PREVIEW_SIZE, str); +} + +void CameraParameters::getPreviewSize(int *width, int *height) const +{ + *width = *height = -1; + // Get the current string, if it doesn't exist, leave the -1x-1 + const char *p = get(KEY_PREVIEW_SIZE); + if (p == 0) return; + parse_pair(p, width, height, 'x'); +} + +void CameraParameters::getPreferredPreviewSizeForVideo(int *width, int *height) const +{ + *width = *height = -1; + const char *p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO); + if (p == 0) return; + parse_pair(p, width, height, 'x'); +} + +void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const +{ + const char *previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES); + parseSizesList(previewSizesStr, sizes); +} + +void CameraParameters::setVideoSize(int width, int height) +{ + char str[32]; + sprintf(str, "%dx%d", width, height); + set(KEY_VIDEO_SIZE, str); +} + +void CameraParameters::getVideoSize(int *width, int *height) const +{ + *width = *height = -1; + const char *p = get(KEY_VIDEO_SIZE); + if (p == 0) return; + parse_pair(p, width, height, 'x'); +} + +void CameraParameters::getSupportedVideoSizes(Vector<Size> &sizes) const +{ + const char *videoSizesStr = get(KEY_SUPPORTED_VIDEO_SIZES); + parseSizesList(videoSizesStr, sizes); +} + +void CameraParameters::setPreviewFrameRate(int fps) +{ + set(KEY_PREVIEW_FRAME_RATE, fps); +} + +int CameraParameters::getPreviewFrameRate() const +{ + return getInt(KEY_PREVIEW_FRAME_RATE); +} + +void CameraParameters::getPreviewFpsRange(int *min_fps, int *max_fps) const +{ + *min_fps = *max_fps = -1; + const char *p = get(KEY_PREVIEW_FPS_RANGE); + if (p == 0) return; + parse_pair(p, min_fps, max_fps, ','); +} + +void CameraParameters::setPreviewFormat(const char *format) +{ + set(KEY_PREVIEW_FORMAT, format); +} + +const char *CameraParameters::getPreviewFormat() const +{ + return get(KEY_PREVIEW_FORMAT); +} + +void CameraParameters::setPictureSize(int width, int height) +{ + char str[32]; + sprintf(str, "%dx%d", width, height); + set(KEY_PICTURE_SIZE, str); +} + +void CameraParameters::getPictureSize(int *width, int *height) const +{ + *width = *height = -1; + // Get the current string, if it doesn't exist, leave the -1x-1 + const char *p = get(KEY_PICTURE_SIZE); + if (p == 0) return; + parse_pair(p, width, height, 'x'); +} + +void CameraParameters::getSupportedPictureSizes(Vector<Size> &sizes) const +{ + const char *pictureSizesStr = get(KEY_SUPPORTED_PICTURE_SIZES); + parseSizesList(pictureSizesStr, sizes); +} + +void CameraParameters::setPictureFormat(const char *format) +{ + set(KEY_PICTURE_FORMAT, format); +} + +const char *CameraParameters::getPictureFormat() const +{ + return get(KEY_PICTURE_FORMAT); +} + +void CameraParameters::dump() const +{ + ALOGD("dump: mMap.size = %zu", mMap.size()); + for (size_t i = 0; i < mMap.size(); i++) { + String8 k, v; + k = mMap.keyAt(i); + v = mMap.valueAt(i); + ALOGD("%s: %s\n", k.string(), v.string()); + } +} + +status_t CameraParameters::dump(int fd, const Vector<String16>& /*args*/) const +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %zu\n", mMap.size()); + result.append(buffer); + for (size_t i = 0; i < mMap.size(); i++) { + String8 k, v; + k = mMap.keyAt(i); + v = mMap.valueAt(i); + snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string()); + result.append(buffer); + } + write(fd, result.string(), result.size()); + return NO_ERROR; +} + +void CameraParameters::getSupportedPreviewFormats(Vector<int>& formats) const { + const char* supportedPreviewFormats = + get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS); + + if (supportedPreviewFormats == NULL) { + ALOGW("%s: No supported preview formats.", __FUNCTION__); + return; + } + + String8 fmtStr(supportedPreviewFormats); + char* prevFmts = fmtStr.lockBuffer(fmtStr.size()); + + char* savePtr; + char* fmt = strtok_r(prevFmts, ",", &savePtr); + while (fmt) { + int actual = previewFormatToEnum(fmt); + if (actual != -1) { + formats.add(actual); + } + fmt = strtok_r(NULL, ",", &savePtr); + } + fmtStr.unlockBuffer(fmtStr.size()); +} + + +int CameraParameters::previewFormatToEnum(const char* format) { + return + !format ? + HAL_PIXEL_FORMAT_YCrCb_420_SP : + !strcmp(format, PIXEL_FORMAT_YUV422SP) ? + HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16 + !strcmp(format, PIXEL_FORMAT_YUV420SP) ? + HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21 + !strcmp(format, PIXEL_FORMAT_YUV422I) ? + HAL_PIXEL_FORMAT_YCbCr_422_I : // YUY2 + !strcmp(format, PIXEL_FORMAT_YUV420P) ? + HAL_PIXEL_FORMAT_YV12 : // YV12 + !strcmp(format, PIXEL_FORMAT_RGB565) ? + HAL_PIXEL_FORMAT_RGB_565 : // RGB565 + !strcmp(format, PIXEL_FORMAT_RGBA8888) ? + HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888 + !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ? + HAL_PIXEL_FORMAT_RAW16 : // Raw sensor data + -1; +} + +bool CameraParameters::isEmpty() const { + return mMap.isEmpty(); +} + +}; // namespace android
diff --git a/camera/provider/2.4/vts/functional/CameraParameters.h b/camera/provider/2.4/vts/functional/CameraParameters.h new file mode 100644 index 0000000..ba33ffe --- /dev/null +++ b/camera/provider/2.4/vts/functional/CameraParameters.h
@@ -0,0 +1,699 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef ANDROID_HARDWARE_CAMERA_PARAMETERS_H +#define ANDROID_HARDWARE_CAMERA_PARAMETERS_H + +#include <utils/KeyedVector.h> +#include <utils/String8.h> + +namespace android { + +struct Size { + int width; + int height; + + Size() { + width = 0; + height = 0; + } + + Size(int w, int h) { + width = w; + height = h; + } +}; + +class CameraParameters +{ +public: + CameraParameters(); + CameraParameters(const String8 ¶ms) { unflatten(params); } + ~CameraParameters(); + + String8 flatten() const; + void unflatten(const String8 ¶ms); + + void set(const char *key, const char *value); + void set(const char *key, int value); + void setFloat(const char *key, float value); + const char *get(const char *key) const; + int getInt(const char *key) const; + float getFloat(const char *key) const; + + void remove(const char *key); + + void setPreviewSize(int width, int height); + void getPreviewSize(int *width, int *height) const; + void getSupportedPreviewSizes(Vector<Size> &sizes) const; + + // Set the dimensions in pixels to the given width and height + // for video frames. The given width and height must be one + // of the supported dimensions returned from + // getSupportedVideoSizes(). Must not be called if + // getSupportedVideoSizes() returns an empty Vector of Size. + void setVideoSize(int width, int height); + // Retrieve the current dimensions (width and height) + // in pixels for video frames, which must be one of the + // supported dimensions returned from getSupportedVideoSizes(). + // Must not be called if getSupportedVideoSizes() returns an + // empty Vector of Size. + void getVideoSize(int *width, int *height) const; + // Retrieve a Vector of supported dimensions (width and height) + // in pixels for video frames. If sizes returned from the method + // is empty, the camera does not support calls to setVideoSize() + // or getVideoSize(). In adddition, it also indicates that + // the camera only has a single output, and does not have + // separate output for video frames and preview frame. + void getSupportedVideoSizes(Vector<Size> &sizes) const; + // Retrieve the preferred preview size (width and height) in pixels + // for video recording. The given width and height must be one of + // supported preview sizes returned from getSupportedPreviewSizes(). + // Must not be called if getSupportedVideoSizes() returns an empty + // Vector of Size. If getSupportedVideoSizes() returns an empty + // Vector of Size, the width and height returned from this method + // is invalid, and is "-1x-1". + void getPreferredPreviewSizeForVideo(int *width, int *height) const; + + void setPreviewFrameRate(int fps); + int getPreviewFrameRate() const; + void getPreviewFpsRange(int *min_fps, int *max_fps) const; + void setPreviewFormat(const char *format); + const char *getPreviewFormat() const; + void setPictureSize(int width, int height); + void getPictureSize(int *width, int *height) const; + void getSupportedPictureSizes(Vector<Size> &sizes) const; + void setPictureFormat(const char *format); + const char *getPictureFormat() const; + + void dump() const; + status_t dump(int fd, const Vector<String16>& args) const; + + /** + * Returns a Vector containing the supported preview formats + * as enums given in graphics.h. + */ + void getSupportedPreviewFormats(Vector<int>& formats) const; + + // Returns true if no keys are present + bool isEmpty() const; + + // Parameter keys to communicate between camera application and driver. + // The access (read/write, read only, or write only) is viewed from the + // perspective of applications, not driver. + + // Preview frame size in pixels (width x height). + // Example value: "480x320". Read/Write. + static const char KEY_PREVIEW_SIZE[]; + // Supported preview frame sizes in pixels. + // Example value: "800x600,480x320". Read only. + static const char KEY_SUPPORTED_PREVIEW_SIZES[]; + // The current minimum and maximum preview fps. This controls the rate of + // preview frames received (CAMERA_MSG_PREVIEW_FRAME). The minimum and + // maximum fps must be one of the elements from + // KEY_SUPPORTED_PREVIEW_FPS_RANGE parameter. + // Example value: "10500,26623" + static const char KEY_PREVIEW_FPS_RANGE[]; + // The supported preview fps (frame-per-second) ranges. Each range contains + // a minimum fps and maximum fps. If minimum fps equals to maximum fps, the + // camera outputs frames in fixed frame rate. If not, the camera outputs + // frames in auto frame rate. The actual frame rate fluctuates between the + // minimum and the maximum. The list has at least one element. The list is + // sorted from small to large (first by maximum fps and then minimum fps). + // Example value: "(10500,26623),(15000,26623),(30000,30000)" + static const char KEY_SUPPORTED_PREVIEW_FPS_RANGE[]; + // The image format for preview frames. See CAMERA_MSG_PREVIEW_FRAME in + // frameworks/av/include/camera/Camera.h. The default is + // PIXEL_FORMAT_YUV420SP. Example value: "yuv420sp" or PIXEL_FORMAT_XXX + // constants. Read/write. + static const char KEY_PREVIEW_FORMAT[]; + // Supported image formats for preview frames. + // Example value: "yuv420sp,yuv422i-yuyv". Read only. + static const char KEY_SUPPORTED_PREVIEW_FORMATS[]; + // Number of preview frames per second. This is the target frame rate. The + // actual frame rate depends on the driver. + // Example value: "15". Read/write. + static const char KEY_PREVIEW_FRAME_RATE[]; + // Supported number of preview frames per second. + // Example value: "24,15,10". Read. + static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[]; + // The dimensions for captured pictures in pixels (width x height). + // Example value: "1024x768". Read/write. + static const char KEY_PICTURE_SIZE[]; + // Supported dimensions for captured pictures in pixels. + // Example value: "2048x1536,1024x768". Read only. + static const char KEY_SUPPORTED_PICTURE_SIZES[]; + // The image format for captured pictures. See CAMERA_MSG_COMPRESSED_IMAGE + // in frameworks/base/include/camera/Camera.h. + // Example value: "jpeg" or PIXEL_FORMAT_XXX constants. Read/write. + static const char KEY_PICTURE_FORMAT[]; + // Supported image formats for captured pictures. + // Example value: "jpeg,rgb565". Read only. + static const char KEY_SUPPORTED_PICTURE_FORMATS[]; + // The width (in pixels) of EXIF thumbnail in Jpeg picture. + // Example value: "512". Read/write. + static const char KEY_JPEG_THUMBNAIL_WIDTH[]; + // The height (in pixels) of EXIF thumbnail in Jpeg picture. + // Example value: "384". Read/write. + static const char KEY_JPEG_THUMBNAIL_HEIGHT[]; + // Supported EXIF thumbnail sizes (width x height). 0x0 means not thumbnail + // in EXIF. + // Example value: "512x384,320x240,0x0". Read only. + static const char KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[]; + // The quality of the EXIF thumbnail in Jpeg picture. The range is 1 to 100, + // with 100 being the best. + // Example value: "90". Read/write. + static const char KEY_JPEG_THUMBNAIL_QUALITY[]; + // Jpeg quality of captured picture. The range is 1 to 100, with 100 being + // the best. + // Example value: "90". Read/write. + static const char KEY_JPEG_QUALITY[]; + // The rotation angle in degrees relative to the orientation of the camera. + // This affects the pictures returned from CAMERA_MSG_COMPRESSED_IMAGE. The + // camera driver may set orientation in the EXIF header without rotating the + // picture. Or the driver may rotate the picture and the EXIF thumbnail. If + // the Jpeg picture is rotated, the orientation in the EXIF header will be + // missing or 1 (row #0 is top and column #0 is left side). + // + // Note that the JPEG pictures of front-facing cameras are not mirrored + // as in preview display. + // + // For example, suppose the natural orientation of the device is portrait. + // The device is rotated 270 degrees clockwise, so the device orientation is + // 270. Suppose a back-facing camera sensor is mounted in landscape and the + // top side of the camera sensor is aligned with the right edge of the + // display in natural orientation. So the camera orientation is 90. The + // rotation should be set to 0 (270 + 90). + // + // Example value: "0" or "90" or "180" or "270". Write only. + static const char KEY_ROTATION[]; + // GPS latitude coordinate. GPSLatitude and GPSLatitudeRef will be stored in + // JPEG EXIF header. + // Example value: "25.032146" or "-33.462809". Write only. + static const char KEY_GPS_LATITUDE[]; + // GPS longitude coordinate. GPSLongitude and GPSLongitudeRef will be stored + // in JPEG EXIF header. + // Example value: "121.564448" or "-70.660286". Write only. + static const char KEY_GPS_LONGITUDE[]; + // GPS altitude. GPSAltitude and GPSAltitudeRef will be stored in JPEG EXIF + // header. + // Example value: "21.0" or "-5". Write only. + static const char KEY_GPS_ALTITUDE[]; + // GPS timestamp (UTC in seconds since January 1, 1970). This should be + // stored in JPEG EXIF header. + // Example value: "1251192757". Write only. + static const char KEY_GPS_TIMESTAMP[]; + // GPS Processing Method + // Example value: "GPS" or "NETWORK". Write only. + static const char KEY_GPS_PROCESSING_METHOD[]; + // Current white balance setting. + // Example value: "auto" or WHITE_BALANCE_XXX constants. Read/write. + static const char KEY_WHITE_BALANCE[]; + // Supported white balance settings. + // Example value: "auto,incandescent,daylight". Read only. + static const char KEY_SUPPORTED_WHITE_BALANCE[]; + // Current color effect setting. + // Example value: "none" or EFFECT_XXX constants. Read/write. + static const char KEY_EFFECT[]; + // Supported color effect settings. + // Example value: "none,mono,sepia". Read only. + static const char KEY_SUPPORTED_EFFECTS[]; + // Current antibanding setting. + // Example value: "auto" or ANTIBANDING_XXX constants. Read/write. + static const char KEY_ANTIBANDING[]; + // Supported antibanding settings. + // Example value: "auto,50hz,60hz,off". Read only. + static const char KEY_SUPPORTED_ANTIBANDING[]; + // Current scene mode. + // Example value: "auto" or SCENE_MODE_XXX constants. Read/write. + static const char KEY_SCENE_MODE[]; + // Supported scene mode settings. + // Example value: "auto,night,fireworks". Read only. + static const char KEY_SUPPORTED_SCENE_MODES[]; + // Current flash mode. + // Example value: "auto" or FLASH_MODE_XXX constants. Read/write. + static const char KEY_FLASH_MODE[]; + // Supported flash modes. + // Example value: "auto,on,off". Read only. + static const char KEY_SUPPORTED_FLASH_MODES[]; + // Current focus mode. This will not be empty. Applications should call + // CameraHardwareInterface.autoFocus to start the focus if focus mode is + // FOCUS_MODE_AUTO or FOCUS_MODE_MACRO. + // Example value: "auto" or FOCUS_MODE_XXX constants. Read/write. + static const char KEY_FOCUS_MODE[]; + // Supported focus modes. + // Example value: "auto,macro,fixed". Read only. + static const char KEY_SUPPORTED_FOCUS_MODES[]; + // The maximum number of focus areas supported. This is the maximum length + // of KEY_FOCUS_AREAS. + // Example value: "0" or "2". Read only. + static const char KEY_MAX_NUM_FOCUS_AREAS[]; + // Current focus areas. + // + // Before accessing this parameter, apps should check + // KEY_MAX_NUM_FOCUS_AREAS first to know the maximum number of focus areas + // first. If the value is 0, focus area is not supported. + // + // Each focus area is a five-element int array. The first four elements are + // the rectangle of the area (left, top, right, bottom). The direction is + // relative to the sensor orientation, that is, what the sensor sees. The + // direction is not affected by the rotation or mirroring of + // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates range from -1000 to 1000. + // (-1000,-1000) is the upper left point. (1000, 1000) is the lower right + // point. The width and height of focus areas cannot be 0 or negative. + // + // The fifth element is the weight. Values for weight must range from 1 to + // 1000. The weight should be interpreted as a per-pixel weight - all + // pixels in the area have the specified weight. This means a small area + // with the same weight as a larger area will have less influence on the + // focusing than the larger area. Focus areas can partially overlap and the + // driver will add the weights in the overlap region. + // + // A special case of single focus area (0,0,0,0,0) means driver to decide + // the focus area. For example, the driver may use more signals to decide + // focus areas and change them dynamically. Apps can set (0,0,0,0,0) if they + // want the driver to decide focus areas. + // + // Focus areas are relative to the current field of view (KEY_ZOOM). No + // matter what the zoom level is, (-1000,-1000) represents the top of the + // currently visible camera frame. The focus area cannot be set to be + // outside the current field of view, even when using zoom. + // + // Focus area only has effect if the current focus mode is FOCUS_MODE_AUTO, + // FOCUS_MODE_MACRO, FOCUS_MODE_CONTINUOUS_VIDEO, or + // FOCUS_MODE_CONTINUOUS_PICTURE. + // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write. + static const char KEY_FOCUS_AREAS[]; + // Focal length in millimeter. + // Example value: "4.31". Read only. + static const char KEY_FOCAL_LENGTH[]; + // Horizontal angle of view in degrees. + // Example value: "54.8". Read only. + static const char KEY_HORIZONTAL_VIEW_ANGLE[]; + // Vertical angle of view in degrees. + // Example value: "42.5". Read only. + static const char KEY_VERTICAL_VIEW_ANGLE[]; + // Exposure compensation index. 0 means exposure is not adjusted. + // Example value: "-5" or "5". Read/write. + static const char KEY_EXPOSURE_COMPENSATION[]; + // The maximum exposure compensation index (>=0). + // Example value: "6". Read only. + static const char KEY_MAX_EXPOSURE_COMPENSATION[]; + // The minimum exposure compensation index (<=0). + // Example value: "-6". Read only. + static const char KEY_MIN_EXPOSURE_COMPENSATION[]; + // The exposure compensation step. Exposure compensation index multiply by + // step eqals to EV. Ex: if exposure compensation index is -6 and step is + // 0.3333, EV is -2. + // Example value: "0.333333333" or "0.5". Read only. + static const char KEY_EXPOSURE_COMPENSATION_STEP[]; + // The state of the auto-exposure lock. "true" means that + // auto-exposure is locked to its current value and will not + // change. "false" means the auto-exposure routine is free to + // change exposure values. If auto-exposure is already locked, + // setting this to true again has no effect (the driver will not + // recalculate exposure values). Changing exposure compensation + // settings will still affect the exposure settings while + // auto-exposure is locked. Stopping preview or taking a still + // image will not change the lock. In conjunction with + // exposure compensation, this allows for capturing multi-exposure + // brackets with known relative exposure values. Locking + // auto-exposure after open but before the first call to + // startPreview may result in severely over- or under-exposed + // images. The driver will not change the AE lock after + // auto-focus completes. + static const char KEY_AUTO_EXPOSURE_LOCK[]; + // Whether locking the auto-exposure is supported. "true" means it is, and + // "false" or this key not existing means it is not supported. + static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[]; + // The state of the auto-white balance lock. "true" means that + // auto-white balance is locked to its current value and will not + // change. "false" means the auto-white balance routine is free to + // change white balance values. If auto-white balance is already + // locked, setting this to true again has no effect (the driver + // will not recalculate white balance values). Stopping preview or + // taking a still image will not change the lock. In conjunction + // with exposure compensation, this allows for capturing + // multi-exposure brackets with fixed white balance. Locking + // auto-white balance after open but before the first call to + // startPreview may result in severely incorrect color. The + // driver will not change the AWB lock after auto-focus + // completes. + static const char KEY_AUTO_WHITEBALANCE_LOCK[]; + // Whether locking the auto-white balance is supported. "true" + // means it is, and "false" or this key not existing means it is + // not supported. + static const char KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[]; + + // The maximum number of metering areas supported. This is the maximum + // length of KEY_METERING_AREAS. + // Example value: "0" or "2". Read only. + static const char KEY_MAX_NUM_METERING_AREAS[]; + // Current metering areas. Camera driver uses these areas to decide + // exposure. + // + // Before accessing this parameter, apps should check + // KEY_MAX_NUM_METERING_AREAS first to know the maximum number of metering + // areas first. If the value is 0, metering area is not supported. + // + // Each metering area is a rectangle with specified weight. The direction is + // relative to the sensor orientation, that is, what the sensor sees. The + // direction is not affected by the rotation or mirroring of + // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates of the rectangle range + // from -1000 to 1000. (-1000, -1000) is the upper left point. (1000, 1000) + // is the lower right point. The width and height of metering areas cannot + // be 0 or negative. + // + // The fifth element is the weight. Values for weight must range from 1 to + // 1000. The weight should be interpreted as a per-pixel weight - all + // pixels in the area have the specified weight. This means a small area + // with the same weight as a larger area will have less influence on the + // metering than the larger area. Metering areas can partially overlap and + // the driver will add the weights in the overlap region. + // + // A special case of all-zero single metering area means driver to decide + // the metering area. For example, the driver may use more signals to decide + // metering areas and change them dynamically. Apps can set all-zero if they + // want the driver to decide metering areas. + // + // Metering areas are relative to the current field of view (KEY_ZOOM). + // No matter what the zoom level is, (-1000,-1000) represents the top of the + // currently visible camera frame. The metering area cannot be set to be + // outside the current field of view, even when using zoom. + // + // No matter what metering areas are, the final exposure are compensated + // by KEY_EXPOSURE_COMPENSATION. + // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write. + static const char KEY_METERING_AREAS[]; + // Current zoom value. + // Example value: "0" or "6". Read/write. + static const char KEY_ZOOM[]; + // Maximum zoom value. + // Example value: "6". Read only. + static const char KEY_MAX_ZOOM[]; + // The zoom ratios of all zoom values. The zoom ratio is in 1/100 + // increments. Ex: a zoom of 3.2x is returned as 320. The number of list + // elements is KEY_MAX_ZOOM + 1. The first element is always 100. The last + // element is the zoom ratio of zoom value KEY_MAX_ZOOM. + // Example value: "100,150,200,250,300,350,400". Read only. + static const char KEY_ZOOM_RATIOS[]; + // Whether zoom is supported. Zoom is supported if the value is "true". Zoom + // is not supported if the value is not "true" or the key does not exist. + // Example value: "true". Read only. + static const char KEY_ZOOM_SUPPORTED[]; + // Whether if smooth zoom is supported. Smooth zoom is supported if the + // value is "true". It is not supported if the value is not "true" or the + // key does not exist. + // See CAMERA_CMD_START_SMOOTH_ZOOM, CAMERA_CMD_STOP_SMOOTH_ZOOM, and + // CAMERA_MSG_ZOOM in frameworks/base/include/camera/Camera.h. + // Example value: "true". Read only. + static const char KEY_SMOOTH_ZOOM_SUPPORTED[]; + + // The distances (in meters) from the camera to where an object appears to + // be in focus. The object is sharpest at the optimal focus distance. The + // depth of field is the far focus distance minus near focus distance. + // + // Focus distances may change after starting auto focus, canceling auto + // focus, or starting the preview. Applications can read this anytime to get + // the latest focus distances. If the focus mode is FOCUS_MODE_CONTINUOUS, + // focus distances may change from time to time. + // + // This is intended to estimate the distance between the camera and the + // subject. After autofocus, the subject distance may be within near and far + // focus distance. However, the precision depends on the camera hardware, + // autofocus algorithm, the focus area, and the scene. The error can be + // large and it should be only used as a reference. + // + // Far focus distance > optimal focus distance > near focus distance. If + // the far focus distance is infinity, the value should be "Infinity" (case + // sensitive). The format is three float values separated by commas. The + // first is near focus distance. The second is optimal focus distance. The + // third is far focus distance. + // Example value: "0.95,1.9,Infinity" or "0.049,0.05,0.051". Read only. + static const char KEY_FOCUS_DISTANCES[]; + + // The current dimensions in pixels (width x height) for video frames. + // The width and height must be one of the supported sizes retrieved + // via KEY_SUPPORTED_VIDEO_SIZES. + // Example value: "1280x720". Read/write. + static const char KEY_VIDEO_SIZE[]; + // A list of the supported dimensions in pixels (width x height) + // for video frames. See CAMERA_MSG_VIDEO_FRAME for details in + // frameworks/base/include/camera/Camera.h. + // Example: "176x144,1280x720". Read only. + static const char KEY_SUPPORTED_VIDEO_SIZES[]; + + // The maximum number of detected faces supported by hardware face + // detection. If the value is 0, hardware face detection is not supported. + // Example: "5". Read only + static const char KEY_MAX_NUM_DETECTED_FACES_HW[]; + + // The maximum number of detected faces supported by software face + // detection. If the value is 0, software face detection is not supported. + // Example: "5". Read only + static const char KEY_MAX_NUM_DETECTED_FACES_SW[]; + + // Preferred preview frame size in pixels for video recording. + // The width and height must be one of the supported sizes retrieved + // via KEY_SUPPORTED_PREVIEW_SIZES. This key can be used only when + // getSupportedVideoSizes() does not return an empty Vector of Size. + // Camcorder applications are recommended to set the preview size + // to a value that is not larger than the preferred preview size. + // In other words, the product of the width and height of the + // preview size should not be larger than that of the preferred + // preview size. In addition, we recommend to choos a preview size + // that has the same aspect ratio as the resolution of video to be + // recorded. + // Example value: "800x600". Read only. + static const char KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[]; + + // The image format for video frames. See CAMERA_MSG_VIDEO_FRAME in + // frameworks/base/include/camera/Camera.h. + // Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only. + static const char KEY_VIDEO_FRAME_FORMAT[]; + + // Sets the hint of the recording mode. If this is true, MediaRecorder.start + // may be faster or has less glitches. This should be called before starting + // the preview for the best result. But it is allowed to change the hint + // while the preview is active. The default value is false. + // + // The apps can still call Camera.takePicture when the hint is true. The + // apps can call MediaRecorder.start when the hint is false. But the + // performance may be worse. + // Example value: "true" or "false". Read/write. + static const char KEY_RECORDING_HINT[]; + + // Returns true if video snapshot is supported. That is, applications + // can call Camera.takePicture during recording. Applications do not need to + // call Camera.startPreview after taking a picture. The preview will be + // still active. Other than that, taking a picture during recording is + // identical to taking a picture normally. All settings and methods related + // to takePicture work identically. Ex: KEY_PICTURE_SIZE, + // KEY_SUPPORTED_PICTURE_SIZES, KEY_JPEG_QUALITY, KEY_ROTATION, and etc. + // The picture will have an EXIF header. FLASH_MODE_AUTO and FLASH_MODE_ON + // also still work, but the video will record the flash. + // + // Applications can set shutter callback as null to avoid the shutter + // sound. It is also recommended to set raw picture and post view callbacks + // to null to avoid the interrupt of preview display. + // + // Field-of-view of the recorded video may be different from that of the + // captured pictures. + // Example value: "true" or "false". Read only. + static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[]; + + // The state of the video stabilization. If set to true, both the + // preview stream and the recorded video stream are stabilized by + // the camera. Only valid to set if KEY_VIDEO_STABILIZATION_SUPPORTED is + // set to true. + // + // The value of this key can be changed any time the camera is + // open. If preview or recording is active, it is acceptable for + // there to be a slight video glitch when video stabilization is + // toggled on and off. + // + // This only stabilizes video streams (between-frames stabilization), and + // has no effect on still image capture. + static const char KEY_VIDEO_STABILIZATION[]; + + // Returns true if video stabilization is supported. That is, applications + // can set KEY_VIDEO_STABILIZATION to true and have a stabilized preview + // stream and record stabilized videos. + static const char KEY_VIDEO_STABILIZATION_SUPPORTED[]; + + // Supported modes for special effects with light. + // Example values: "lowlight,hdr". + static const char KEY_LIGHTFX[]; + + // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED. + static const char TRUE[]; + static const char FALSE[]; + + // Value for KEY_FOCUS_DISTANCES. + static const char FOCUS_DISTANCE_INFINITY[]; + + // Values for white balance settings. + static const char WHITE_BALANCE_AUTO[]; + static const char WHITE_BALANCE_INCANDESCENT[]; + static const char WHITE_BALANCE_FLUORESCENT[]; + static const char WHITE_BALANCE_WARM_FLUORESCENT[]; + static const char WHITE_BALANCE_DAYLIGHT[]; + static const char WHITE_BALANCE_CLOUDY_DAYLIGHT[]; + static const char WHITE_BALANCE_TWILIGHT[]; + static const char WHITE_BALANCE_SHADE[]; + + // Values for effect settings. + static const char EFFECT_NONE[]; + static const char EFFECT_MONO[]; + static const char EFFECT_NEGATIVE[]; + static const char EFFECT_SOLARIZE[]; + static const char EFFECT_SEPIA[]; + static const char EFFECT_POSTERIZE[]; + static const char EFFECT_WHITEBOARD[]; + static const char EFFECT_BLACKBOARD[]; + static const char EFFECT_AQUA[]; + + // Values for antibanding settings. + static const char ANTIBANDING_AUTO[]; + static const char ANTIBANDING_50HZ[]; + static const char ANTIBANDING_60HZ[]; + static const char ANTIBANDING_OFF[]; + + // Values for flash mode settings. + // Flash will not be fired. + static const char FLASH_MODE_OFF[]; + // Flash will be fired automatically when required. The flash may be fired + // during preview, auto-focus, or snapshot depending on the driver. + static const char FLASH_MODE_AUTO[]; + // Flash will always be fired during snapshot. The flash may also be + // fired during preview or auto-focus depending on the driver. + static const char FLASH_MODE_ON[]; + // Flash will be fired in red-eye reduction mode. + static const char FLASH_MODE_RED_EYE[]; + // Constant emission of light during preview, auto-focus and snapshot. + // This can also be used for video recording. + static const char FLASH_MODE_TORCH[]; + + // Values for scene mode settings. + static const char SCENE_MODE_AUTO[]; + static const char SCENE_MODE_ACTION[]; + static const char SCENE_MODE_PORTRAIT[]; + static const char SCENE_MODE_LANDSCAPE[]; + static const char SCENE_MODE_NIGHT[]; + static const char SCENE_MODE_NIGHT_PORTRAIT[]; + static const char SCENE_MODE_THEATRE[]; + static const char SCENE_MODE_BEACH[]; + static const char SCENE_MODE_SNOW[]; + static const char SCENE_MODE_SUNSET[]; + static const char SCENE_MODE_STEADYPHOTO[]; + static const char SCENE_MODE_FIREWORKS[]; + static const char SCENE_MODE_SPORTS[]; + static const char SCENE_MODE_PARTY[]; + static const char SCENE_MODE_CANDLELIGHT[]; + // Applications are looking for a barcode. Camera driver will be optimized + // for barcode reading. + static const char SCENE_MODE_BARCODE[]; + // A high-dynamic range mode. In this mode, the HAL module will use a + // capture strategy that extends the dynamic range of the captured + // image in some fashion. Only the final image is returned. + static const char SCENE_MODE_HDR[]; + + // Pixel color formats for KEY_PREVIEW_FORMAT, KEY_PICTURE_FORMAT, + // and KEY_VIDEO_FRAME_FORMAT + static const char PIXEL_FORMAT_YUV422SP[]; + static const char PIXEL_FORMAT_YUV420SP[]; // NV21 + static const char PIXEL_FORMAT_YUV422I[]; // YUY2 + static const char PIXEL_FORMAT_YUV420P[]; // YV12 + static const char PIXEL_FORMAT_RGB565[]; + static const char PIXEL_FORMAT_RGBA8888[]; + static const char PIXEL_FORMAT_JPEG[]; + // Raw bayer format used for images, which is 10 bit precision samples + // stored in 16 bit words. The filter pattern is RGGB. + static const char PIXEL_FORMAT_BAYER_RGGB[]; + // Pixel format is not known to the framework + static const char PIXEL_FORMAT_ANDROID_OPAQUE[]; + + // Values for focus mode settings. + // Auto-focus mode. Applications should call + // CameraHardwareInterface.autoFocus to start the focus in this mode. + static const char FOCUS_MODE_AUTO[]; + // Focus is set at infinity. Applications should not call + // CameraHardwareInterface.autoFocus in this mode. + static const char FOCUS_MODE_INFINITY[]; + // Macro (close-up) focus mode. Applications should call + // CameraHardwareInterface.autoFocus to start the focus in this mode. + static const char FOCUS_MODE_MACRO[]; + // Focus is fixed. The camera is always in this mode if the focus is not + // adjustable. If the camera has auto-focus, this mode can fix the + // focus, which is usually at hyperfocal distance. Applications should + // not call CameraHardwareInterface.autoFocus in this mode. + static const char FOCUS_MODE_FIXED[]; + // Extended depth of field (EDOF). Focusing is done digitally and + // continuously. Applications should not call + // CameraHardwareInterface.autoFocus in this mode. + static const char FOCUS_MODE_EDOF[]; + // Continuous auto focus mode intended for video recording. The camera + // continuously tries to focus. This is the best choice for video + // recording because the focus changes smoothly . Applications still can + // call CameraHardwareInterface.takePicture in this mode but the subject may + // not be in focus. Auto focus starts when the parameter is set. + // + // Applications can call CameraHardwareInterface.autoFocus in this mode. The + // focus callback will immediately return with a boolean that indicates + // whether the focus is sharp or not. The focus position is locked after + // autoFocus call. If applications want to resume the continuous focus, + // cancelAutoFocus must be called. Restarting the preview will not resume + // the continuous autofocus. To stop continuous focus, applications should + // change the focus mode to other modes. + static const char FOCUS_MODE_CONTINUOUS_VIDEO[]; + // Continuous auto focus mode intended for taking pictures. The camera + // continuously tries to focus. The speed of focus change is more aggressive + // than FOCUS_MODE_CONTINUOUS_VIDEO. Auto focus starts when the parameter is + // set. + // + // Applications can call CameraHardwareInterface.autoFocus in this mode. If + // the autofocus is in the middle of scanning, the focus callback will + // return when it completes. If the autofocus is not scanning, focus + // callback will immediately return with a boolean that indicates whether + // the focus is sharp or not. The apps can then decide if they want to take + // a picture immediately or to change the focus mode to auto, and run a full + // autofocus cycle. The focus position is locked after autoFocus call. If + // applications want to resume the continuous focus, cancelAutoFocus must be + // called. Restarting the preview will not resume the continuous autofocus. + // To stop continuous focus, applications should change the focus mode to + // other modes. + static const char FOCUS_MODE_CONTINUOUS_PICTURE[]; + + // Values for light special effects + // Low-light enhancement mode + static const char LIGHTFX_LOWLIGHT[]; + // High-dynamic range mode + static const char LIGHTFX_HDR[]; + + /** + * Returns the the supported preview formats as an enum given in graphics.h + * corrsponding to the format given in the input string or -1 if no such + * conversion exists. + */ + static int previewFormatToEnum(const char* format); + +private: + DefaultKeyedVector<String8,String8> mMap; +}; + +}; // namespace android + +#endif
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp new file mode 100644 index 0000000..598127f --- /dev/null +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -0,0 +1,3196 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "camera_hidl_hal_test" +#include <android/hardware/camera/provider/2.4/ICameraProvider.h> +#include <android/hardware/camera/device/3.2/ICameraDevice.h> +#include <android/hardware/camera/device/1.0/ICameraDevice.h> +#include "CameraParameters.h" +#include <system/camera.h> +#include <android/log.h> +#include <ui/GraphicBuffer.h> +#include <VtsHalHidlTargetTestBase.h> +#include <gui/BufferQueue.h> +#include <gui/Surface.h> +#include <gui/BufferItemConsumer.h> +#include <binder/MemoryHeapBase.h> +#include <regex> +#include "system/camera_metadata.h" +#include <hardware/gralloc.h> +#include <hardware/gralloc1.h> +#include <unordered_map> +#include <mutex> +#include <condition_variable> +#include <chrono> +#include <inttypes.h> +#include <utils/Errors.h> + +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::sp; +using ::android::wp; +using ::android::GraphicBuffer; +using ::android::IGraphicBufferProducer; +using ::android::IGraphicBufferConsumer; +using ::android::BufferQueue; +using ::android::BufferItemConsumer; +using ::android::Surface; +using ::android::CameraParameters; +using ::android::hardware::graphics::common::V1_0::PixelFormat; +using ::android::hardware::graphics::allocator::V2_0::ProducerUsage; +using ::android::hardware::camera::common::V1_0::Status; +using ::android::hardware::camera::common::V1_0::CameraDeviceStatus; +using ::android::hardware::camera::common::V1_0::TorchMode; +using ::android::hardware::camera::common::V1_0::TorchModeStatus; +using ::android::hardware::camera::provider::V2_4::ICameraProvider; +using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback; +using ::android::hardware::camera::device::V3_2::ICameraDevice; +using ::android::hardware::camera::device::V3_2::CaptureRequest; +using ::android::hardware::camera::device::V3_2::CaptureResult; +using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback; +using ::android::hardware::camera::device::V3_2::ICameraDeviceSession; +using ::android::hardware::camera::device::V3_2::NotifyMsg; +using ::android::hardware::camera::device::V3_2::RequestTemplate; +using ::android::hardware::camera::device::V3_2::Stream; +using ::android::hardware::camera::device::V3_2::StreamType; +using ::android::hardware::camera::device::V3_2::StreamRotation; +using ::android::hardware::camera::device::V3_2::StreamConfiguration; +using ::android::hardware::camera::device::V3_2::StreamConfigurationMode; +using ::android::hardware::camera::device::V3_2::CameraMetadata; +using ::android::hardware::camera::device::V3_2::HalStreamConfiguration; +using ::android::hardware::camera::device::V3_2::BufferStatus; +using ::android::hardware::camera::device::V3_2::StreamBuffer; +using ::android::hardware::camera::device::V3_2::MsgType; +using ::android::hardware::camera::device::V3_2::ErrorMsg; +using ::android::hardware::camera::device::V3_2::ErrorCode; +using ::android::hardware::camera::device::V1_0::CameraFacing; +using ::android::hardware::camera::device::V1_0::NotifyCallbackMsg; +using ::android::hardware::camera::device::V1_0::CommandType; +using ::android::hardware::camera::device::V1_0::DataCallbackMsg; +using ::android::hardware::camera::device::V1_0::CameraFrameMetadata; +using ::android::hardware::camera::device::V1_0::ICameraDevicePreviewCallback; +using ::android::hardware::camera::device::V1_0::FrameCallbackFlag; + +const char kCameraPassthroughServiceName[] = "legacy/0"; +const uint32_t kMaxPreviewWidth = 1920; +const uint32_t kMaxPreviewHeight = 1080; +const uint32_t kMaxVideoWidth = 4096; +const uint32_t kMaxVideoHeight = 2160; +const int64_t kStreamBufferTimeoutSec = 3; +const int64_t kAutoFocusTimeoutSec = 5; +const int64_t kTorchTimeoutSec = 1; +const int64_t kEmptyFlushTimeoutMSec = 200; +const char kDumpOutput[] = "/dev/null"; + +struct AvailableStream { + int32_t width; + int32_t height; + int32_t format; +}; + +struct AvailableZSLInputOutput { + int32_t inputFormat; + int32_t outputFormat; +}; + +namespace { + // "device@<version>/legacy/<id>" + const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/legacy/(.+)"; + const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302; + const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100; + const char *kHAL3_2 = "3.2"; + const char *kHAL1_0 = "1.0"; + + bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm) { + std::regex e(kDeviceNameRE); + std::string deviceNameStd(deviceName.c_str()); + return std::regex_match(deviceNameStd, sm, e); + } + + int getCameraDeviceVersion(const hidl_string& deviceName) { + std::smatch sm; + bool match = matchDeviceName(deviceName, sm); + if (!match) { + return -1; + } + std::string version = sm[1].str(); + if (version.compare(kHAL3_2) == 0) { + // maybe switched to 3.4 or define the hidl version enumlater + return CAMERA_DEVICE_API_VERSION_3_2; + } else if (version.compare(kHAL1_0) == 0) { + return CAMERA_DEVICE_API_VERSION_1_0; + } + return 0; + } + + Status mapToStatus(::android::status_t s) { + switch(s) { + case ::android::OK: + return Status::OK ; + case ::android::BAD_VALUE: + return Status::ILLEGAL_ARGUMENT ; + case -EBUSY: + return Status::CAMERA_IN_USE; + case -EUSERS: + return Status::MAX_CAMERAS_IN_USE; + case ::android::UNKNOWN_TRANSACTION: + return Status::METHOD_NOT_SUPPORTED; + case ::android::INVALID_OPERATION: + return Status::OPERATION_NOT_SUPPORTED; + case ::android::DEAD_OBJECT: + return Status::CAMERA_DISCONNECTED; + } + ALOGW("Unexpected HAL status code %d", s); + return Status::OPERATION_NOT_SUPPORTED; + } +} + +// Test environment for camera +class CameraHidlEnvironment : public ::testing::Environment { +public: + // get the test environment singleton + static CameraHidlEnvironment* Instance() { + static CameraHidlEnvironment* instance = new CameraHidlEnvironment; + return instance; + } + + virtual void SetUp() override; + virtual void TearDown() override; + + sp<ICameraProvider> mProvider; + +private: + CameraHidlEnvironment() {} + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment); +}; + +void CameraHidlEnvironment::SetUp() { + // TODO: test the binderized mode + mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(kCameraPassthroughServiceName); + // TODO: handle the device doesn't have any camera case + ALOGI_IF(mProvider, "provider is not nullptr, %p", mProvider.get()); + ASSERT_NE(mProvider, nullptr); +} + +void CameraHidlEnvironment::TearDown() { + ALOGI("TearDown CameraHidlEnvironment"); +} + +struct BufferItemHander: public BufferItemConsumer::FrameAvailableListener { + BufferItemHander(wp<BufferItemConsumer> consumer) : mConsumer(consumer) {} + + void onFrameAvailable(const android::BufferItem&) override { + sp<BufferItemConsumer> consumer = mConsumer.promote(); + ASSERT_NE(nullptr, consumer.get()); + + android::BufferItem buffer; + ASSERT_EQ(android::OK, consumer->acquireBuffer(&buffer, 0)); + ASSERT_EQ(android::OK, consumer->releaseBuffer(buffer)); + } + + private: + wp<BufferItemConsumer> mConsumer; +}; + +struct PreviewWindowCb : public ICameraDevicePreviewCallback { + PreviewWindowCb(sp<ANativeWindow> anw) : mPreviewWidth(0), + mPreviewHeight(0), mFormat(0), mPreviewUsage(0), + mPreviewSwapInterval(-1), mCrop{-1, -1, -1, -1}, mAnw(anw) {} + + using dequeueBuffer_cb = + std::function<void(Status status, uint64_t bufferId, + const hidl_handle& buffer, uint32_t stride)>; + Return<void> dequeueBuffer(dequeueBuffer_cb _hidl_cb) override; + + Return<Status> enqueueBuffer(uint64_t bufferId) override; + + Return<Status> cancelBuffer(uint64_t bufferId) override; + + Return<Status> setBufferCount(uint32_t count) override; + + Return<Status> setBuffersGeometry(uint32_t w, + uint32_t h, PixelFormat format) override; + + Return<Status> setCrop(int32_t left, int32_t top, + int32_t right, int32_t bottom) override; + + Return<Status> setUsage(ProducerUsage usage) override; + + Return<Status> setSwapInterval(int32_t interval) override; + + using getMinUndequeuedBufferCount_cb = + std::function<void(Status status, uint32_t count)>; + Return<void> getMinUndequeuedBufferCount( + getMinUndequeuedBufferCount_cb _hidl_cb) override; + + Return<Status> setTimestamp(int64_t timestamp) override; + + private: + struct BufferHasher { + size_t operator()(const buffer_handle_t& buf) const { + if (buf == nullptr) + return 0; + + size_t result = 1; + result = 31 * result + buf->numFds; + result = 31 * result + buf->numInts; + int length = buf->numFds + buf->numInts; + for (int i = 0; i < length; i++) { + result = 31 * result + buf->data[i]; + } + return result; + } + }; + + struct BufferComparator { + bool operator()(const buffer_handle_t& buf1, + const buffer_handle_t& buf2) const { + if ((buf1->numFds == buf2->numFds) && + (buf1->numInts == buf2->numInts)) { + int length = buf1->numFds + buf1->numInts; + for (int i = 0; i < length; i++) { + if (buf1->data[i] != buf2->data[i]) { + return false; + } + } + return true; + } + return false; + } + }; + + std::pair<bool, uint64_t> getBufferId(ANativeWindowBuffer* anb); + void cleanupCirculatingBuffers(); + + std::mutex mBufferIdMapLock; // protecting mBufferIdMap and mNextBufferId + typedef std::unordered_map<const buffer_handle_t, uint64_t, + BufferHasher, BufferComparator> BufferIdMap; + + BufferIdMap mBufferIdMap; // stream ID -> per stream buffer ID map + std::unordered_map<uint64_t, ANativeWindowBuffer*> mReversedBufMap; + uint64_t mNextBufferId = 1; + + uint32_t mPreviewWidth, mPreviewHeight; + int mFormat, mPreviewUsage; + int32_t mPreviewSwapInterval; + android_native_rect_t mCrop; + sp<ANativeWindow> mAnw; //Native window reference +}; + +std::pair<bool, uint64_t> PreviewWindowCb::getBufferId( + ANativeWindowBuffer* anb) { + std::lock_guard<std::mutex> lock(mBufferIdMapLock); + + buffer_handle_t& buf = anb->handle; + auto it = mBufferIdMap.find(buf); + if (it == mBufferIdMap.end()) { + uint64_t bufId = mNextBufferId++; + mBufferIdMap[buf] = bufId; + mReversedBufMap[bufId] = anb; + return std::make_pair(true, bufId); + } else { + return std::make_pair(false, it->second); + } +} + +void PreviewWindowCb::cleanupCirculatingBuffers() { + std::lock_guard<std::mutex> lock(mBufferIdMapLock); + mBufferIdMap.clear(); + mReversedBufMap.clear(); +} + +Return<void> PreviewWindowCb::dequeueBuffer(dequeueBuffer_cb _hidl_cb) { + ANativeWindowBuffer* anb; + auto rc = native_window_dequeue_buffer_and_wait(mAnw.get(), &anb); + uint64_t bufferId = 0; + uint32_t stride = 0; + hidl_handle buf = nullptr; + if (rc == ::android::OK) { + auto pair = getBufferId(anb); + buf = (pair.first) ? anb->handle : nullptr; + bufferId = pair.second; + stride = anb->stride; + } + + _hidl_cb(mapToStatus(rc), bufferId, buf, stride); + return Void(); +} + +Return<Status> PreviewWindowCb::enqueueBuffer(uint64_t bufferId) { + if (mReversedBufMap.count(bufferId) == 0) { + ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId); + return Status::ILLEGAL_ARGUMENT; + } + return mapToStatus(mAnw->queueBuffer(mAnw.get(), + mReversedBufMap.at(bufferId), -1)); +} + +Return<Status> PreviewWindowCb::cancelBuffer(uint64_t bufferId) { + if (mReversedBufMap.count(bufferId) == 0) { + ALOGE("%s: bufferId %" PRIu64 " not found", __FUNCTION__, bufferId); + return Status::ILLEGAL_ARGUMENT; + } + return mapToStatus(mAnw->cancelBuffer(mAnw.get(), + mReversedBufMap.at(bufferId), -1)); +} + +Return<Status> PreviewWindowCb::setBufferCount(uint32_t count) { + if (mAnw.get() != nullptr) { + // WAR for b/27039775 + native_window_api_disconnect(mAnw.get(), NATIVE_WINDOW_API_CAMERA); + native_window_api_connect(mAnw.get(), NATIVE_WINDOW_API_CAMERA); + if (mPreviewWidth != 0) { + native_window_set_buffers_dimensions(mAnw.get(), + mPreviewWidth, mPreviewHeight); + native_window_set_buffers_format(mAnw.get(), mFormat); + } + if (mPreviewUsage != 0) { + native_window_set_usage(mAnw.get(), mPreviewUsage); + } + if (mPreviewSwapInterval >= 0) { + mAnw->setSwapInterval(mAnw.get(), mPreviewSwapInterval); + } + if (mCrop.left >= 0) { + native_window_set_crop(mAnw.get(), &(mCrop)); + } + } + + auto rc = native_window_set_buffer_count(mAnw.get(), count); + if (rc == ::android::OK) { + cleanupCirculatingBuffers(); + } + + return mapToStatus(rc); +} + +Return<Status> PreviewWindowCb::setBuffersGeometry(uint32_t w, uint32_t h, + PixelFormat format) { + auto rc = native_window_set_buffers_dimensions(mAnw.get(), w, h); + if (rc == ::android::OK) { + mPreviewWidth = w; + mPreviewHeight = h; + rc = native_window_set_buffers_format(mAnw.get(), + static_cast<int>(format)); + if (rc == ::android::OK) { + mFormat = static_cast<int>(format); + } + } + + return mapToStatus(rc); +} + +Return<Status> PreviewWindowCb::setCrop(int32_t left, int32_t top, + int32_t right, int32_t bottom) { + android_native_rect_t crop = { left, top, right, bottom }; + auto rc = native_window_set_crop(mAnw.get(), &crop); + if (rc == ::android::OK) { + mCrop = crop; + } + return mapToStatus(rc); +} + +Return<Status> PreviewWindowCb::setUsage(ProducerUsage usage) { + auto rc = native_window_set_usage(mAnw.get(), static_cast<int>(usage)); + if (rc == ::android::OK) { + mPreviewUsage = static_cast<int>(usage); + } + return mapToStatus(rc); +} + +Return<Status> PreviewWindowCb::setSwapInterval(int32_t interval) { + auto rc = mAnw->setSwapInterval(mAnw.get(), interval); + if (rc == ::android::OK) { + mPreviewSwapInterval = interval; + } + return mapToStatus(rc); +} + +Return<void> PreviewWindowCb::getMinUndequeuedBufferCount( + getMinUndequeuedBufferCount_cb _hidl_cb) { + int count = 0; + auto rc = mAnw->query(mAnw.get(), + NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &count); + _hidl_cb(mapToStatus(rc), count); + return Void(); +} + +Return<Status> PreviewWindowCb::setTimestamp(int64_t timestamp) { + return mapToStatus(native_window_set_buffers_timestamp(mAnw.get(), + timestamp)); +} + +// The main test class for camera HIDL HAL. +class CameraHidlTest : public ::testing::VtsHalHidlTargetTestBase { +public: + virtual void SetUp() override {} + virtual void TearDown() override {} + + hidl_vec<hidl_string> getCameraDeviceNames(); + + struct EmptyDeviceCb : public ICameraDeviceCallback { + virtual Return<void> processCaptureResult(const CaptureResult& /*result*/) override { + ALOGI("processCaptureResult callback"); + ADD_FAILURE(); // Empty callback should not reach here + return Void(); + } + + virtual Return<void> notify(const NotifyMsg& /*msg*/) override { + ALOGI("notify callback"); + ADD_FAILURE(); // Empty callback should not reach here + return Void(); + } + }; + + struct DeviceCb : public ICameraDeviceCallback { + DeviceCb(CameraHidlTest *parent) : mParent(parent) {} + Return<void> processCaptureResult(const CaptureResult& result) override; + Return<void> notify(const NotifyMsg& msg) override; + + private: + CameraHidlTest *mParent; // Parent object + }; + + struct TorchProviderCb : public ICameraProviderCallback { + TorchProviderCb(CameraHidlTest *parent) : mParent(parent) {} + virtual Return<void> cameraDeviceStatusChange( + const hidl_string&, CameraDeviceStatus) override { + return Void(); + } + + virtual Return<void> torchModeStatusChange( + const hidl_string&, TorchModeStatus newStatus) override { + std::lock_guard<std::mutex> l(mParent->mTorchLock); + mParent->mTorchStatus = newStatus; + mParent->mTorchCond.notify_one(); + return Void(); + } + + private: + CameraHidlTest *mParent; // Parent object + }; + + struct Camera1DeviceCb : + public ::android::hardware::camera::device::V1_0::ICameraDeviceCallback { + Camera1DeviceCb(CameraHidlTest *parent) : mParent(parent) {} + + Return<void> notifyCallback(NotifyCallbackMsg msgType, + int32_t ext1, int32_t ext2) override; + + Return<uint32_t> registerMemory(const hidl_handle& descriptor, + uint32_t bufferSize, uint32_t bufferCount) override; + + Return<void> unregisterMemory(uint32_t memId) override; + + Return<void> dataCallback(DataCallbackMsg msgType, + uint32_t data, uint32_t bufferIndex, + const CameraFrameMetadata& metadata) override; + + Return<void> dataCallbackTimestamp(DataCallbackMsg msgType, + uint32_t data, uint32_t bufferIndex, + int64_t timestamp) override; + + Return<void> handleCallbackTimestamp(DataCallbackMsg msgType, + const hidl_handle& frameData,uint32_t data, + uint32_t bufferIndex, int64_t timestamp) override; + + private: + CameraHidlTest *mParent; // Parent object + }; + + void openCameraDevice(const std::string &name,const CameraHidlEnvironment* env, + sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device /*out*/); + void setupPreviewWindow( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, + sp<BufferItemConsumer> *bufferItemConsumer /*out*/, + sp<BufferItemHander> *bufferHandler /*out*/); + void stopPreviewAndClose( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device); + void startPreview( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device); + void enableMsgType(unsigned int msgType, + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device); + void disableMsgType(unsigned int msgType, + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device); + void getParameters( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, + CameraParameters *cameraParams /*out*/); + void setParameters( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, + const CameraParameters &cameraParams); + void waitForFrameLocked(DataCallbackMsg msgFrame, + std::unique_lock<std::mutex> &l); + void openEmptyDeviceSession(const std::string &name, + const CameraHidlEnvironment* env, + sp<ICameraDeviceSession> *session /*out*/, + camera_metadata_t **staticMeta /*out*/); + void configurePreviewStream(const std::string &name, + const CameraHidlEnvironment* env, + const AvailableStream *previewThreshold, + sp<ICameraDeviceSession> *session /*out*/, + Stream *previewStream /*out*/, + HalStreamConfiguration *halStreamConfig /*out*/); + static Status getAvailableOutputStreams(camera_metadata_t *staticMeta, + std::vector<AvailableStream> &outputStreams, + const AvailableStream *threshold = nullptr); + static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta); + static Status pickConstrainedModeSize(camera_metadata_t *staticMeta, + AvailableStream &hfrStream); + static Status isZSLModeAvailable(camera_metadata_t *staticMeta); + static Status getZSLInputOutputMap(camera_metadata_t *staticMeta, + std::vector<AvailableZSLInputOutput> &inputOutputMap); + static Status findLargestSize( + const std::vector<AvailableStream> &streamSizes, + int32_t format, AvailableStream &result); + static Status isAutoFocusModeAvailable( + ::android::CameraParameters &cameraParams, const char *mode) ; + +protected: + std::mutex mLock; // Synchronize access to member variables + std::condition_variable mResultCondition; // Condition variable for incoming results + uint32_t mResultFrameNumber; // Expected result frame number + std::vector<StreamBuffer> mResultBuffers; // Holds stream buffers from capture result + std::vector<ErrorMsg> mErrors; // Holds incoming error notifications + DataCallbackMsg mDataMessageTypeReceived; // Most recent message type received through data callbacks + uint32_t mVideoBufferIndex; // Buffer index of the most recent video buffer + uint32_t mVideoData; // Buffer data of the most recent video buffer + hidl_handle mVideoNativeHandle; // Most recent video buffer native handle + NotifyCallbackMsg mNotifyMessage; // Current notification message + + std::mutex mTorchLock; // Synchronize access to torch status + std::condition_variable mTorchCond; // Condition variable for torch status + TorchModeStatus mTorchStatus; // Current torch status + + // Holds camera registered buffers + std::unordered_map<uint32_t, sp<::android::MemoryHeapBase> > mMemoryPool; +}; + +Return<void> CameraHidlTest::Camera1DeviceCb::notifyCallback( + NotifyCallbackMsg msgType, int32_t ext1 __unused, + int32_t ext2 __unused) { + std::unique_lock<std::mutex> l(mParent->mLock); + mParent->mNotifyMessage = msgType; + mParent->mResultCondition.notify_one(); + + return Void(); +} + +Return<uint32_t> CameraHidlTest::Camera1DeviceCb::registerMemory( + const hidl_handle& descriptor, uint32_t bufferSize, + uint32_t bufferCount) { + if (descriptor->numFds != 1) { + ADD_FAILURE() << "camera memory descriptor has" + " numFds " << descriptor->numFds << " (expect 1)" ; + return 0; + } + if (descriptor->data[0] < 0) { + ADD_FAILURE() << "camera memory descriptor has" + " FD " << descriptor->data[0] << " (expect >= 0)"; + return 0; + } + + sp<::android::MemoryHeapBase> pool = new ::android::MemoryHeapBase( + descriptor->data[0], bufferSize*bufferCount, 0, 0); + mParent->mMemoryPool.emplace(pool->getHeapID(), pool); + + return pool->getHeapID(); +} + +Return<void> CameraHidlTest::Camera1DeviceCb::unregisterMemory(uint32_t memId) { + if (mParent->mMemoryPool.count(memId) == 0) { + ALOGE("%s: memory pool ID %d not found", __FUNCTION__, memId); + ADD_FAILURE(); + return Void(); + } + + mParent->mMemoryPool.erase(memId); + return Void(); +} + +Return<void> CameraHidlTest::Camera1DeviceCb::dataCallback( + DataCallbackMsg msgType __unused, uint32_t data __unused, + uint32_t bufferIndex __unused, + const CameraFrameMetadata& metadata __unused) { + std::unique_lock<std::mutex> l(mParent->mLock); + mParent->mDataMessageTypeReceived = msgType; + mParent->mResultCondition.notify_one(); + + return Void(); +} + +Return<void> CameraHidlTest::Camera1DeviceCb::dataCallbackTimestamp( + DataCallbackMsg msgType, uint32_t data, + uint32_t bufferIndex, int64_t timestamp __unused) { + std::unique_lock<std::mutex> l(mParent->mLock); + mParent->mDataMessageTypeReceived = msgType; + mParent->mVideoBufferIndex = bufferIndex; + if (mParent->mMemoryPool.count(data) == 0) { + ADD_FAILURE() << "memory pool ID " << data << "not found"; + } + mParent->mVideoData = data; + mParent->mResultCondition.notify_one(); + + return Void(); +} + +Return<void> CameraHidlTest::Camera1DeviceCb::handleCallbackTimestamp( + DataCallbackMsg msgType, const hidl_handle& frameData, + uint32_t data __unused, uint32_t bufferIndex, + int64_t timestamp __unused) { + std::unique_lock<std::mutex> l(mParent->mLock); + mParent->mDataMessageTypeReceived = msgType; + mParent->mVideoBufferIndex = bufferIndex; + if (mParent->mMemoryPool.count(data) == 0) { + ADD_FAILURE() << "memory pool ID " << data << " not found"; + } + mParent->mVideoData = data; + mParent->mVideoNativeHandle = frameData; + mParent->mResultCondition.notify_one(); + + return Void(); +} + +Return<void> CameraHidlTest::DeviceCb::processCaptureResult( + const CaptureResult& result) { + if (nullptr == mParent) { + return Void(); + } + + std::unique_lock<std::mutex> l(mParent->mLock); + + if(mParent->mResultFrameNumber != result.frameNumber) { + ALOGE("%s: Unexpected frame number! Expected: %u received: %u", + __func__, mParent->mResultFrameNumber, result.frameNumber); + ADD_FAILURE(); + } + + size_t resultLength = result.outputBuffers.size(); + for (size_t i = 0; i < resultLength; i++) { + mParent->mResultBuffers.push_back(result.outputBuffers[i]); + } + + // TODO(epeev): Handle partial results in case client supports them and + // verify the result against request settings. + + l.unlock(); + mParent->mResultCondition.notify_one(); + + return Void(); +} + +Return<void> CameraHidlTest::DeviceCb::notify( + const NotifyMsg& message) { + + if (MsgType::ERROR == message.type) { + { + std::lock_guard<std::mutex> l(mParent->mLock); + mParent->mErrors.push_back(message.msg.error); + } + + if ((ErrorCode::ERROR_REQUEST == message.msg.error.errorCode) + || (ErrorCode::ERROR_BUFFER == message.msg.error.errorCode)) { + mParent->mResultCondition.notify_one(); + } + } + + return Void(); +} + +hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames() { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames; + Return<void> ret; + ret = env->mProvider->getCameraIdList( + [&](auto status, const auto& idList) { + ALOGI("getCameraIdList returns status:%d", (int)status); + for (size_t i = 0; i < idList.size(); i++) { + ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str()); + } + ASSERT_EQ(Status::OK, status); + cameraDeviceNames = idList; + }); + if (!ret.isOk()) { + ADD_FAILURE(); + } + return cameraDeviceNames; +} + +// Test if ICameraProvider::isTorchModeSupported returns Status::OK +TEST_F(CameraHidlTest, isTorchModeSupported) { + Return<void> ret; + ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported( + [&](auto status, bool support) { + ALOGI("isSetTorchModeSupported returns status:%d supported:%d", + (int)status, support); + ASSERT_EQ(Status::OK, status); + }); + ASSERT_TRUE(ret.isOk()); +} + +// TODO: consider removing this test if getCameraDeviceNames() has the same coverage +TEST_F(CameraHidlTest, getCameraIdList) { + Return<void> ret; + ret = CameraHidlEnvironment::Instance()->mProvider->getCameraIdList( + [&](auto status, const auto& idList) { + ALOGI("getCameraIdList returns status:%d", (int)status); + for (size_t i = 0; i < idList.size(); i++) { + ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str()); + } + ASSERT_EQ(Status::OK, status); + // This is true for internal camera provider. + // Not necessary hold for external cameras providers + ASSERT_GT(idList.size(), 0u); + }); + ASSERT_TRUE(ret.isOk()); +} + +// Test if ICameraProvider::getVendorTags returns Status::OK +TEST_F(CameraHidlTest, getVendorTags) { + Return<void> ret; + ret = CameraHidlEnvironment::Instance()->mProvider->getVendorTags( + [&](auto status, const auto& vendorTagSecs) { + ALOGI("getVendorTags returns status:%d numSections %zu", + (int)status, vendorTagSecs.size()); + for (size_t i = 0; i < vendorTagSecs.size(); i++) { + ALOGI("Vendor tag section %zu name %s", + i, vendorTagSecs[i].sectionName.c_str()); + for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) { + const auto& tag = vendorTagSecs[i].tags[j]; + ALOGI("Vendor tag id %u name %s type %d", + tag.tagId, + tag.tagName.c_str(), + (int) tag.tagType); + } + } + ASSERT_EQ(Status::OK, status); + }); + ASSERT_TRUE(ret.isOk()); +} + +// Test if ICameraProvider::setCallback returns Status::OK +TEST_F(CameraHidlTest, setCallback) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + struct ProviderCb : public ICameraProviderCallback { + virtual Return<void> cameraDeviceStatusChange( + const hidl_string& cameraDeviceName, + CameraDeviceStatus newStatus) override { + ALOGI("camera device status callback name %s, status %d", + cameraDeviceName.c_str(), (int) newStatus); + return Void(); + } + + virtual Return<void> torchModeStatusChange( + const hidl_string& cameraDeviceName, + TorchModeStatus newStatus) override { + ALOGI("Torch mode status callback name %s, status %d", + cameraDeviceName.c_str(), (int) newStatus); + return Void(); + } + }; + sp<ProviderCb> cb = new ProviderCb; + auto status = env->mProvider->setCallback(cb); + ASSERT_TRUE(status.isOk()); + ASSERT_EQ(Status::OK, status); +} + +// Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device +TEST_F(CameraHidlTest, getCameraDeviceInterface) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device3_2) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device3_2, nullptr); + }); + ASSERT_TRUE(ret.isOk()); + } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V1_x( + name, + [&](auto status, const auto& device1) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device1, nullptr); + }); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Verify that the device resource cost can be retrieved and the values are +// sane. +TEST_F(CameraHidlTest, getResourceCost) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + ALOGI("getResourceCost: Testing camera device %s", name.c_str()); + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device3_2 = device; + }); + ASSERT_TRUE(ret.isOk()); + + ret = device3_2->getResourceCost( + [&](auto status, const auto& resourceCost) { + ALOGI("getResourceCost returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ALOGI(" Resource cost is %d", resourceCost.resourceCost); + ASSERT_LE(resourceCost.resourceCost, 100u); + for (const auto& name : resourceCost.conflictingDevices) { + ALOGI(" Conflicting device: %s", name.c_str()); + } + }); + ASSERT_TRUE(ret.isOk()); + } else { + ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + ALOGI("getResourceCost: Testing camera device %s", name.c_str()); + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V1_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device1 = device; + }); + ASSERT_TRUE(ret.isOk()); + + ret = device1->getResourceCost( + [&](auto status, const auto& resourceCost) { + ALOGI("getResourceCost returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ALOGI(" Resource cost is %d", resourceCost.resourceCost); + ASSERT_LE(resourceCost.resourceCost, 100u); + for (const auto& name : resourceCost.conflictingDevices) { + ALOGI(" Conflicting device: %s", name.c_str()); + } + }); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Verify that the static camera info can be retrieved +// successfully. +TEST_F(CameraHidlTest, getCameraInfo) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str()); + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V1_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device1 = device; + }); + ASSERT_TRUE(ret.isOk()); + + ret = device1->getCameraInfo( + [&](auto status, const auto& info) { + ALOGI("getCameraInfo returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + switch(info.orientation) { + case 0: + case 90: + case 180: + case 270: + //Expected cases + ALOGI("camera orientation: %d", info.orientation); + break; + default: + FAIL() << "Unexpected camera orientation:" << info.orientation; + } + switch(info.facing) { + case CameraFacing::BACK: + case CameraFacing::FRONT: + case CameraFacing::EXTERNAL: + //Expected cases + ALOGI("camera facing: %d", info.facing); + break; + default: + FAIL() << "Unexpected camera facing:" << static_cast<uint32_t> (info.facing); + } + }); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Check whether preview window can be configured +TEST_F(CameraHidlTest, setPreviewWindow) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, + &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + + Return<void> ret; + ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Verify that setting preview window fails in case device is not open +TEST_F(CameraHidlTest, setPreviewWindowInvalid) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str()); + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V1_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device1 = device; + }); + ASSERT_TRUE(ret.isOk()); + + Return<Status> returnStatus = device1->setPreviewWindow(nullptr); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OPERATION_NOT_SUPPORTED, returnStatus); + } + } +} + +// Start and stop preview checking whether it gets enabled in between. +TEST_F(CameraHidlTest, startStopPreview) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, + &bufferItemConsumer /*out*/, &bufferHandler /*out*/); + + startPreview(device1); + + Return<bool> returnBoolStatus = device1->previewEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_TRUE(returnBoolStatus); + + stopPreviewAndClose(device1); + } + } +} + +// Start preview without active preview window. Preview should start as soon +// as a valid active window gets configured. +TEST_F(CameraHidlTest, startStopPreviewDelayed) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + Return<Status> returnStatus = device1->setPreviewWindow(nullptr); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + startPreview(device1); + + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, + &bufferHandler /*out*/); + + //Preview should get enabled now + Return<bool> returnBoolStatus = device1->previewEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_TRUE(returnBoolStatus); + + stopPreviewAndClose(device1); + } + } +} + +// Verify that image capture behaves as expected along with preview callbacks. +TEST_F(CameraHidlTest, takePicture) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, + &bufferHandler /*out*/); + + { + std::unique_lock<std::mutex> l(mLock); + mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; + } + + enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); + startPreview(device1); + + { + std::unique_lock<std::mutex> l(mLock); + waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l); + } + + disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, + device1); + enableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE, + device1); + + { + std::unique_lock<std::mutex> l(mLock); + mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; + } + + Return<Status> returnStatus = device1->takePicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + { + std::unique_lock<std::mutex> l(mLock); + waitForFrameLocked(DataCallbackMsg::COMPRESSED_IMAGE, l); + } + + disableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE, + device1); + stopPreviewAndClose(device1); + } + } +} + +// Image capture should fail in case preview didn't get enabled first. +TEST_F(CameraHidlTest, takePictureFail) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + Return<Status> returnStatus = device1->takePicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_NE(Status::OK, returnStatus); + + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Verify that image capture can be cancelled. +TEST_F(CameraHidlTest, cancelPicture) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, + &bufferHandler /*out*/); + startPreview(device1); + + Return<Status> returnStatus = device1->takePicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + returnStatus = device1->cancelPicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + stopPreviewAndClose(device1); + } + } +} + +// Image capture cancel should fail when image capture is not running. +TEST_F(CameraHidlTest, cancelPictureFail) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, + &bufferHandler /*out*/); + startPreview(device1); + + Return<Status> returnStatus = device1->cancelPicture(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_NE(Status::OK, returnStatus); + + stopPreviewAndClose(device1); + } + } +} + +// Test basic video recording. +TEST_F(CameraHidlTest, startStopRecording) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, + &bufferHandler /*out*/); + + { + std::unique_lock<std::mutex> l(mLock); + mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; + } + + enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); + startPreview(device1); + + { + std::unique_lock<std::mutex> l(mLock); + waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l); + mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY; + mVideoBufferIndex = UINT32_MAX; + } + + disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1); + + bool videoMetaEnabled = false; + Return<Status> returnStatus = device1->storeMetaDataInBuffers(true); + ASSERT_TRUE(returnStatus.isOk()); + // It is allowed for devices to not support this feature + ASSERT_TRUE((Status::OK == returnStatus) || + (Status::OPERATION_NOT_SUPPORTED == returnStatus)); + if (Status::OK == returnStatus) { + videoMetaEnabled = true; + } + + enableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, device1); + Return<bool> returnBoolStatus = device1->recordingEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_FALSE(returnBoolStatus); + + returnStatus = device1->startRecording(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + { + std::unique_lock<std::mutex> l(mLock); + waitForFrameLocked(DataCallbackMsg::VIDEO_FRAME, l); + ASSERT_NE(UINT32_MAX, mVideoBufferIndex); + disableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, + device1); + } + + returnBoolStatus = device1->recordingEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_TRUE(returnBoolStatus); + + Return<void> ret; + if (videoMetaEnabled) { + ret = device1->releaseRecordingFrameHandle(mVideoData, + mVideoBufferIndex, mVideoNativeHandle); + ASSERT_TRUE(ret.isOk()); + } else { + ret = device1->releaseRecordingFrame(mVideoData, mVideoBufferIndex); + ASSERT_TRUE(ret.isOk()); + } + + ret = device1->stopRecording(); + ASSERT_TRUE(ret.isOk()); + + stopPreviewAndClose(device1); + } + } +} + +// It shouldn't be possible to start recording without enabling preview first. +TEST_F(CameraHidlTest, startRecordingFail) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + Return<bool> returnBoolStatus = device1->recordingEnabled(); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_FALSE(returnBoolStatus); + + Return<Status> returnStatus = device1->startRecording(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_NE(Status::OK, returnStatus); + + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Check autofocus support if available. +TEST_F(CameraHidlTest, autoFocus) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<const char *> focusModes = {CameraParameters::FOCUS_MODE_AUTO, + CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE, + CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO}; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + ::android::CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); + + if (Status::OK != isAutoFocusModeAvailable(cameraParams, + CameraParameters::FOCUS_MODE_AUTO)) { + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } + + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, + &bufferHandler /*out*/); + startPreview(device1); + enableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1); + + for (auto &iter : focusModes) { + if (Status::OK != isAutoFocusModeAvailable(cameraParams, + iter)) { + continue; + } + + cameraParams.set(CameraParameters::KEY_FOCUS_MODE, iter); + setParameters(device1, cameraParams); + { + std::unique_lock<std::mutex> l(mLock); + mNotifyMessage = NotifyCallbackMsg::ERROR; + } + + Return<Status> returnStatus = device1->autoFocus(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + { + std::unique_lock<std::mutex> l(mLock); + while (NotifyCallbackMsg::FOCUS != mNotifyMessage) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kAutoFocusTimeoutSec); + ASSERT_NE(std::cv_status::timeout, + mResultCondition.wait_until(l, timeout)); + } + } + } + + disableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1); + stopPreviewAndClose(device1); + } + } +} + +// In case autofocus is supported verify that it can be cancelled. +TEST_F(CameraHidlTest, cancelAutoFocus) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + ::android::CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); + + if (Status::OK != isAutoFocusModeAvailable(cameraParams, + CameraParameters::FOCUS_MODE_AUTO)) { + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } + + // It should be fine to call before preview starts. + ASSERT_EQ(Status::OK, device1->cancelAutoFocus()); + + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, + &bufferHandler /*out*/); + startPreview(device1); + + // It should be fine to call after preview starts too. + Return<Status> returnStatus = device1->cancelAutoFocus(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + returnStatus = device1->autoFocus(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + returnStatus = device1->cancelAutoFocus(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + stopPreviewAndClose(device1); + } + } +} + +// Check whether face detection is available and try to enable&disable. +TEST_F(CameraHidlTest, sendCommandFaceDetection) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + ::android::CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); + + int32_t hwFaces = cameraParams.getInt( + CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW); + int32_t swFaces = cameraParams.getInt( + CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW); + if ((0 >= hwFaces) && (0 >= swFaces)) { + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } + + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, + &bufferHandler /*out*/); + startPreview(device1); + + if (0 < hwFaces) { + Return<Status> returnStatus = device1->sendCommand( + CommandType::START_FACE_DETECTION, + CAMERA_FACE_DETECTION_HW, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + // TODO(epeev) : Enable and check for face notifications + returnStatus = device1->sendCommand( + CommandType::STOP_FACE_DETECTION, + CAMERA_FACE_DETECTION_HW, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + } + + if (0 < swFaces) { + Return<Status> returnStatus = device1->sendCommand( + CommandType::START_FACE_DETECTION, + CAMERA_FACE_DETECTION_SW, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + // TODO(epeev) : Enable and check for face notifications + returnStatus = device1->sendCommand( + CommandType::STOP_FACE_DETECTION, + CAMERA_FACE_DETECTION_SW, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + } + + stopPreviewAndClose(device1); + } + } +} + +// Check whether smooth zoom is available and try to enable&disable. +TEST_F(CameraHidlTest, sendCommandSmoothZoom) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + ::android::CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); + + const char *smoothZoomStr = cameraParams.get( + CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED); + bool smoothZoomSupported = ((nullptr != smoothZoomStr) && + (strcmp(smoothZoomStr, CameraParameters::TRUE) == 0)) ? + true : false; + if (!smoothZoomSupported) { + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } + + int32_t maxZoom = cameraParams.getInt( + CameraParameters::KEY_MAX_ZOOM); + ASSERT_TRUE(0 < maxZoom); + + sp<BufferItemConsumer> bufferItemConsumer; + sp<BufferItemHander> bufferHandler; + setupPreviewWindow(device1, &bufferItemConsumer /*out*/, + &bufferHandler /*out*/); + startPreview(device1); + setParameters(device1, cameraParams); + + Return<Status> returnStatus = device1->sendCommand( + CommandType::START_SMOOTH_ZOOM, maxZoom, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + // TODO(epeev) : Enable and check for face notifications + returnStatus = device1->sendCommand(CommandType::STOP_SMOOTH_ZOOM, + 0, 0); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + stopPreviewAndClose(device1); + } + } +} + +// Basic sanity tests related to camera parameters. +TEST_F(CameraHidlTest, getSetParameters) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + ::android::CameraParameters cameraParams; + getParameters(device1, &cameraParams /*out*/); + + int32_t width, height; + cameraParams.getPictureSize(&width, &height); + ASSERT_TRUE((0 < width) && (0 < height)); + cameraParams.getPreviewSize(&width, &height); + ASSERT_TRUE((0 < width) && (0 < height)); + int32_t minFps, maxFps; + cameraParams.getPreviewFpsRange(&minFps, &maxFps); + ASSERT_TRUE((0 < minFps) && (0 < maxFps)); + ASSERT_NE(nullptr, cameraParams.getPreviewFormat()); + ASSERT_NE(nullptr, cameraParams.getPictureFormat()); + ASSERT_TRUE(strcmp(CameraParameters::PIXEL_FORMAT_JPEG, + cameraParams.getPictureFormat()) == 0); + + const char *flashMode = cameraParams.get( + CameraParameters::KEY_FLASH_MODE); + ASSERT_TRUE((nullptr == flashMode) || (strcmp( + CameraParameters::FLASH_MODE_OFF, flashMode) == 0)); + + const char *wbMode = cameraParams.get( + CameraParameters::KEY_WHITE_BALANCE); + ASSERT_TRUE((nullptr == wbMode) || (strcmp( + CameraParameters::WHITE_BALANCE_AUTO, wbMode) == 0)); + + const char *effect = cameraParams.get(CameraParameters::KEY_EFFECT); + ASSERT_TRUE((nullptr == effect) || (strcmp( + CameraParameters::EFFECT_NONE, effect) == 0)); + + ::android::Vector<::android::Size> previewSizes; + cameraParams.getSupportedPreviewSizes(previewSizes); + ASSERT_FALSE(previewSizes.empty()); + ::android::Vector<::android::Size> pictureSizes; + cameraParams.getSupportedPictureSizes(pictureSizes); + ASSERT_FALSE(pictureSizes.empty()); + const char *previewFormats = cameraParams.get( + CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS); + ASSERT_NE(nullptr, previewFormats); + ::android::String8 previewFormatsString(previewFormats); + ASSERT_TRUE(previewFormatsString.contains( + CameraParameters::PIXEL_FORMAT_YUV420SP)); + ASSERT_NE(nullptr, cameraParams.get( + CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS)); + ASSERT_NE(nullptr, cameraParams.get( + CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)); + const char *focusModes = cameraParams.get( + CameraParameters::KEY_SUPPORTED_FOCUS_MODES); + ASSERT_NE(nullptr, focusModes); + ::android::String8 focusModesString(focusModes); + const char *focusMode = cameraParams.get( + CameraParameters::KEY_FOCUS_MODE); + ASSERT_NE(nullptr, focusMode); + // Auto focus mode should be default + if (focusModesString.contains(CameraParameters::FOCUS_MODE_AUTO)) { + ASSERT_TRUE(strcmp( + CameraParameters::FOCUS_MODE_AUTO, focusMode) == 0); + } + ASSERT_TRUE(0 < cameraParams.getInt( + CameraParameters::KEY_FOCAL_LENGTH)); + int32_t horizontalViewAngle = cameraParams.getInt( + CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE); + ASSERT_TRUE((0 < horizontalViewAngle) && (360 >= horizontalViewAngle)); + int32_t verticalViewAngle = cameraParams.getInt( + CameraParameters::KEY_VERTICAL_VIEW_ANGLE); + ASSERT_TRUE((0 < verticalViewAngle) && (360 >= verticalViewAngle)); + int32_t jpegQuality = cameraParams.getInt( + CameraParameters::KEY_JPEG_QUALITY); + ASSERT_TRUE((1 <= jpegQuality) && (100 >= jpegQuality)); + int32_t jpegThumbQuality = cameraParams.getInt( + CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); + ASSERT_TRUE((1 <= jpegThumbQuality) && (100 >= jpegThumbQuality)); + + cameraParams.setPictureSize(pictureSizes[0].width, + pictureSizes[0].height); + cameraParams.setPreviewSize(previewSizes[0].width, + previewSizes[0].height); + + setParameters(device1, cameraParams); + getParameters(device1, &cameraParams /*out*/); + + cameraParams.getPictureSize(&width, &height); + ASSERT_TRUE((pictureSizes[0].width == width) && + (pictureSizes[0].height == height)); + cameraParams.getPreviewSize(&width, &height); + ASSERT_TRUE((previewSizes[0].width == width) && + (previewSizes[0].height == height)); + + Return<void> ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Verify that the static camera characteristics can be retrieved +// successfully. +TEST_F(CameraHidlTest, getCameraCharacteristics) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str()); + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device3_2 = device; + }); + ASSERT_TRUE(ret.isOk()); + + ret = device3_2->getCameraCharacteristics( + [&](auto status, const auto& chars) { + ALOGI("getCameraCharacteristics returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + const camera_metadata_t* metadata = (camera_metadata_t*) chars.data(); + size_t expectedSize = chars.size(); + ASSERT_EQ(0, validate_camera_metadata_structure(metadata, &expectedSize)); + size_t entryCount = get_camera_metadata_entry_count(metadata); + // TODO: we can do better than 0 here. Need to check how many required + // characteristics keys we've defined. + ASSERT_GT(entryCount, 0u); + ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount); + }); + ASSERT_TRUE(ret.isOk()); + } + } +} + +//In case it is supported verify that torch can be enabled. +//Check for corresponding toch callbacks as well. +TEST_F(CameraHidlTest, setTorchMode) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + bool torchControlSupported = false; + Return<void> ret; + + ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported( + [&](auto status, bool support) { + ALOGI("isSetTorchModeSupported returns status:%d supported:%d", + (int)status, support); + ASSERT_EQ(Status::OK, status); + torchControlSupported = support; + }); + + + sp<TorchProviderCb> cb = new TorchProviderCb(this); + Return<Status> returnStatus = env->mProvider->setCallback(cb); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + ALOGI("setTorchMode: Testing camera device %s", name.c_str()); + ret = env->mProvider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device3_2 = device; + }); + ASSERT_TRUE(ret.isOk()); + + mTorchStatus = TorchModeStatus::NOT_AVAILABLE; + returnStatus = device3_2->setTorchMode(TorchMode::ON); + ASSERT_TRUE(returnStatus.isOk()); + if (!torchControlSupported) { + ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus); + } else { + ASSERT_TRUE(returnStatus == Status::OK || + returnStatus == Status::OPERATION_NOT_SUPPORTED); + if (returnStatus == Status::OK) { + { + std::unique_lock<std::mutex> l(mTorchLock); + while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kTorchTimeoutSec); + ASSERT_NE(std::cv_status::timeout, + mTorchCond.wait_until(l, timeout)); + } + ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus); + mTorchStatus = TorchModeStatus::NOT_AVAILABLE; + } + + returnStatus = device3_2->setTorchMode(TorchMode::OFF); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + { + std::unique_lock<std::mutex> l(mTorchLock); + while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kTorchTimeoutSec); + ASSERT_NE(std::cv_status::timeout, + mTorchCond.wait_until(l, timeout)); + } + ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus); + } + } + } + } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + ALOGI("dumpState: Testing camera device %s", name.c_str()); + ret = env->mProvider->getCameraDeviceInterface_V1_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device1 = device; + }); + ASSERT_TRUE(ret.isOk()); + + mTorchStatus = TorchModeStatus::NOT_AVAILABLE; + returnStatus = device1->setTorchMode(TorchMode::ON); + ASSERT_TRUE(returnStatus.isOk()); + if (!torchControlSupported) { + ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus); + } else { + ASSERT_TRUE(returnStatus == Status::OK || + returnStatus == Status::OPERATION_NOT_SUPPORTED); + if (returnStatus == Status::OK) { + { + std::unique_lock<std::mutex> l(mTorchLock); + while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kTorchTimeoutSec); + ASSERT_NE(std::cv_status::timeout, + mTorchCond.wait_until(l, timeout)); + } + ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus); + mTorchStatus = TorchModeStatus::NOT_AVAILABLE; + } + + returnStatus = device1->setTorchMode(TorchMode::OFF); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + { + std::unique_lock<std::mutex> l(mTorchLock); + while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kTorchTimeoutSec); + ASSERT_NE(std::cv_status::timeout, + mTorchCond.wait_until(l, timeout)); + } + ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus); + } + } + } + ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + } + } + + returnStatus = env->mProvider->setCallback(nullptr); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); +} + +// Check dump functionality. +TEST_F(CameraHidlTest, dumpState) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + Return<void> ret; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + ALOGI("dumpState: Testing camera device %s", name.c_str()); + ret = env->mProvider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device3_2 = device; + }); + ASSERT_TRUE(ret.isOk()); + + native_handle_t* raw_handle = native_handle_create(1, 0); + raw_handle->data[0] = open(kDumpOutput, O_RDWR); + ASSERT_GE(raw_handle->data[0], 0); + hidl_handle handle = raw_handle; + ret= device3_2->dumpState(handle); + ASSERT_TRUE(ret.isOk()); + close(raw_handle->data[0]); + native_handle_delete(raw_handle); + } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + ALOGI("dumpState: Testing camera device %s", name.c_str()); + ret = env->mProvider->getCameraDeviceInterface_V1_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device1 = device; + }); + ASSERT_TRUE(ret.isOk()); + + native_handle_t* raw_handle = native_handle_create(1, 0); + raw_handle->data[0] = open(kDumpOutput, O_RDWR); + ASSERT_GE(raw_handle->data[0], 0); + hidl_handle handle = raw_handle; + Return<Status> returnStatus = device1->dumpState(handle); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + close(raw_handle->data[0]); + native_handle_delete(raw_handle); + } + } +} + +// Open, dumpStates, then close +TEST_F(CameraHidlTest, openClose) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + Return<void> ret; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + ALOGI("openClose: Testing camera device %s", name.c_str()); + ret = env->mProvider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device3_2 = device; + }); + ASSERT_TRUE(ret.isOk()); + + sp<EmptyDeviceCb> cb = new EmptyDeviceCb; + sp<ICameraDeviceSession> session; + ret = device3_2->open( + cb, + [&](auto status, const auto& newSession) { + ALOGI("device::open returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(newSession, nullptr); + session = newSession; + }); + ASSERT_TRUE(ret.isOk()); + + native_handle_t* raw_handle = native_handle_create(1, 0); + raw_handle->data[0] = open(kDumpOutput, O_RDWR); + ASSERT_GE(raw_handle->data[0], 0); + hidl_handle handle = raw_handle; + ret = device3_2->dumpState(handle); + ASSERT_TRUE(ret.isOk()); + close(raw_handle->data[0]); + native_handle_delete(raw_handle); + + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + // TODO: test all session API calls return INTERNAL_ERROR after close + // TODO: keep a wp copy here and verify session cannot be promoted out of this scope + } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) { + sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1; + openCameraDevice(name, env, &device1 /*out*/); + ASSERT_NE(nullptr, device1.get()); + + native_handle_t* raw_handle = native_handle_create(1, 0); + raw_handle->data[0] = open(kDumpOutput, O_RDWR); + ASSERT_GE(raw_handle->data[0], 0); + hidl_handle handle = raw_handle; + Return<Status> returnStatus = device1->dumpState(handle); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + close(raw_handle->data[0]); + native_handle_delete(raw_handle); + + ret = device1->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Check whether all common default request settings can be sucessfully +// constructed. +TEST_F(CameraHidlTest, constructDefaultRequestSettings) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2; + Return<void> ret; + ALOGI("constructDefaultRequestSettings: Testing camera device %s", name.c_str()); + ret = env->mProvider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device3_2 = device; + }); + ASSERT_TRUE(ret.isOk()); + + sp<EmptyDeviceCb> cb = new EmptyDeviceCb; + sp<ICameraDeviceSession> session; + ret = device3_2->open( + cb, + [&](auto status, const auto& newSession) { + ALOGI("device::open returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(newSession, nullptr); + session = newSession; + }); + ASSERT_TRUE(ret.isOk()); + + for (uint32_t t = (uint32_t) RequestTemplate::PREVIEW; + t <= (uint32_t) RequestTemplate::MANUAL; t++) { + RequestTemplate reqTemplate = (RequestTemplate) t; + ret = session->constructDefaultRequestSettings( + reqTemplate, + [&](auto status, const auto& req) { + ALOGI("constructDefaultRequestSettings returns status:%d", (int)status); + if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG || + reqTemplate == RequestTemplate::MANUAL) { + // optional templates + ASSERT_TRUE(status == Status::OK || status == Status::ILLEGAL_ARGUMENT); + } else { + ASSERT_EQ(Status::OK, status); + } + + if (status == Status::OK) { + const camera_metadata_t* metadata = + (camera_metadata_t*) req.data(); + size_t expectedSize = req.size(); + ASSERT_EQ(0, validate_camera_metadata_structure( + metadata, &expectedSize)); + size_t entryCount = get_camera_metadata_entry_count(metadata); + // TODO: we can do better than 0 here. Need to check how many required + // request keys we've defined for each template + ASSERT_GT(entryCount, 0u); + ALOGI("template %u metadata entry count is %zu", t, entryCount); + } else { + ASSERT_EQ(0u, req.size()); + } + }); + ASSERT_TRUE(ret.isOk()); + } + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Verify that all supported stream formats and sizes can be configured +// successfully. +TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<AvailableStream> outputStreams; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + camera_metadata_t *staticMeta; + Return<void> ret; + sp<ICameraDeviceSession> session; + openEmptyDeviceSession(name, env, &session /*out*/, + &staticMeta /*out*/); + + outputStreams.clear(); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, + outputStreams)); + ASSERT_NE(0u, outputStreams.size()); + + int32_t streamId = 0; + for (auto &it : outputStreams) { + Stream stream = {streamId, StreamType::OUTPUT, + static_cast<uint32_t> (it.width), + static_cast<uint32_t> (it.height), + static_cast<PixelFormat> (it.format), 0, 0, + StreamRotation::ROTATION_0}; + ::android::hardware::hidl_vec<Stream> streams = {stream}; + StreamConfiguration config = {streams, + StreamConfigurationMode::NORMAL_MODE}; + ret = session->configureStreams(config, [streamId] (Status s, + HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + ASSERT_EQ(halConfig.streams[0].id, streamId); + }); + ASSERT_TRUE(ret.isOk()); + streamId++; + } + + free_camera_metadata(staticMeta); + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Check for correct handling of invalid/incorrect configuration parameters. +TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<AvailableStream> outputStreams; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + camera_metadata_t *staticMeta; + Return<void> ret; + sp<ICameraDeviceSession> session; + openEmptyDeviceSession(name, env, &session /*out*/, + &staticMeta /*out*/); + + outputStreams.clear(); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, + outputStreams)); + ASSERT_NE(0u, outputStreams.size()); + + int32_t streamId = 0; + Stream stream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (0), + static_cast<uint32_t> (0), + static_cast<PixelFormat> (outputStreams[0].format), + 0, 0, StreamRotation::ROTATION_0}; + ::android::hardware::hidl_vec<Stream> streams = {stream}; + StreamConfiguration config = {streams, + StreamConfigurationMode::NORMAL_MODE}; + ret = session->configureStreams(config, [] (Status s, + HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); + ASSERT_TRUE(ret.isOk()); + + stream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (UINT32_MAX), + static_cast<uint32_t> (UINT32_MAX), + static_cast<PixelFormat> (outputStreams[0].format), + 0, 0, StreamRotation::ROTATION_0}; + streams[0] = stream; + config = {streams, + StreamConfigurationMode::NORMAL_MODE}; + ret = session->configureStreams(config, [] (Status s, + HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + ASSERT_TRUE(ret.isOk()); + + for (auto &it : outputStreams) { + stream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (it.width), + static_cast<uint32_t> (it.height), + static_cast<PixelFormat> (UINT32_MAX), + 0, 0, StreamRotation::ROTATION_0}; + streams[0] = stream; + config = {streams, + StreamConfigurationMode::NORMAL_MODE}; + ret = session->configureStreams(config, [] (Status s, + HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + ASSERT_TRUE(ret.isOk()); + + stream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (it.width), + static_cast<uint32_t> (it.height), + static_cast<PixelFormat> (it.format), + 0, 0, static_cast<StreamRotation> (UINT32_MAX)}; + streams[0] = stream; + config = {streams, + StreamConfigurationMode::NORMAL_MODE}; + ret = session->configureStreams(config, [] (Status s, + HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + ASSERT_TRUE(ret.isOk()); + } + + free_camera_metadata(staticMeta); + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Check whether all supported ZSL output stream combinations can be +// configured successfully. +TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<AvailableStream> inputStreams; + std::vector<AvailableZSLInputOutput> inputOutputMap; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + camera_metadata_t *staticMeta; + Return<void> ret; + sp<ICameraDeviceSession> session; + openEmptyDeviceSession(name, env, &session /*out*/, + &staticMeta /*out*/); + + Status rc = isZSLModeAvailable(staticMeta); + if (Status::METHOD_NOT_SUPPORTED == rc) { + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } + ASSERT_EQ(Status::OK, rc); + + inputStreams.clear(); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, + inputStreams)); + ASSERT_NE(0u, inputStreams.size()); + + inputOutputMap.clear(); + ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, + inputOutputMap)); + ASSERT_NE(0u, inputOutputMap.size()); + + int32_t streamId = 0; + for (auto &inputIter : inputOutputMap) { + AvailableStream input; + ASSERT_EQ(Status::OK, + findLargestSize(inputStreams, inputIter.inputFormat, input)); + ASSERT_NE(0u, inputStreams.size()); + + AvailableStream outputThreshold = {INT32_MAX, INT32_MAX, + inputIter.outputFormat}; + std::vector<AvailableStream> outputStreams; + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, + outputStreams, &outputThreshold)); + for (auto &outputIter : outputStreams) { + Stream zslStream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (input.width), + static_cast<uint32_t> (input.height), + static_cast<PixelFormat> (input.format), + GRALLOC_USAGE_HW_CAMERA_ZSL, 0, + StreamRotation::ROTATION_0}; + Stream inputStream = {streamId++, StreamType::INPUT, + static_cast<uint32_t> (input.width), + static_cast<uint32_t> (input.height), + static_cast<PixelFormat> (input.format), 0, 0, + StreamRotation::ROTATION_0}; + Stream outputStream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (outputIter.width), + static_cast<uint32_t> (outputIter.height), + static_cast<PixelFormat> (outputIter.format), 0, 0, + StreamRotation::ROTATION_0}; + + ::android::hardware::hidl_vec<Stream> streams = { + inputStream, zslStream, outputStream}; + StreamConfiguration config = {streams, + StreamConfigurationMode::NORMAL_MODE}; + ret = session->configureStreams(config, [streamId] (Status s, + HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(3u, halConfig.streams.size()); + }); + ASSERT_TRUE(ret.isOk()); + } + } + + free_camera_metadata(staticMeta); + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Verify that all supported preview + still capture stream combinations +// can be configured successfully. +TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<AvailableStream> outputBlobStreams; + std::vector<AvailableStream> outputPreviewStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + AvailableStream blobThreshold = {INT32_MAX, INT32_MAX, + static_cast<int32_t>(PixelFormat::BLOB)}; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + camera_metadata_t *staticMeta; + Return<void> ret; + sp<ICameraDeviceSession> session; + openEmptyDeviceSession(name, env, &session /*out*/, + &staticMeta /*out*/); + + outputBlobStreams.clear(); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, + outputBlobStreams, &blobThreshold)); + ASSERT_NE(0u, outputBlobStreams.size()); + + outputPreviewStreams.clear(); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, + outputPreviewStreams, &previewThreshold)); + ASSERT_NE(0u, outputPreviewStreams.size()); + + int32_t streamId = 0; + for (auto &blobIter : outputBlobStreams) { + for (auto &previewIter : outputPreviewStreams) { + Stream previewStream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (previewIter.width), + static_cast<uint32_t> (previewIter.height), + static_cast<PixelFormat> (previewIter.format), 0, 0, + StreamRotation::ROTATION_0}; + Stream blobStream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (blobIter.width), + static_cast<uint32_t> (blobIter.height), + static_cast<PixelFormat> (blobIter.format), 0, 0, + StreamRotation::ROTATION_0}; + ::android::hardware::hidl_vec<Stream> streams = { + previewStream, blobStream}; + StreamConfiguration config = {streams, + StreamConfigurationMode::NORMAL_MODE}; + ret = session->configureStreams(config, [streamId] (Status s, + HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(2u, halConfig.streams.size()); + }); + ASSERT_TRUE(ret.isOk()); + } + } + + free_camera_metadata(staticMeta); + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// In case constrained mode is supported, test whether it can be +// configured. Additionally check for common invalid inputs when +// using this mode. +TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + camera_metadata_t *staticMeta; + Return<void> ret; + sp<ICameraDeviceSession> session; + openEmptyDeviceSession(name, env, &session /*out*/, + &staticMeta /*out*/); + + Status rc = isConstrainedModeAvailable(staticMeta); + if (Status::METHOD_NOT_SUPPORTED == rc) { + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + continue; + } + ASSERT_EQ(Status::OK, rc); + + AvailableStream hfrStream; + rc = pickConstrainedModeSize(staticMeta, hfrStream); + ASSERT_EQ(Status::OK, rc); + + int32_t streamId = 0; + Stream stream = {streamId, StreamType::OUTPUT, + static_cast<uint32_t> (hfrStream.width), + static_cast<uint32_t> (hfrStream.height), + static_cast<PixelFormat> (hfrStream.format), 0, 0, + StreamRotation::ROTATION_0}; + ::android::hardware::hidl_vec<Stream> streams = {stream}; + StreamConfiguration config = {streams, + StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; + ret = session->configureStreams(config, [streamId] (Status s, + HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + ASSERT_EQ(halConfig.streams[0].id, streamId); + }); + ASSERT_TRUE(ret.isOk()); + + stream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (0), + static_cast<uint32_t> (0), + static_cast<PixelFormat> (hfrStream.format), 0, 0, + StreamRotation::ROTATION_0}; + streams[0] = stream; + config = {streams, + StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; + ret = session->configureStreams(config, [streamId] (Status s, + HalStreamConfiguration) { + ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) || + (Status::INTERNAL_ERROR == s)); + }); + ASSERT_TRUE(ret.isOk()); + + stream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (UINT32_MAX), + static_cast<uint32_t> (UINT32_MAX), + static_cast<PixelFormat> (hfrStream.format), 0, 0, + StreamRotation::ROTATION_0}; + streams[0] = stream; + config = {streams, + StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; + ret = session->configureStreams(config, [streamId] (Status s, + HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + ASSERT_TRUE(ret.isOk()); + + stream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (hfrStream.width), + static_cast<uint32_t> (hfrStream.height), + static_cast<PixelFormat> (UINT32_MAX), 0, 0, + StreamRotation::ROTATION_0}; + streams[0] = stream; + config = {streams, + StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE}; + ret = session->configureStreams(config, [streamId] (Status s, + HalStreamConfiguration) { + ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s); + }); + ASSERT_TRUE(ret.isOk()); + + free_camera_metadata(staticMeta); + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Verify that all supported video + snapshot stream combinations can +// be configured successfully. +TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<AvailableStream> outputBlobStreams; + std::vector<AvailableStream> outputVideoStreams; + AvailableStream videoThreshold = {kMaxVideoWidth, kMaxVideoHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + AvailableStream blobThreshold = {kMaxVideoWidth, kMaxVideoHeight, + static_cast<int32_t>(PixelFormat::BLOB)}; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + camera_metadata_t *staticMeta; + Return<void> ret; + sp<ICameraDeviceSession> session; + openEmptyDeviceSession(name, env, &session /*out*/, + &staticMeta /*out*/); + + outputBlobStreams.clear(); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, + outputBlobStreams, &blobThreshold)); + ASSERT_NE(0u, outputBlobStreams.size()); + + outputVideoStreams.clear(); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, + outputVideoStreams, &videoThreshold)); + ASSERT_NE(0u, outputVideoStreams.size()); + + int32_t streamId = 0; + for (auto &blobIter : outputBlobStreams) { + for (auto &videoIter : outputVideoStreams) { + Stream videoStream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (videoIter.width), + static_cast<uint32_t> (videoIter.height), + static_cast<PixelFormat> (videoIter.format), 0, 0, + StreamRotation::ROTATION_0}; + Stream blobStream = {streamId++, StreamType::OUTPUT, + static_cast<uint32_t> (blobIter.width), + static_cast<uint32_t> (blobIter.height), + static_cast<PixelFormat> (blobIter.format), + GRALLOC_USAGE_HW_VIDEO_ENCODER, 0, + StreamRotation::ROTATION_0}; + ::android::hardware::hidl_vec<Stream> streams = { + videoStream, blobStream}; + StreamConfiguration config = {streams, + StreamConfigurationMode::NORMAL_MODE}; + ret = session->configureStreams(config, [streamId] (Status s, + HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(2u, halConfig.streams.size()); + }); + ASSERT_TRUE(ret.isOk()); + } + } + + free_camera_metadata(staticMeta); + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Generate and verify a camera capture request +TEST_F(CameraHidlTest, processCaptureRequestPreview) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + uint64_t bufferId = 1; + uint32_t frameNumber = 1; + ::android::hardware::hidl_vec<uint8_t> settings; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + Stream previewStream; + HalStreamConfiguration halStreamConfig; + sp<ICameraDeviceSession> session; + configurePreviewStream(name, env, &previewThreshold, + &session /*out*/, &previewStream /*out*/, + &halStreamConfig /*out*/); + + RequestTemplate reqTemplate = RequestTemplate::PREVIEW; + Return<void> ret; + ret = session->constructDefaultRequestSettings(reqTemplate, + [&](auto status, const auto& req) { + ASSERT_EQ(Status::OK, status); + settings = req; }); + ASSERT_TRUE(ret.isOk()); + + sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width, + previewStream.height, + static_cast<int32_t> (halStreamConfig.streams[0].overrideFormat), + 1, halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage); + ASSERT_NE(nullptr, gb.get()); + StreamBuffer outputBuffer = {halStreamConfig.streams[0].id, + bufferId, hidl_handle(gb->getNativeBuffer()->handle), + BufferStatus::OK, nullptr, nullptr}; + ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = { + outputBuffer}; + StreamBuffer emptyInputBuffer = {-1, 0, nullptr, + BufferStatus::ERROR, nullptr, nullptr}; + CaptureRequest request = {frameNumber, settings, + emptyInputBuffer, outputBuffers}; + + { + std::unique_lock<std::mutex> l(mLock); + mResultBuffers.clear(); + mResultFrameNumber = frameNumber; + } + + Return<Status> returnStatus = session->processCaptureRequest( + request); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + { + std::unique_lock<std::mutex> l(mLock); + while (0 == mResultBuffers.size()) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kStreamBufferTimeoutSec); + ASSERT_NE(std::cv_status::timeout, + mResultCondition.wait_until(l, timeout)); + } + + ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status); + ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId); + + request.frameNumber++; + //Empty settings should be supported after the first call + //for repeating requests. + request.settings.setToExternal(nullptr, 0, true); + mResultBuffers.clear(); + mResultFrameNumber++; + } + + returnStatus = session->processCaptureRequest( + request); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + { + std::unique_lock<std::mutex> l(mLock); + while (0 == mResultBuffers.size()) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kStreamBufferTimeoutSec); + ASSERT_NE(std::cv_status::timeout, + mResultCondition.wait_until(l, timeout)); + } + ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status); + ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId); + } + + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Test whether an incorrect capture request with missing settings will +// be reported correctly. +TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<AvailableStream> outputPreviewStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + uint64_t bufferId = 1; + uint32_t frameNumber = 1; + ::android::hardware::hidl_vec<uint8_t> settings; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + Stream previewStream; + HalStreamConfiguration halStreamConfig; + sp<ICameraDeviceSession> session; + configurePreviewStream(name, env, &previewThreshold, + &session /*out*/, &previewStream /*out*/, + &halStreamConfig /*out*/); + + sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width, + previewStream.height, + static_cast<int32_t> (halStreamConfig.streams[0].overrideFormat), + 1, halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage); + + StreamBuffer outputBuffer = {halStreamConfig.streams[0].id, + bufferId, hidl_handle(gb->getNativeBuffer()->handle), + BufferStatus::OK, nullptr, nullptr}; + ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = { + outputBuffer}; + StreamBuffer emptyInputBuffer = {-1, 0, nullptr, + BufferStatus::ERROR, nullptr, nullptr}; + CaptureRequest request = {frameNumber, settings, + emptyInputBuffer, outputBuffers}; + + //Settings were not correctly initialized, we should fail here + Return<Status> returnStatus = session->processCaptureRequest( + request); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::INTERNAL_ERROR, returnStatus); + + Return<void> ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Check whether an invalid capture request with missing output buffers +// will be reported correctly. +TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<AvailableStream> outputBlobStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + uint32_t frameNumber = 1; + ::android::hardware::hidl_vec<uint8_t> settings; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + Stream previewStream; + HalStreamConfiguration halStreamConfig; + sp<ICameraDeviceSession> session; + configurePreviewStream(name, env, &previewThreshold, + &session /*out*/, &previewStream /*out*/, + &halStreamConfig /*out*/); + + RequestTemplate reqTemplate = RequestTemplate::PREVIEW; + Return<void> ret; + ret = session->constructDefaultRequestSettings(reqTemplate, + [&](auto status, const auto& req) { + ASSERT_EQ(Status::OK, status); + settings = req; }); + ASSERT_TRUE(ret.isOk()); + + ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers; + StreamBuffer emptyInputBuffer = {-1, 0, nullptr, + BufferStatus::ERROR, nullptr, nullptr}; + CaptureRequest request = {frameNumber, settings, + emptyInputBuffer, emptyOutputBuffers}; + + //Output buffers are missing, we should fail here + Return<Status> returnStatus = session->processCaptureRequest( + request); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::INTERNAL_ERROR, + returnStatus); + + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Generate, trigger and flush a preview request +TEST_F(CameraHidlTest, flushPreviewRequest) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<AvailableStream> outputPreviewStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + uint64_t bufferId = 1; + uint32_t frameNumber = 1; + ::android::hardware::hidl_vec<uint8_t> settings; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + Stream previewStream; + HalStreamConfiguration halStreamConfig; + sp<ICameraDeviceSession> session; + configurePreviewStream(name, env, &previewThreshold, + &session /*out*/, &previewStream /*out*/, + &halStreamConfig /*out*/); + + RequestTemplate reqTemplate = RequestTemplate::PREVIEW; + Return<void> ret; + ret = session->constructDefaultRequestSettings(reqTemplate, + [&](auto status, const auto& req) { + ASSERT_EQ(Status::OK, status); + settings = req; }); + ASSERT_TRUE(ret.isOk()); + + sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width, + previewStream.height, + static_cast<int32_t> (halStreamConfig.streams[0].overrideFormat), + 1, halStreamConfig.streams[0].producerUsage, + halStreamConfig.streams[0].consumerUsage); + ASSERT_NE(nullptr, gb.get()); + StreamBuffer outputBuffer = {halStreamConfig.streams[0].id, + bufferId, hidl_handle(gb->getNativeBuffer()->handle), + BufferStatus::OK, nullptr, nullptr}; + ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = { + outputBuffer}; + const StreamBuffer emptyInputBuffer = {-1, 0, nullptr, + BufferStatus::ERROR, nullptr, nullptr}; + CaptureRequest request = {frameNumber, settings, + emptyInputBuffer, outputBuffers}; + + { + std::unique_lock<std::mutex> l(mLock); + mResultBuffers.clear(); + mErrors.clear(); + mResultFrameNumber = frameNumber; + } + + Return<Status> returnStatus = session->processCaptureRequest( + request); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + //Flush before waiting for request to complete. + returnStatus = session->flush(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + { + std::unique_lock<std::mutex> l(mLock); + while ((0 == mResultBuffers.size()) && (0 == mErrors.size())) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kStreamBufferTimeoutSec); + ASSERT_NE(std::cv_status::timeout, + mResultCondition.wait_until(l, timeout)); + } + + if (mErrors.empty()) { + ASSERT_EQ(BufferStatus::OK, mResultBuffers[0].status); + ASSERT_EQ(previewStream.id, mResultBuffers[0].streamId); + } else { + for (auto &error : mErrors) { + switch (error.errorCode) { + case ErrorCode::ERROR_REQUEST: + case ErrorCode::ERROR_RESULT: + //Expected + break; + case ErrorCode::ERROR_BUFFER: + //Expected as well + ASSERT_EQ(frameNumber, error.frameNumber); + ASSERT_EQ(previewStream.id, error.errorStreamId); + break; + case ErrorCode::ERROR_DEVICE: + default: + FAIL() <<"Unexpected error:" << static_cast<uint32_t> (error.errorCode); + } + } + } + } + + ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Verify that camera flushes correctly without any pending requests. +TEST_F(CameraHidlTest, flushEmpty) { + CameraHidlEnvironment* env = CameraHidlEnvironment::Instance(); + hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(); + std::vector<AvailableStream> outputPreviewStreams; + AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight, + static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + + for (const auto& name : cameraDeviceNames) { + if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) { + Stream previewStream; + HalStreamConfiguration halStreamConfig; + sp<ICameraDeviceSession> session; + configurePreviewStream(name, env, &previewThreshold, + &session /*out*/, &previewStream /*out*/, + &halStreamConfig /*out*/); + + { + std::unique_lock<std::mutex> l(mLock); + mResultBuffers.clear(); + mErrors.clear(); + mResultFrameNumber = 0; + } + + Return<Status> returnStatus = session->flush(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); + + { + std::unique_lock<std::mutex> l(mLock); + auto timeout = std::chrono::system_clock::now() + + std::chrono::milliseconds(kEmptyFlushTimeoutMSec); + ASSERT_EQ(std::cv_status::timeout, + mResultCondition.wait_until(l, timeout)); + ASSERT_TRUE(mErrors.empty()); + ASSERT_TRUE(mResultBuffers.empty()); + } + + Return<void> ret = session->close(); + ASSERT_TRUE(ret.isOk()); + } + } +} + +// Retrieve all valid output stream resolutions from the camera +// static characteristics. +Status CameraHidlTest::getAvailableOutputStreams(camera_metadata_t *staticMeta, + std::vector<AvailableStream> &outputStreams, + const AvailableStream *threshold) { + if (nullptr == staticMeta) { + return Status::ILLEGAL_ARGUMENT; + } + + camera_metadata_ro_entry entry; + int rc = find_camera_metadata_ro_entry(staticMeta, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry); + if ((0 != rc) || (0 != (entry.count % 4))) { + return Status::ILLEGAL_ARGUMENT; + } + + for (size_t i = 0; i < entry.count; i+=4) { + if (ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT == + entry.data.i32[i + 3]) { + if(nullptr == threshold) { + AvailableStream s = {entry.data.i32[i+1], + entry.data.i32[i+2], entry.data.i32[i]}; + outputStreams.push_back(s); + } else { + if ((threshold->format == entry.data.i32[i]) && + (threshold->width >= entry.data.i32[i+1]) && + (threshold->height >= entry.data.i32[i+2])) { + AvailableStream s = {entry.data.i32[i+1], + entry.data.i32[i+2], threshold->format}; + outputStreams.push_back(s); + } + } + } + + } + + return Status::OK; +} + +// Check if constrained mode is supported by using the static +// camera characteristics. +Status CameraHidlTest::isConstrainedModeAvailable(camera_metadata_t *staticMeta) { + Status ret = Status::METHOD_NOT_SUPPORTED; + if (nullptr == staticMeta) { + return Status::ILLEGAL_ARGUMENT; + } + + camera_metadata_ro_entry entry; + int rc = find_camera_metadata_ro_entry(staticMeta, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry); + if (0 != rc) { + return Status::ILLEGAL_ARGUMENT; + } + + for (size_t i = 0; i < entry.count; i++) { + if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO == + entry.data.u8[i]) { + ret = Status::OK; + break; + } + } + + return ret; +} + +// Pick the largest supported HFR mode from the static camera +// characteristics. +Status CameraHidlTest::pickConstrainedModeSize(camera_metadata_t *staticMeta, + AvailableStream &hfrStream) { + if (nullptr == staticMeta) { + return Status::ILLEGAL_ARGUMENT; + } + + camera_metadata_ro_entry entry; + int rc = find_camera_metadata_ro_entry(staticMeta, + ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, &entry); + if (0 != rc) { + return Status::METHOD_NOT_SUPPORTED; + } else if (0 != (entry.count % 5)) { + return Status::ILLEGAL_ARGUMENT; + } + + hfrStream = {0, 0, + static_cast<uint32_t>(PixelFormat::IMPLEMENTATION_DEFINED)}; + for (size_t i = 0; i < entry.count; i+=5) { + int32_t w = entry.data.i32[i]; + int32_t h = entry.data.i32[i+1]; + if ((hfrStream.width * hfrStream.height) < (w *h)) { + hfrStream.width = w; + hfrStream.height = h; + } + } + + return Status::OK; +} + +// Check whether ZSL is available using the static camera +// characteristics. +Status CameraHidlTest::isZSLModeAvailable(camera_metadata_t *staticMeta) { + Status ret = Status::METHOD_NOT_SUPPORTED; + if (nullptr == staticMeta) { + return Status::ILLEGAL_ARGUMENT; + } + + camera_metadata_ro_entry entry; + int rc = find_camera_metadata_ro_entry(staticMeta, + ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry); + if (0 != rc) { + return Status::ILLEGAL_ARGUMENT; + } + + for (size_t i = 0; i < entry.count; i++) { + if ((ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING == + entry.data.u8[i]) || + (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING == + entry.data.u8[i]) ){ + ret = Status::OK; + break; + } + } + + return ret; +} + +// Retrieve the reprocess input-output format map from the static +// camera characteristics. +Status CameraHidlTest::getZSLInputOutputMap(camera_metadata_t *staticMeta, + std::vector<AvailableZSLInputOutput> &inputOutputMap) { + if (nullptr == staticMeta) { + return Status::ILLEGAL_ARGUMENT; + } + + camera_metadata_ro_entry entry; + int rc = find_camera_metadata_ro_entry(staticMeta, + ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP, &entry); + if ((0 != rc) || (0 >= entry.count)) { + return Status::ILLEGAL_ARGUMENT; + } + + const int32_t* contents = &entry.data.i32[0]; + for (size_t i = 0; i < entry.count; ) { + int32_t inputFormat = contents[i++]; + int32_t length = contents[i++]; + for (int32_t j = 0; j < length; j++) { + int32_t outputFormat = contents[i+j]; + AvailableZSLInputOutput zslEntry = {inputFormat, outputFormat}; + inputOutputMap.push_back(zslEntry); + } + i += length; + } + + return Status::OK; +} + +// Search for the largest stream size for a given format. +Status CameraHidlTest::findLargestSize( + const std::vector<AvailableStream> &streamSizes, int32_t format, + AvailableStream &result) { + result = {0, 0, 0}; + for (auto &iter : streamSizes) { + if (format == iter.format) { + if ((result.width * result.height) < (iter.width * iter.height)) { + result = iter; + } + } + } + + return (result.format == format) ? Status::OK : Status::ILLEGAL_ARGUMENT; +} + +// Check whether the camera device supports specific focus mode. +Status CameraHidlTest::isAutoFocusModeAvailable( + ::android::CameraParameters &cameraParams, + const char *mode) { + ::android::String8 focusModes(cameraParams.get( + CameraParameters::KEY_SUPPORTED_FOCUS_MODES)); + if (focusModes.contains(mode)) { + return Status::OK; + } + + return Status::METHOD_NOT_SUPPORTED; +} + +// Open a device session and configure a preview stream. +void CameraHidlTest::configurePreviewStream(const std::string &name, + const CameraHidlEnvironment* env, + const AvailableStream *previewThreshold, + sp<ICameraDeviceSession> *session /*out*/, + Stream *previewStream /*out*/, + HalStreamConfiguration *halStreamConfig /*out*/) { + ASSERT_NE(nullptr, env); + ASSERT_NE(nullptr, session); + ASSERT_NE(nullptr, previewStream); + ASSERT_NE(nullptr, halStreamConfig); + + std::vector<AvailableStream> outputPreviewStreams; + ::android::sp<ICameraDevice> device3_2; + ALOGI("configureStreams: Testing camera device %s", name.c_str()); + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", + (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device3_2 = device; + }); + ASSERT_TRUE(ret.isOk()); + + sp<DeviceCb> cb = new DeviceCb(this); + ret = device3_2->open( + cb, + [&](auto status, const auto& newSession) { + ALOGI("device::open returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(newSession, nullptr); + *session = newSession; + }); + ASSERT_TRUE(ret.isOk()); + + camera_metadata_t *staticMeta; + ret = device3_2->getCameraCharacteristics([&] (Status s, + CameraMetadata metadata) { + ASSERT_EQ(Status::OK, s); + staticMeta = clone_camera_metadata( + reinterpret_cast<const camera_metadata_t*>(metadata.data())); + ASSERT_NE(nullptr, staticMeta); + }); + ASSERT_TRUE(ret.isOk()); + + outputPreviewStreams.clear(); + auto rc = getAvailableOutputStreams(staticMeta, + outputPreviewStreams, previewThreshold); + free_camera_metadata(staticMeta); + ASSERT_EQ(Status::OK, rc); + ASSERT_FALSE(outputPreviewStreams.empty()); + + *previewStream = {0, StreamType::OUTPUT, + static_cast<uint32_t> (outputPreviewStreams[0].width), + static_cast<uint32_t> (outputPreviewStreams[0].height), + static_cast<PixelFormat> (outputPreviewStreams[0].format), + 0, 0, StreamRotation::ROTATION_0}; + ::android::hardware::hidl_vec<Stream> streams = {*previewStream}; + StreamConfiguration config = {streams, + StreamConfigurationMode::NORMAL_MODE}; + ret = (*session)->configureStreams(config, [&] (Status s, + HalStreamConfiguration halConfig) { + ASSERT_EQ(Status::OK, s); + ASSERT_EQ(1u, halConfig.streams.size()); + *halStreamConfig = halConfig; + }); + ASSERT_TRUE(ret.isOk()); +} + +// Open a device session with empty callbacks and return static metadata. +void CameraHidlTest::openEmptyDeviceSession(const std::string &name, + const CameraHidlEnvironment* env, + sp<ICameraDeviceSession> *session /*out*/, + camera_metadata_t **staticMeta /*out*/) { + ASSERT_NE(nullptr, env); + ASSERT_NE(nullptr, session); + ASSERT_NE(nullptr, staticMeta); + + ::android::sp<ICameraDevice> device3_2; + ALOGI("configureStreams: Testing camera device %s", name.c_str()); + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V3_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V3_x returns status:%d", + (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + device3_2 = device; + }); + ASSERT_TRUE(ret.isOk()); + + sp<EmptyDeviceCb> cb = new EmptyDeviceCb(); + ret = device3_2->open(cb, [&](auto status, const auto& newSession) { + ALOGI("device::open returns status:%d", (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(newSession, nullptr); + *session = newSession; + }); + ASSERT_TRUE(ret.isOk()); + + ret = device3_2->getCameraCharacteristics([&] (Status s, + CameraMetadata metadata) { + ASSERT_EQ(Status::OK, s); + *staticMeta = clone_camera_metadata( + reinterpret_cast<const camera_metadata_t*>(metadata.data())); + ASSERT_NE(nullptr, *staticMeta); + }); + ASSERT_TRUE(ret.isOk()); +} + +// Open a particular camera device. +void CameraHidlTest::openCameraDevice(const std::string &name, + const CameraHidlEnvironment* env, + sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device1 /*out*/) { + ASSERT_TRUE(nullptr != env); + ASSERT_TRUE(nullptr != device1); + + Return<void> ret; + ret = env->mProvider->getCameraDeviceInterface_V1_x( + name, + [&](auto status, const auto& device) { + ALOGI("getCameraDeviceInterface_V1_x returns status:%d", + (int)status); + ASSERT_EQ(Status::OK, status); + ASSERT_NE(device, nullptr); + *device1 = device; + }); + ASSERT_TRUE(ret.isOk()); + + sp<Camera1DeviceCb> deviceCb = new Camera1DeviceCb(this); + Return<Status> returnStatus = (*device1)->open(deviceCb); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); +} + +// Initialize and configure a preview window. +void CameraHidlTest::setupPreviewWindow( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, + sp<BufferItemConsumer> *bufferItemConsumer /*out*/, + sp<BufferItemHander> *bufferHandler /*out*/) { + ASSERT_NE(nullptr, device.get()); + ASSERT_NE(nullptr, bufferItemConsumer); + ASSERT_NE(nullptr, bufferHandler); + + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + *bufferItemConsumer = new BufferItemConsumer(consumer, + GraphicBuffer::USAGE_HW_TEXTURE); //Use GLConsumer default usage flags + ASSERT_NE(nullptr, (*bufferItemConsumer).get()); + *bufferHandler = new BufferItemHander(*bufferItemConsumer); + ASSERT_NE(nullptr, (*bufferHandler).get()); + (*bufferItemConsumer)->setFrameAvailableListener(*bufferHandler); + sp<Surface> surface = new Surface(producer); + sp<PreviewWindowCb> previewCb = new PreviewWindowCb(surface); + + auto rc = device->setPreviewWindow(previewCb); + ASSERT_TRUE(rc.isOk()); + ASSERT_EQ(Status::OK, rc); +} + +// Stop camera preview and close camera. +void CameraHidlTest::stopPreviewAndClose( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) { + Return<void> ret = device->stopPreview(); + ASSERT_TRUE(ret.isOk()); + + ret = device->close(); + ASSERT_TRUE(ret.isOk()); +} + +// Enable a specific camera message type. +void CameraHidlTest::enableMsgType(unsigned int msgType, + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) { + Return<void> ret = device->enableMsgType(msgType); + ASSERT_TRUE(ret.isOk()); + + Return<bool> returnBoolStatus = device->msgTypeEnabled(msgType); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_TRUE(returnBoolStatus); +} + +// Disable a specific camera message type. +void CameraHidlTest::disableMsgType(unsigned int msgType, + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) { + Return<void> ret = device->disableMsgType(msgType); + ASSERT_TRUE(ret.isOk()); + + Return<bool> returnBoolStatus = device->msgTypeEnabled(msgType); + ASSERT_TRUE(returnBoolStatus.isOk()); + ASSERT_FALSE(returnBoolStatus); +} + +// Wait until a specific frame notification arrives. +void CameraHidlTest::waitForFrameLocked(DataCallbackMsg msgFrame, + std::unique_lock<std::mutex> &l) { + while (msgFrame != mDataMessageTypeReceived) { + auto timeout = std::chrono::system_clock::now() + + std::chrono::seconds(kStreamBufferTimeoutSec); + ASSERT_NE(std::cv_status::timeout, + mResultCondition.wait_until(l, timeout)); + } +} + +// Start preview on a particular camera device +void CameraHidlTest::startPreview( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device) { + Return<Status> returnStatus = device->startPreview(); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); +} + +// Retrieve camera parameters. +void CameraHidlTest::getParameters( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, + CameraParameters *cameraParams /*out*/) { + ASSERT_NE(nullptr, cameraParams); + + Return<void> ret; + ret = device->getParameters([&] (const ::android::hardware::hidl_string& params) { + ASSERT_FALSE(params.empty()); + ::android::String8 paramString(params.c_str()); + (*cameraParams).unflatten(paramString); + }); + ASSERT_TRUE(ret.isOk()); +} + +// Set camera parameters. +void CameraHidlTest::setParameters( + const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device, + const CameraParameters &cameraParams) { + Return<Status> returnStatus = device->setParameters( + cameraParams.flatten().string()); + ASSERT_TRUE(returnStatus.isOk()); + ASSERT_EQ(Status::OK, returnStatus); +} + +int main(int argc, char **argv) { + ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +}
diff --git a/camera/provider/README.md b/camera/provider/README.md new file mode 100644 index 0000000..0718fb1 --- /dev/null +++ b/camera/provider/README.md
@@ -0,0 +1,37 @@ +## Camera Provider HAL ## +--- + +## Overview: ## + +The camera.provider HAL is used by the Android camera service to discover, +query, and open individual camera devices. + +It also allows for direct control of the flash unit of camera devices that have +one, for turning on/off torch mode. + +More complete information about the Android camera HAL and subsystem can be found at +[source.android.com](http://source.android.com/devices/camera/index.html). + +## Version history: ## + +## types.hal: ## + +### @0.0: + +Common enum and struct definitions for all camera HAL interfaces. Does not +define any interfaces of its own. + +## ICameraProvider.hal: ## + +### @2.4: + +First HIDL version of the camera provider HAL, closely matching the feature set +and operation of the pre-HIDL camera HAL module v2.4. + +## ICameraProviderCallback.hal: ## + +### @2.4: + +First HIDL version of the camara provider HAL callback interface, closely +matching the feature set and operation of the pre-HIDL camera HAL module +callbacks v2.4.
diff --git a/configstore/1.0/ISurfaceFlingerConfigs.hal b/configstore/1.0/ISurfaceFlingerConfigs.hal index 4403a90..f9a49ce 100644 --- a/configstore/1.0/ISurfaceFlingerConfigs.hal +++ b/configstore/1.0/ISurfaceFlingerConfigs.hal
@@ -16,6 +16,58 @@ package android.hardware.configstore@1.0; interface ISurfaceFlingerConfigs { + /* + * The following two methods define (respectively): + * + * - The phase offset between hardware vsync and when apps are woken up by the + * Choreographer callback + * - The phase offset between hardware vsync and when SurfaceFlinger wakes up + * to consume input + * + * Their values may be tuned to trade off between display pipeline latency (both + * overall latency and the lengths of the app --> SF and SF --> display phases) + * and frame delivery jitter (which typically manifests as "jank" or "jerkiness" + * while interacting with the device). The default values must produce a + * relatively low amount of jitter at the expense of roughly two frames of + * app --> display latency, and unless significant testing is performed to avoid + * increased display jitter (both manual investigation using systrace [1] and + * automated testing using dumpsys gfxinfo [2] are recommended), they should not + * be modified. + * + * [1] https://developer.android.com/studio/profile/systrace.html + * [2] https://developer.android.com/training/testing/performance.html + */ vsyncEventPhaseOffsetNs() generates (OptionalInt64 value); + vsyncSfEventPhaseOffsetNs() generates (OptionalInt64 value); + useTripleFramebuffer() generates (OptionalBool value); + + /* + * Instruct the Render Engine to use EGL_IMG_context_priority hint if + * availabe. + */ + useContextPriority() generates(OptionalBool value); + + /* + * hasWideColorDisplay indicates that the device has + * or can support a wide-color display, e.g. color space + * greater than sRGB. Typical display may have same + * color primaries as DCI-P3. + * Indicate support for this feature by setting + * TARGET_HAS_WIDE_COLOR_DISPLAY to true in BoardConfig.mk + * This also means that the device is color managed. + * A color managed device will use the appropriate + * display mode depending on the content on the screen. + * Default is sRGB. + */ + hasWideColorDisplay() generates (OptionalBool value); + + /* + * hwHdrDisplay indicates that the device has + * or can support an HDR (High Dynamic Range) display. + * Typically an HDR display is also wide-color. + * Indicate support for this feature by setting + * TARGET_HAS_HDR_DISPLAY to true in BoardConfig.mk + */ + hasHDRDisplay() generates (OptionalBool value); };
diff --git a/configstore/1.0/default/SurfaceFlingerConfigs.cpp b/configstore/1.0/default/SurfaceFlingerConfigs.cpp index 5d62b15..035479c 100644 --- a/configstore/1.0/default/SurfaceFlingerConfigs.cpp +++ b/configstore/1.0/default/SurfaceFlingerConfigs.cpp
@@ -19,6 +19,16 @@ return Void(); } +Return<void> SurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) { +#ifdef SF_VSYNC_EVENT_PHASE_OFFSET_NS + _hidl_cb({true, SF_VSYNC_EVENT_PHASE_OFFSET_NS}); + LOG(INFO) << "sfvsync event phase offset ns = " << SF_VSYNC_EVENT_PHASE_OFFSET_NS; +#else + _hidl_cb({false, 0}); +#endif + return Void(); +} + Return<void> SurfaceFlingerConfigs::useTripleFramebuffer(useTripleFramebuffer_cb _hidl_cb) { bool value = false; #ifdef USE_TRIPLE_FRAMEBUFFER @@ -29,6 +39,36 @@ return Void(); } +Return<void> SurfaceFlingerConfigs::useContextPriority(useContextPriority_cb _hidl_cb) { +#ifdef USE_CONTEXT_PRIORITY + _hidl_cb({true, USE_CONTEXT_PRIORITY}); + LOG(INFO) << "SurfaceFlinger useContextPriority=" << USE_CONTEXT_PRIORITY; +#else + _hidl_cb({false, false}); +#endif + return Void(); +} + +Return<void> SurfaceFlingerConfigs::hasWideColorDisplay(hasWideColorDisplay_cb _hidl_cb) { + bool value = false; +#ifdef HAS_WIDE_COLOR_DISPLAY + value = true; +#endif + _hidl_cb({true, value}); + LOG(INFO) << "SurfaceFlinger Display: " << (value ? "Wide Color" : "Standard Color"); + return Void(); +} + +Return<void> SurfaceFlingerConfigs::hasHDRDisplay(hasHDRDisplay_cb _hidl_cb) { + bool value = false; +#ifdef HAS_HDR_DISPLAY + value = true; +#endif + _hidl_cb({true, value}); + LOG(INFO) << "SurfaceFlinger Display: " << (value ? "HDR" : "SDR"); + return Void(); +} + // Methods from ::android::hidl::base::V1_0::IBase follow. ISurfaceFlingerConfigs* HIDL_FETCH_ISurfaceFlingerConfigs(const char* /* name */) {
diff --git a/configstore/1.0/default/SurfaceFlingerConfigs.h b/configstore/1.0/default/SurfaceFlingerConfigs.h index c9652fc..aa7fb8b 100644 --- a/configstore/1.0/default/SurfaceFlingerConfigs.h +++ b/configstore/1.0/default/SurfaceFlingerConfigs.h
@@ -25,7 +25,11 @@ struct SurfaceFlingerConfigs : public ISurfaceFlingerConfigs { // Methods from ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs follow. Return<void> vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override; + Return<void> vsyncSfEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override; Return<void> useTripleFramebuffer(useTripleFramebuffer_cb _hidl_cb) override; + Return<void> useContextPriority(useContextPriority_cb _hidl_cb) override; + Return<void> hasWideColorDisplay(hasWideColorDisplay_cb _hidl_cb) override; + Return<void> hasHDRDisplay(hasHDRDisplay_cb _hidl_cb) override; // Methods from ::android::hidl::base::V1_0::IBase follow.
diff --git a/configstore/1.0/default/surfaceflinger.mk b/configstore/1.0/default/surfaceflinger.mk index 5a946f4..8ee3686 100644 --- a/configstore/1.0/default/surfaceflinger.mk +++ b/configstore/1.0/default/surfaceflinger.mk
@@ -5,6 +5,27 @@ LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS) endif +ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),) + LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS) +endif + ifeq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),3) LOCAL_CFLAGS += -DUSE_TRIPLE_FRAMEBUFFER endif + +ifeq ($(TARGET_BOARD_PLATFORM),omap4) + LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1 +endif + +ifeq ($(TARGET_BOARD_PLATFORM),s5pc110) + LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1 +endif + +ifeq ($(TARGET_HAS_WIDE_COLOR_DISPLAY),true) + LOCAL_CFLAGS += -DHAS_WIDE_COLOR_DISPLAY +endif + +ifeq ($(TARGET_HAS_HDR_DISPLAY),true) + LOCAL_CFLAGS += -DHAS_HDR_DISPLAY +endif +
diff --git a/contexthub/1.0/Android.bp b/contexthub/1.0/Android.bp new file mode 100644 index 0000000..8cd4acb --- /dev/null +++ b/contexthub/1.0/Android.bp
@@ -0,0 +1,69 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.contexthub@1.0_hal", + srcs: [ + "types.hal", + "IContexthub.hal", + "IContexthubCallback.hal", + ], +} + +genrule { + name: "android.hardware.contexthub@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.contexthub@1.0", + srcs: [ + ":android.hardware.contexthub@1.0_hal", + ], + out: [ + "android/hardware/contexthub/1.0/types.cpp", + "android/hardware/contexthub/1.0/ContexthubAll.cpp", + "android/hardware/contexthub/1.0/ContexthubCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.contexthub@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.contexthub@1.0", + srcs: [ + ":android.hardware.contexthub@1.0_hal", + ], + out: [ + "android/hardware/contexthub/1.0/types.h", + "android/hardware/contexthub/1.0/IContexthub.h", + "android/hardware/contexthub/1.0/IHwContexthub.h", + "android/hardware/contexthub/1.0/BnHwContexthub.h", + "android/hardware/contexthub/1.0/BpHwContexthub.h", + "android/hardware/contexthub/1.0/BsContexthub.h", + "android/hardware/contexthub/1.0/IContexthubCallback.h", + "android/hardware/contexthub/1.0/IHwContexthubCallback.h", + "android/hardware/contexthub/1.0/BnHwContexthubCallback.h", + "android/hardware/contexthub/1.0/BpHwContexthubCallback.h", + "android/hardware/contexthub/1.0/BsContexthubCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.contexthub@1.0", + generated_sources: ["android.hardware.contexthub@1.0_genc++"], + generated_headers: ["android.hardware.contexthub@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.contexthub@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/contexthub/1.0/Android.mk b/contexthub/1.0/Android.mk new file mode 100644 index 0000000..a053986 --- /dev/null +++ b/contexthub/1.0/Android.mk
@@ -0,0 +1,658 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.contexthub@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (AsyncEventType) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/AsyncEventType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.AsyncEventType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ContextHub) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/ContextHub.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.ContextHub + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ContextHubMsg) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/ContextHubMsg.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.ContextHubMsg + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HostEndPoint) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/HostEndPoint.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.HostEndPoint + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HubAppInfo) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubAppInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.HubAppInfo + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HubMemoryFlag) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubMemoryFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.HubMemoryFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HubMemoryType) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubMemoryType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.HubMemoryType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MemRange) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/MemRange.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.MemRange + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (NanoAppBinary) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/NanoAppBinary.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.NanoAppBinary + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (NanoAppFlags) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/NanoAppFlags.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.NanoAppFlags + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PhysicalSensor) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/PhysicalSensor.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.PhysicalSensor + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Result) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/Result.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.Result + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SensorType) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/SensorType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.SensorType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TransactionResult) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/TransactionResult.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.TransactionResult + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IContexthub.hal +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/IContexthub.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IContexthub.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IContexthubCallback.hal +$(GEN): $(LOCAL_PATH)/IContexthubCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::IContexthub + +$(GEN): $(LOCAL_PATH)/IContexthub.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IContexthubCallback.hal +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/IContexthubCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IContexthubCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::IContexthubCallback + +$(GEN): $(LOCAL_PATH)/IContexthubCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.contexthub@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (AsyncEventType) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/AsyncEventType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.AsyncEventType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ContextHub) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/ContextHub.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.ContextHub + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ContextHubMsg) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/ContextHubMsg.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.ContextHubMsg + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HostEndPoint) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/HostEndPoint.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.HostEndPoint + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HubAppInfo) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubAppInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.HubAppInfo + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HubMemoryFlag) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubMemoryFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.HubMemoryFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HubMemoryType) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/HubMemoryType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.HubMemoryType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MemRange) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/MemRange.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.MemRange + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (NanoAppBinary) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/NanoAppBinary.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.NanoAppBinary + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (NanoAppFlags) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/NanoAppFlags.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.NanoAppFlags + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PhysicalSensor) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/PhysicalSensor.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.PhysicalSensor + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Result) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/Result.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.Result + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SensorType) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/SensorType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.SensorType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TransactionResult) +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/TransactionResult.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::types.TransactionResult + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IContexthub.hal +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/IContexthub.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IContexthub.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IContexthubCallback.hal +$(GEN): $(LOCAL_PATH)/IContexthubCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::IContexthub + +$(GEN): $(LOCAL_PATH)/IContexthub.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IContexthubCallback.hal +# +GEN := $(intermediates)/android/hardware/contexthub/V1_0/IContexthubCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IContexthubCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.contexthub@1.0::IContexthubCallback + +$(GEN): $(LOCAL_PATH)/IContexthubCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/contexthub/1.0/IContexthub.hal b/contexthub/1.0/IContexthub.hal new file mode 100644 index 0000000..c0928d5 --- /dev/null +++ b/contexthub/1.0/IContexthub.hal
@@ -0,0 +1,172 @@ +/* + * Copyright (C) 2016 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.contexthub@1.0; + +import IContexthubCallback; + +/* + * The Context Hub HAL provides an interface to a separate low-power processing + * domain that has direct access to contextual information, such as sensors. + * Native applications that run within a context hub are known as nanoapps, and + * they execute within the Context Hub Runtime Environment (CHRE), which is + * standardized via the CHRE API, defined elsewhere. + */ +interface IContexthub { + /* + * Enumerate all available context hubs on the system. + * + * @return hubs list of hubs on this system. + */ + getHubs() generates (vec<ContextHub> hubs); + + /* + * Register a callback for the HAL implementation to send asynchronous + * messages to the service from a context hub. There can be a maximum of + * one callback registered with the HAL. A call to this function when a + * callback has already been registered must override the previous + * registration. + * + * @param hubId identifier for the hub + * callback an implementation of the IContextHubCallbacks + * + * @return result OK on success + * BAD_VALUE if parameters are not sane + * + */ + registerCallback(uint32_t hubId, IContexthubCallback cb) generates (Result result); + + /** + * Send a message to a hub + * + * @param hubId identifier for hub to send message to + * msg message to be sent + * + * @return result OK if successful, error code otherwise + * BAD_VALUE if parameters are not sane + * TRANSACTION_FAILED if message send failed + */ + sendMessageToHub(uint32_t hubId, ContextHubMsg msg) + generates (Result result); + + /** + * Loads a nanoApp. After loading, the nanoApp's init method must be called. + * After the init method for nanoApp returns success, this must be indicated + * to the service by an asynchronous call to handleTxnResult. + * + * Loading a nanoapp must not take more than 30 seconds. + * + * Depending on the implementation, nanoApps loaded via this API may or may + * not persist across reboots of the hub. If they do persist, the + * implementation must initially place nanoApps in the disabled state upon a + * reboot, and not start them until a call is made to enableNanoApp(). In + * this case, the app must also be unloaded upon a factory reset of the + * device. + * + * @param hubId identifer of the contextHub + * appBinary contains the binary representation of the nanoApp, plus + * metadata + * transactionId transactionId for this call + * + * @return result OK if transation started + * BAD_VALUE if parameters are not sane + * TRANSACTION_PENDING if hub is busy with another + * load/unload transaction + * TRANSACTION_FAILED if load failed synchronously + * + */ + loadNanoApp(uint32_t hubId, + NanoAppBinary appBinary, + uint32_t transactionId) + generates (Result result); + + /** + * Unloads a nanoApp. Before the unload, the apps deinit method is called. + * After this, success must be indicated to the service through an + * asynchronous call to handleTxnResult. + * + * Unloading a nanoapp must not take more than 5 seconds. + * + * @param hubId identifer of the contextHub + * appId appIdentifier returned by the HAL + * msg message to be sent + * + * @return result OK if transation started + * BAD_VALUE if parameters are not sane + * TRANSACTION_PENDING if hub is busy with another + * load/unload transaction + * TRANSACTION_FAILED if unload failed synchronously + * + */ + unloadNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) + generates (Result result); + + /** + * Enables a nanoApp. The app's init method is called. + * After this, success must be indicated to the service through an + * asynchronous message. + * + * Enabling a nanoapp must not take more than 5 seconds. + * + * @param hubId identifer of the contextHub + * appId appIdentifier returned by the HAL + * msg message to be sent + * + * @return result OK if transation started + * BAD_VALUE if parameters are not sane + * TRANSACTION_PENDING if hub is busy with another + * load/unload transaction + * FAILED_TRANSACTION if load fails immediately + * + */ + enableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) + generates (Result result); + + /** + * Disables a nanoApp. The app's deinit method is called. + * After this, success must be indicated to the service through an + * asynchronous message. + * + * Disabling a nanoapp must not take more than 5 seconds. + * + * @param hubId identifer of the contextHub + * appId appIdentifier returned by the HAL + * msg message to be sent + * + * @return result OK if transation started + * BAD_VALUE if parameters are not sane + * TRANSACTION_PENDING if hub is busy with another + * load/unload transaction + * FAILED_TRANSACTION if load fails immediately + * + */ + disableNanoApp(uint32_t hubId, uint64_t appId, uint32_t transactionId) + generates (Result result); + + /** + * Queries for Loaded apps on the hub + * + * @param hubId identifer of the contextHub + * + * @return apps all nanoApps on the hub. + * All nanoApps that can be modified by the service must + * be returned. A non-modifiable nanoapps must not be + * returned. A modifiable nanoApp is one that can be + * unloaded/disabled/enabled by the service. + * + */ + queryApps(uint32_t hubId) generates (Result result); +};
diff --git a/contexthub/1.0/IContexthubCallback.hal b/contexthub/1.0/IContexthubCallback.hal new file mode 100644 index 0000000..9a6db4c --- /dev/null +++ b/contexthub/1.0/IContexthubCallback.hal
@@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 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.contexthub@1.0; + +interface IContexthubCallback { + /* + * This callback is passed by the Contexthub service to the HAL + * implementation to allow the HAL to send asynchronous messages back + * to the service and registered clients of the ContextHub service. + * + * @params msg : message + * + */ + handleClientMsg(ContextHubMsg msg); + + /* + * This callback is passed by the Contexthub service to the HAL + * implementation to allow the HAL to send the response for a + * transaction. + * + * @params txnId : transaction id whose result is being sent + * passed in by the service at start of transacation. + * result: result of transaction. + * + */ + handleTxnResult(uint32_t txnId, TransactionResult result); + + /* + * This callback is passed by the Contexthub service to the HAL + * implementation to allow the HAL to send an asynchronous event + * to the ContextHub service. + * + * @params msg : message + * + */ + handleHubEvent(AsyncEventType evt); + + /* + * This callback is passed by the Contexthub service to the HAL + * implementation to allow the HAL to send a notification to the service + * that a nanp-app has aborted. + * This method must be called when a nanoapp invokes chreAbort(...)). + * + * @params appId : app identifier + * : abortCode code passed by the nanoApp. + * + * Also see chreAbort(...) + * + */ + handleAppAbort(uint64_t appId, uint32_t abortCode); + + /* + * This callback is passed by the Contexthub service to the HAL + * implementation to allow the HAL to send information about the + * currently loaded and active nanoapps on the hub. + * + * @params appInfo : vector of HubAppinfo structure for each nanoApp + * on the hub that can be enabled, disabled and + * unloaded by the service. Any nanoApps that cannot + * be controlled by the service must not be reported. + * All nanoApps that can be controlled by the service + * must be reported. + */ + handleAppsInfo(vec<HubAppInfo> appInfo); +};
diff --git a/contexthub/1.0/default/Android.bp b/contexthub/1.0/default/Android.bp new file mode 100644 index 0000000..78d27cc --- /dev/null +++ b/contexthub/1.0/default/Android.bp
@@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016 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. + */ + +cc_library_shared { + name: "android.hardware.contexthub@1.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["Contexthub.cpp"], + shared_libs: [ + "liblog", + "libcutils", + "libhardware", + "libbase", + "libcutils", + "libutils", + "libhidlbase", + "libhidltransport", + "android.hardware.contexthub@1.0", + ], +}
diff --git a/contexthub/1.0/default/Android.mk b/contexthub/1.0/default/Android.mk new file mode 100644 index 0000000..538a6b2 --- /dev/null +++ b/contexthub/1.0/default/Android.mk
@@ -0,0 +1,23 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.contexthub@1.0-service +LOCAL_INIT_RC := android.hardware.contexthub@1.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcutils \ + libdl \ + libhardware \ + libhardware_legacy \ + libhidlbase \ + libhidltransport \ + liblog \ + libutils \ + android.hardware.contexthub@1.0 \ + +include $(BUILD_EXECUTABLE)
diff --git a/contexthub/1.0/default/Contexthub.cpp b/contexthub/1.0/default/Contexthub.cpp new file mode 100644 index 0000000..4a6b3f2 --- /dev/null +++ b/contexthub/1.0/default/Contexthub.cpp
@@ -0,0 +1,553 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "Contexthub.h" + +#include <inttypes.h> + +#include <log/log.h> + +#include <android/hardware/contexthub/1.0/IContexthub.h> +#include <hardware/context_hub.h> +#include <sys/endian.h> + +#undef LOG_TAG +#define LOG_TAG "ContextHubHalAdapter" + +namespace android { +namespace hardware { +namespace contexthub { +namespace V1_0 { +namespace implementation { + +static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF); + +Contexthub::Contexthub() + : mInitCheck(NO_INIT), + mContextHubModule(nullptr), + mIsTransactionPending(false) { + const hw_module_t *module; + + mInitCheck = hw_get_module(CONTEXT_HUB_MODULE_ID, &module); + + if (mInitCheck != OK) { + ALOGE("Could not load %s module: %s", CONTEXT_HUB_MODULE_ID, strerror(-mInitCheck)); + } else if (module == nullptr) { + ALOGE("hal returned succes but a null module!"); + // Assign an error, this should not really happen... + mInitCheck = UNKNOWN_ERROR; + } else { + ALOGI("Loaded Context Hub module"); + mContextHubModule = reinterpret_cast<const context_hub_module_t *>(module); + } +} + +bool Contexthub::setOsAppAsDestination(hub_message_t *msg, int hubId) { + if (!isValidHubId(hubId)) { + ALOGW("%s: Hub information is null for hubHandle %d", + __FUNCTION__, + hubId); + return false; + } else { + msg->app_name = mCachedHubInfo[hubId].osAppName; + return true; + } +} + +Return<void> Contexthub::getHubs(getHubs_cb _hidl_cb) { + std::vector<ContextHub> hubs; + if (isInitialized()) { + const context_hub_t *hubArray = nullptr; + size_t numHubs; + + // Explicitly discarding const. HAL method discards it. + numHubs = mContextHubModule->get_hubs(const_cast<context_hub_module_t *>(mContextHubModule), + &hubArray); + ALOGI("Context Hub Hal Adapter reports %zu hubs", numHubs); + + mCachedHubInfo.clear(); + + for (size_t i = 0; i < numHubs; i++) { + CachedHubInformation info; + ContextHub c; + + c.hubId = hubArray[i].hub_id; + c.name = hubArray[i].name; + c.vendor = hubArray[i].vendor; + c.toolchain = hubArray[i].toolchain; + c.toolchainVersion = hubArray[i].toolchain_version; + c.platformVersion = hubArray[i].platform_version; + c.maxSupportedMsgLen = hubArray[i].max_supported_msg_len; + c.peakMips = hubArray[i].peak_mips; + c.peakPowerDrawMw = hubArray[i].peak_power_draw_mw; + c.stoppedPowerDrawMw = hubArray[i].stopped_power_draw_mw; + c.sleepPowerDrawMw = hubArray[i].sleep_power_draw_mw; + + info.callBack = nullptr; + info.osAppName = hubArray[i].os_app_name; + mCachedHubInfo[hubArray[i].hub_id] = info; + + hubs.push_back(c); + } + } else { + ALOGW("Context Hub Hal Adapter not initialized"); + } + + _hidl_cb(hubs); + return Void(); +} + +bool Contexthub::isValidHubId(uint32_t hubId) { + if (!mCachedHubInfo.count(hubId)) { + ALOGW("Hub information not found for hubId %" PRIu32, hubId); + return false; + } else { + return true; + } +} + +sp<IContexthubCallback> Contexthub::getCallBackForHubId(uint32_t hubId) { + if (!isValidHubId(hubId)) { + return nullptr; + } else { + return mCachedHubInfo[hubId].callBack; + } +} + +Return<Result> Contexthub::sendMessageToHub(uint32_t hubId, + const ContextHubMsg &msg) { + if (!isInitialized()) { + return Result::NOT_INIT; + } + + if (!isValidHubId(hubId) || msg.msg.size() > UINT32_MAX) { + return Result::BAD_PARAMS; + } + + hub_message_t txMsg = { + .app_name.id = msg.appName, + .message_type = msg.msgType, + .message_len = static_cast<uint32_t>(msg.msg.size()), // Note the check above + .message = static_cast<const uint8_t *>(msg.msg.data()), + }; + + ALOGI("Sending msg of type %" PRIu32 ", size %" PRIu32 " to app 0x%" PRIx64, + txMsg.message_type, + txMsg.message_len, + txMsg.app_name.id); + + if(mContextHubModule->send_message(hubId, &txMsg) != 0) { + return Result::TRANSACTION_FAILED; + } + + return Result::OK; +} + +Return<Result> Contexthub::reboot(uint32_t hubId) { + if (!isInitialized()) { + return Result::NOT_INIT; + } + + hub_message_t msg; + + if (setOsAppAsDestination(&msg, hubId) == false) { + return Result::BAD_PARAMS; + } + + msg.message_type = CONTEXT_HUB_OS_REBOOT; + msg.message_len = 0; + msg.message = nullptr; + + if(mContextHubModule->send_message(hubId, &msg) != 0) { + return Result::TRANSACTION_FAILED; + } else { + return Result::OK; + } +} + +Return<Result> Contexthub::registerCallback(uint32_t hubId, + const sp<IContexthubCallback> &cb) { + Return<Result> retVal = Result::BAD_PARAMS; + + if (!isInitialized()) { + // Not initilalized + ALOGW("Context hub not initialized successfully"); + retVal = Result::NOT_INIT; + } else if (!isValidHubId(hubId)) { + // Initialized, but hubId is not valid + retVal = Result::BAD_PARAMS; + } else if (mContextHubModule->subscribe_messages(hubId, + contextHubCb, + this) == 0) { + // Initialized && valid hub && subscription successful + retVal = Result::OK; + mCachedHubInfo[hubId].callBack = cb; + } else { + // Initalized && valid hubId - but subscription unsuccessful + // This is likely an internal error in the HAL implementation, but we + // cannot add more information. + ALOGW("Could not subscribe to the hub for callback"); + retVal = Result::UNKNOWN_FAILURE; + } + + return retVal; +} + +static bool isValidOsStatus(const uint8_t *msg, + size_t msgLen, + status_response_t *rsp) { + // Workaround a bug in some HALs + if (msgLen == 1) { + rsp->result = msg[0]; + return true; + } + + if (msg == nullptr || msgLen != sizeof(*rsp)) { + ALOGI("Received invalid response (is null : %d, size %zu)", + msg == nullptr ? 1 : 0, + msgLen); + return false; + } + + memcpy(rsp, msg, sizeof(*rsp)); + + // No sanity checks on return values + return true; +} + +int Contexthub::handleOsMessage(sp<IContexthubCallback> cb, + uint32_t msgType, + const uint8_t *msg, + int msgLen) { + int retVal = -1; + + + switch(msgType) { + case CONTEXT_HUB_APPS_ENABLE: + case CONTEXT_HUB_APPS_DISABLE: + case CONTEXT_HUB_LOAD_APP: + case CONTEXT_HUB_UNLOAD_APP: + { + struct status_response_t rsp; + TransactionResult result; + if (isValidOsStatus(msg, msgLen, &rsp) && rsp.result == 0) { + retVal = 0; + result = TransactionResult::SUCCESS; + } else { + result = TransactionResult::FAILURE; + } + + if (cb != nullptr) { + cb->handleTxnResult(mTransactionId, result); + } + retVal = 0; + mIsTransactionPending = false; + break; + } + + case CONTEXT_HUB_QUERY_APPS: + { + std::vector<HubAppInfo> apps; + int numApps = msgLen / sizeof(hub_app_info); + const hub_app_info *unalignedInfoAddr = reinterpret_cast<const hub_app_info *>(msg); + + for (int i = 0; i < numApps; i++) { + hub_app_info query_info; + memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info)); + HubAppInfo app; + app.appId = query_info.app_name.id; + app.version = query_info.version; + // TODO :: Add memory ranges + + apps.push_back(app); + } + + if (cb != nullptr) { + cb->handleAppsInfo(apps); + } + retVal = 0; + break; + } + + case CONTEXT_HUB_QUERY_MEMORY: + { + // Deferring this use + retVal = 0; + break; + } + + case CONTEXT_HUB_OS_REBOOT: + { + mIsTransactionPending = false; + if (cb != nullptr) { + cb->handleHubEvent(AsyncEventType::RESTARTED); + } + retVal = 0; + break; + } + + default: + { + retVal = -1; + break; + } + } + + return retVal; +} + +int Contexthub::contextHubCb(uint32_t hubId, + const struct hub_message_t *rxMsg, + void *cookie) { + Contexthub *obj = static_cast<Contexthub *>(cookie); + + if (rxMsg == nullptr) { + ALOGW("Ignoring NULL message"); + return -1; + } + + if (!obj->isValidHubId(hubId)) { + ALOGW("Invalid hub Id %" PRIu32, hubId); + return -1; + } + + sp<IContexthubCallback> cb = obj->getCallBackForHubId(hubId); + + if (cb == nullptr) { + // This should not ever happen + ALOGW("No callback registered, returning"); + return -1; + } + + if (rxMsg->message_type < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) { + obj->handleOsMessage(cb, + rxMsg->message_type, + static_cast<const uint8_t *>(rxMsg->message), + rxMsg->message_len); + } else { + ContextHubMsg msg; + + msg.appName = rxMsg->app_name.id; + msg.msgType = rxMsg->message_type; + msg.msg = std::vector<uint8_t>(static_cast<const uint8_t *>(rxMsg->message), + static_cast<const uint8_t *>(rxMsg->message) + + rxMsg->message_len); + + cb->handleClientMsg(msg); + } + + return 0; +} + +Return<Result> Contexthub::unloadNanoApp(uint32_t hubId, + uint64_t appId, + uint32_t transactionId) { + if (!isInitialized()) { + return Result::NOT_INIT; + } + + if (mIsTransactionPending) { + return Result::TRANSACTION_PENDING; + } + + hub_message_t msg; + + if (setOsAppAsDestination(&msg, hubId) == false) { + return Result::BAD_PARAMS; + } + + struct apps_disable_request_t req; + + msg.message_type = CONTEXT_HUB_UNLOAD_APP; + msg.message_len = sizeof(req); + msg.message = &req; + req.app_name.id = appId; + + if(mContextHubModule->send_message(hubId, &msg) != 0) { + return Result::TRANSACTION_FAILED; + } else { + mTransactionId = transactionId; + mIsTransactionPending = true; + return Result::OK; + } +} + +Return<Result> Contexthub::loadNanoApp(uint32_t hubId, + const NanoAppBinary& appBinary, + uint32_t transactionId) { + if (!isInitialized()) { + return Result::NOT_INIT; + } + + if (mIsTransactionPending) { + return Result::TRANSACTION_PENDING; + } + + hub_message_t hubMsg; + + if (setOsAppAsDestination(&hubMsg, hubId) == false) { + return Result::BAD_PARAMS; + } + + // Data from the nanoapp header is passed through HIDL as explicit fields, + // but the legacy HAL expects it prepended to the binary, therefore we must + // reconstruct it here prior to passing to the legacy HAL. + uint32_t targetChreApiVersion = + (appBinary.targetChreApiMajorVersion << 24) | + (appBinary.targetChreApiMinorVersion << 16); + const struct nano_app_binary_t header = { + .header_version = htole32(1), + .magic = htole32(NANOAPP_MAGIC), + .app_id.id = htole64(appBinary.appId), + .app_version = htole32(appBinary.appVersion), + .flags = htole32(appBinary.flags), + .hw_hub_type = htole64(0), + .reserved[0] = htole32(targetChreApiVersion), + .reserved[1] = 0, + }; + const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(&header); + + std::vector<uint8_t> binaryWithHeader(appBinary.customBinary); + binaryWithHeader.insert(binaryWithHeader.begin(), + headerBytes, + headerBytes + sizeof(header)); + + hubMsg.message_type = CONTEXT_HUB_LOAD_APP; + hubMsg.message_len = binaryWithHeader.size(); + hubMsg.message = binaryWithHeader.data(); + + if (mContextHubModule->send_message(hubId, &hubMsg) != 0) { + return Result::TRANSACTION_FAILED; + } else { + mTransactionId = transactionId; + mIsTransactionPending = true; + return Result::OK; + } +} + +Return<Result> Contexthub::enableNanoApp(uint32_t hubId, + uint64_t appId, + uint32_t transactionId) { + if (!isInitialized()) { + return Result::NOT_INIT; + } + + if (mIsTransactionPending) { + return Result::TRANSACTION_PENDING; + } + + hub_message_t msg; + + if (setOsAppAsDestination(&msg, hubId) == false) { + return Result::BAD_PARAMS; + } + + struct apps_enable_request_t req; + + msg.message_type = CONTEXT_HUB_APPS_ENABLE; + msg.message_len = sizeof(req); + req.app_name.id = appId; + msg.message = &req; + + if(mContextHubModule->send_message(hubId, &msg) != 0) { + return Result::TRANSACTION_FAILED; + } else { + mTransactionId = transactionId; + mIsTransactionPending = true; + return Result::OK; + } +} + +Return<Result> Contexthub::disableNanoApp(uint32_t hubId, + uint64_t appId, + uint32_t transactionId) { + if (!isInitialized()) { + return Result::NOT_INIT; + } + + if (mIsTransactionPending) { + return Result::TRANSACTION_PENDING; + } + + hub_message_t msg; + + if (setOsAppAsDestination(&msg, hubId) == false) { + return Result::BAD_PARAMS; + } + + struct apps_disable_request_t req; + + msg.message_type = CONTEXT_HUB_APPS_DISABLE; + msg.message_len = sizeof(req); + req.app_name.id = appId; + msg.message = &req; + + if(mContextHubModule->send_message(hubId, &msg) != 0) { + return Result::TRANSACTION_FAILED; + } else { + mTransactionId = transactionId; + mIsTransactionPending = true; + return Result::OK; + } +} + +Return<Result> Contexthub::queryApps(uint32_t hubId) { + if (!isInitialized()) { + return Result::NOT_INIT; + } + + hub_message_t msg; + + if (setOsAppAsDestination(&msg, hubId) == false) { + ALOGW("Could not find hubId %" PRIu32, hubId); + return Result::BAD_PARAMS; + } + + query_apps_request_t payload; + payload.app_name.id = ALL_APPS; // TODO : Pass this in as a parameter + msg.message = &payload; + msg.message_len = sizeof(payload); + msg.message_type = CONTEXT_HUB_QUERY_APPS; + + if(mContextHubModule->send_message(hubId, &msg) != 0) { + ALOGW("Query Apps sendMessage failed"); + return Result::TRANSACTION_FAILED; + } + + return Result::OK; +} + +bool Contexthub::isInitialized() { + return (mInitCheck == OK && mContextHubModule != nullptr); +} + +IContexthub *HIDL_FETCH_IContexthub(const char * halName) { + ALOGI("%s Called for %s", __FUNCTION__, halName); + Contexthub *contexthub = new Contexthub; + + if (!contexthub->isInitialized()) { + delete contexthub; + contexthub = nullptr; + } + + return contexthub; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace contexthub +} // namespace hardware +} // namespace android
diff --git a/contexthub/1.0/default/Contexthub.h b/contexthub/1.0/default/Contexthub.h new file mode 100644 index 0000000..236e079 --- /dev/null +++ b/contexthub/1.0/default/Contexthub.h
@@ -0,0 +1,105 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H_ +#define ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H_ + +#include <unordered_map> + +#include <android/hardware/contexthub/1.0/IContexthub.h> +#include <hardware/context_hub.h> + +namespace android { +namespace hardware { +namespace contexthub { +namespace V1_0 { +namespace implementation { + +struct Contexthub : public ::android::hardware::contexthub::V1_0::IContexthub { + Contexthub(); + + Return<void> getHubs(getHubs_cb _hidl_cb) override; + + Return<Result> registerCallback(uint32_t hubId, + const sp<IContexthubCallback> &cb) override; + + Return<Result> sendMessageToHub(uint32_t hubId, + const ContextHubMsg &msg) override; + + Return<Result> loadNanoApp(uint32_t hubId, + const NanoAppBinary& appBinary, + uint32_t transactionId) override; + + Return<Result> unloadNanoApp(uint32_t hubId, + uint64_t appId, + uint32_t transactionId) override; + + Return<Result> enableNanoApp(uint32_t hubId, + uint64_t appId, + uint32_t transactionId) override; + + Return<Result> disableNanoApp(uint32_t hubId, + uint64_t appId, + uint32_t transactionId) override; + + Return<Result> queryApps(uint32_t hubId) override; + + Return<Result> reboot(uint32_t hubId); + + bool isInitialized(); + +private: + + struct CachedHubInformation{ + struct hub_app_name_t osAppName; + sp<IContexthubCallback> callBack; + }; + + status_t mInitCheck; + const struct context_hub_module_t *mContextHubModule; + std::unordered_map<uint32_t, CachedHubInformation> mCachedHubInfo; + + sp<IContexthubCallback> mCb; + bool mIsTransactionPending; + uint32_t mTransactionId; + + bool isValidHubId(uint32_t hubId); + + sp<IContexthubCallback> getCallBackForHubId(uint32_t hubId); + + int handleOsMessage(sp<IContexthubCallback> cb, + uint32_t msgType, + const uint8_t *msg, + int msgLen); + + static int contextHubCb(uint32_t hubId, + const struct hub_message_t *rxMsg, + void *cookie); + + bool setOsAppAsDestination(hub_message_t *msg, int hubId); + + DISALLOW_COPY_AND_ASSIGN(Contexthub); +}; + +extern "C" IContexthub *HIDL_FETCH_IContexthub(const char *name); + +} // namespace implementation +} // namespace V1_0 +} // namespace contexthub +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_CONTEXTHUB_V1_0_CONTEXTHUB_H_
diff --git a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc new file mode 100644 index 0000000..5677ec2 --- /dev/null +++ b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
@@ -0,0 +1,4 @@ +service contexthub-hal-1-0 /vendor/bin/hw/android.hardware.contexthub@1.0-service + class hal + user system + group system
diff --git a/contexthub/1.0/default/service.cpp b/contexthub/1.0/default/service.cpp new file mode 100644 index 0000000..8c676b4 --- /dev/null +++ b/contexthub/1.0/default/service.cpp
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.contexthub@1.0-service" + +#include <android/hardware/contexthub/1.0/IContexthub.h> +#include <hidl/LegacySupport.h> + +using android::hardware::contexthub::V1_0::IContexthub; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IContexthub>(); +}
diff --git a/contexthub/1.0/types.hal b/contexthub/1.0/types.hal new file mode 100644 index 0000000..4950627 --- /dev/null +++ b/contexthub/1.0/types.hal
@@ -0,0 +1,196 @@ +/* + * Copyright (C) 2016 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.contexthub@1.0; + +enum Result : uint32_t { + OK, // Success + UNKNOWN_FAILURE, // Failure, unknown reason + BAD_PARAMS, // Parameters not sane + NOT_INIT, // Not initialized + TRANSACTION_FAILED, // Transaction failed + TRANSACTION_PENDING, // Pending transaction, cannot accept a new request +}; + +enum NanoAppFlags : uint32_t { + SIGNED = 1 << 0, + ENCRYPTED = 1 << 1, +}; + +struct NanoAppBinary { + uint64_t appId; // Nanoapp identifier + uint32_t appVersion; // Version of the app (semantics defined by app) + bitfield<NanoAppFlags> flags; + + // The version of the CHRE API that this nanoApp was compiled against. See + // the CHRE API header file chre/version.h for more information. The hub + // implementation must use this to confirm compatibility before loading + // this nanoApp. + uint8_t targetChreApiMajorVersion; + uint8_t targetChreApiMinorVersion; + + // Implementation-specific binary nanoapp data. This does not include the + // common nanoapp header that contains the app ID, etc., as this data is + // explicitly passed through the other fields in this struct. + vec<uint8_t> customBinary; +}; + +enum SensorType : uint32_t { + RESERVED, + ACCELEROMETER, + GYROSCOPE, + MAGNETOMETER, + BAROMETER, + PROXIMITY_SENSOR, + AMBIENT_LIGHT_SENSOR, + STATIONARY_DETECT, + INSTANT_MOTION_DETECT, + + GPS = 0x100, + // Reserving this space for variants on GPS + + WIFI = 0x200, + // Reserving this space for variants on WIFI + + AUDIO = 0x300, + // Reserving this space for variants on Audio + + CAMERA = 0x400, + // Reserving this space for variants on Camera + + BLE = 0x500, + // Reserving this space for variants on Bluetooth Low Energy + + WWAN = 0x600, + // Reserving this space for variants on WWAN + + PRIVATE_SENSOR_BASE = 0x10000, + // Sensor types beyond PRIVATE_SENSOR_BASE are custom types +}; + +struct PhysicalSensor{ + SensorType sensorType; // From the definitions above eg: 100 + string type; // Type as a string. eg: "GPS" + string name; // Identifier eg: "Bosch BMI160" + string vendor; // Vendor : eg "STM" + uint32_t version; // Version : eg 0x1001 + uint32_t fifoReservedCount; // Batching possible in hardware. Please + // note that here hardware does not include + // the context hub itself. Thus, this + // definition may be different from say the + // number advertised in the sensors HAL + // which allows for batching in a hub. + uint32_t fifoMaxCount; // Maximum number of batchable events. + uint64_t minDelayMs; // In milliseconds, corresponding to highest + // sampling freq. + uint64_t maxDelayMs; // In milliseconds, corresponds to minimum + // sampling frequency + float peakPowerMw; // At max frequency & no batching, power + // in milliwatts +}; + +struct ContextHub { + string name; // Descriptive name eg: "Awesome Hub #1" + string vendor; // Hub hardware vendor eg: "Qualcomm" + string toolchain; // Toolchain to make binaries eg: "gcc ARM" + uint32_t platformVersion; // Version of the hardware : eg 0x20 + uint32_t toolchainVersion; // Version of the toolchain : eg: 0x484 + uint32_t hubId; // A device unique ID for this hub + + float peakMips; // Peak MIPS platform can deliver + float stoppedPowerDrawMw; // If stopped, retention power, milliwatts + float sleepPowerDrawMw; // If sleeping, retention power, milliwatts + float peakPowerDrawMw; // For a busy CPU, power in milliwatts + + vec<PhysicalSensor> connectedSensors; // Array of connected sensors + + uint32_t maxSupportedMsgLen;// This is the maximum size of the message that can + // be sent to the hub in one chunk (in bytes) + + // Machine-readable CHRE platform ID, returned to nanoapps in the CHRE API + // function call chreGetPlatformId(). This field pairs with + // chreApiMajorVersion, chreApiMinorVersion, and chrePatchVersion to fully + // specify the CHRE implementation version. See also the CHRE API header + // file chre/version.h. + uint64_t chrePlatformId; + + // The version of the CHRE implementation returned to nanoApps in the CHRE + // API function call chreGetVersion(). The major and minor version specify + // the implemented version of the CHRE API, while the patch version + // describes the implementation version within the scope of the platform + // ID. See also the CHRE API header file chre/version.h. + uint8_t chreApiMajorVersion; + uint8_t chreApiMinorVersion; + uint16_t chrePatchVersion; +}; + +enum HostEndPoint : uint16_t { + BROADCAST = 0xFFFF, // The message endpoint is a broadcast end point. + // This value must never be used for a message from + // the host to the hub. + // If BROADCAST is specified as a destination for a + // message from the context hub to the ContextHub + // service, the message must be broadcast to all + // registered clients by the Context Hub service. + UNSPECIFIED = 0xFFFE, // The message endpoint is unspecified. This value + // must not be used for messages from the hub to host. + // This value may be used for messages from the host + // to the hub. +}; + +struct ContextHubMsg { + uint64_t appName; // Intended recipient (appId) + uint16_t hostEndPoint; // identifier for the endpoint. (also see enum HostEndPoint) + uint32_t msgType; // Identifier for message + vec<uint8_t> msg; // Message body +}; + +enum HubMemoryType : uint32_t { + MAIN = 0, // Main memory + SECONDARY = 1, // Secondary memory + TCM = 2, // Tightly coupled memory +}; + +enum HubMemoryFlag : uint32_t { + READ = 1 << 0, // Readable + WRITE = 1 << 1, // Writable + EXEC = 1 << 2, // Executable +}; + +struct MemRange { + uint32_t totalBytes; // Total capacity in bytes + uint32_t freeBytes; // Free capacity in bytes + HubMemoryType type; // Type of memory, see HubMemoryType + bitfield<HubMemoryFlag> flags; +}; + +enum AsyncEventType : uint32_t { + RESTARTED = 1, // Hub restarted unexpectedly +}; + +enum TransactionResult : int32_t { + SUCCESS, // Successful completion of transaction + FAILURE, // Failed transaction +}; + +struct HubAppInfo { + uint64_t appId; // Identifier of the app + uint32_t version; // Version of the app + vec<MemRange> memUsage; // Memory used by this app + bool enabled; // true if the app is currently enabled and running, + // or false if in the loaded but disabled state +}; +
diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..c35386d --- /dev/null +++ b/contexthub/1.0/vts/functional/Android.bp
@@ -0,0 +1,34 @@ +// +// Copyright (C) 2017 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. +// + +cc_test { + name: "VtsHalContexthubV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalContexthubV1_0TargetTest.cpp"], + shared_libs: [ + "liblog", + "libhidlbase", + "libhidltransport", + "libutils", + "android.hardware.contexthub@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ] +} +
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp new file mode 100644 index 0000000..765857f --- /dev/null +++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -0,0 +1,386 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "contexthub_hidl_hal_test" + +#include <android-base/logging.h> +#include <android/hardware/contexthub/1.0/IContexthub.h> +#include <android/hardware/contexthub/1.0/IContexthubCallback.h> +#include <android/hardware/contexthub/1.0/types.h> +#include <android/log.h> +#include <VtsHalHidlTargetTestBase.h> + +#include <cinttypes> +#include <future> +#include <utility> + +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::contexthub::V1_0::AsyncEventType; +using ::android::hardware::contexthub::V1_0::ContextHub; +using ::android::hardware::contexthub::V1_0::ContextHubMsg; +using ::android::hardware::contexthub::V1_0::HubAppInfo; +using ::android::hardware::contexthub::V1_0::IContexthub; +using ::android::hardware::contexthub::V1_0::IContexthubCallback; +using ::android::hardware::contexthub::V1_0::NanoAppBinary; +using ::android::hardware::contexthub::V1_0::Result; +using ::android::hardware::contexthub::V1_0::TransactionResult; +using ::android::sp; + +#define ASSERT_OK(result) ASSERT_EQ(result, Result::OK) +#define EXPECT_OK(result) EXPECT_EQ(result, Result::OK) + +namespace { + +// App ID with vendor "GoogT" (Google Testing), app identifier 0x555555. This +// app ID is reserved and must never appear in the list of loaded apps. +constexpr uint64_t kNonExistentAppId = 0x476f6f6754555555; + +// Helper that does explicit conversion of an enum class to its underlying/base +// type. Useful for stream output of enum values. +template<typename EnumType> +constexpr typename std::underlying_type<EnumType>::type asBaseType( + EnumType value) { + return static_cast<typename std::underlying_type<EnumType>::type>(value); +} + +// Synchronously queries IContexthub::getHubs() and returns the result +hidl_vec<ContextHub> getHubsSync(sp<IContexthub> hubApi) { + hidl_vec<ContextHub> hubList; + std::promise<void> barrier; + + hubApi->getHubs([&hubList, &barrier](const hidl_vec<ContextHub>& hubs) { + hubList = hubs; + barrier.set_value(); + }); + barrier.get_future().wait_for(std::chrono::seconds(1)); + + return hubList; +} + +// Gets a list of valid hub IDs in the system +std::vector<uint32_t> getHubIds() { + static std::vector<uint32_t> hubIds; + + if (hubIds.size() == 0) { + sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>(); + + if (hubApi != nullptr) { + for (ContextHub hub : getHubsSync(hubApi)) { + hubIds.push_back(hub.hubId); + } + } + } + + ALOGD("Running tests against all %zu reported hubs", hubIds.size()); + return hubIds; +} + +// Base test fixture that initializes the HAL and makes the context hub API +// handle available +class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>(); + ASSERT_NE(hubApi, nullptr); + + // getHubs() must be called at least once for proper initialization of the + // HAL implementation + getHubsSync(hubApi); + } + + virtual void TearDown() override {} + + sp<IContexthub> hubApi; +}; + +// Test fixture parameterized by hub ID +class ContexthubHidlTest : public ContexthubHidlTestBase, + public ::testing::WithParamInterface<uint32_t> { + public: + uint32_t getHubId() { + return GetParam(); + } + + Result registerCallback(sp<IContexthubCallback> cb) { + Result result = hubApi->registerCallback(getHubId(), cb); + ALOGD("Registered callback, result %" PRIu32, result); + return result; + } +}; + +// Base callback implementation that just logs all callbacks by default +class ContexthubCallbackBase : public IContexthubCallback { + public: + virtual Return<void> handleClientMsg(const ContextHubMsg& /*msg*/) override { + ALOGD("Got client message callback"); + return Void(); + } + + virtual Return<void> handleTxnResult( + uint32_t txnId, TransactionResult result) override { + ALOGD("Got transaction result callback for txnId %" PRIu32 " with result %" + PRId32, txnId, result); + return Void(); + } + + virtual Return<void> handleHubEvent(AsyncEventType evt) override { + ALOGD("Got hub event callback for event type %" PRIu32, evt); + return Void(); + } + + virtual Return<void> handleAppAbort(uint64_t appId, uint32_t abortCode) + override { + ALOGD("Got app abort notification for appId 0x%" PRIx64 " with abort code " + "0x%" PRIx32, appId, abortCode); + return Void(); + } + + virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& /*appInfo*/) + override { + ALOGD("Got app info callback"); + return Void(); + } +}; + +// Wait for a callback to occur (signaled by the given future) up to the +// provided timeout. If the future is invalid or the callback does not come +// within the given time, returns false. +template<class ReturnType> +bool waitForCallback( + std::future<ReturnType> future, + ReturnType *result, + std::chrono::milliseconds timeout = std::chrono::seconds(5)) { + auto expiration = std::chrono::system_clock::now() + timeout; + + EXPECT_NE(result, nullptr); + EXPECT_TRUE(future.valid()); + if (result != nullptr && future.valid()) { + std::future_status status = future.wait_until(expiration); + EXPECT_NE(status, std::future_status::timeout) + << "Timed out waiting for callback"; + + if (status == std::future_status::ready) { + *result = future.get(); + return true; + } + } + + return false; +} + +// Ensures that the metadata reported in getHubs() is sane +TEST_F(ContexthubHidlTestBase, TestGetHubs) { + hidl_vec<ContextHub> hubs = getHubsSync(hubApi); + ALOGD("System reports %zu hubs", hubs.size()); + + for (ContextHub hub : hubs) { + ALOGD("Checking hub ID %" PRIu32, hub.hubId); + + EXPECT_FALSE(hub.name.empty()); + EXPECT_FALSE(hub.vendor.empty()); + EXPECT_FALSE(hub.toolchain.empty()); + EXPECT_GT(hub.peakMips, 0); + EXPECT_GE(hub.stoppedPowerDrawMw, 0); + EXPECT_GE(hub.sleepPowerDrawMw, 0); + EXPECT_GT(hub.peakPowerDrawMw, 0); + + // Minimum 128 byte MTU as required by CHRE API v1.0 + EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128)); + } +} + +TEST_P(ContexthubHidlTest, TestRegisterCallback) { + ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId()); + ASSERT_OK(registerCallback(new ContexthubCallbackBase())); +} + +TEST_P(ContexthubHidlTest, TestRegisterNullCallback) { + ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId()); + ASSERT_OK(registerCallback(nullptr)); +} + +// Helper callback that puts the async appInfo callback data into a promise +class QueryAppsCallback : public ContexthubCallbackBase { + public: + virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& appInfo) + override { + ALOGD("Got app info callback with %zu apps", appInfo.size()); + promise.set_value(appInfo); + return Void(); + } + + std::promise<hidl_vec<HubAppInfo>> promise; +}; + +// Calls queryApps() and checks the returned metadata +TEST_P(ContexthubHidlTest, TestQueryApps) { + ALOGD("TestQueryApps called, hubId %u", getHubId()); + sp<QueryAppsCallback> cb = new QueryAppsCallback(); + ASSERT_OK(registerCallback(cb)); + + Result result = hubApi->queryApps(getHubId()); + ASSERT_OK(result); + + ALOGD("Waiting for app info callback"); + hidl_vec<HubAppInfo> appList; + ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList)); + for (const HubAppInfo &appInfo : appList) { + EXPECT_NE(appInfo.appId, UINT64_C(0)); + EXPECT_NE(appInfo.appId, kNonExistentAppId); + } +} + +// Helper callback that puts the TransactionResult for the expectedTxnId into a +// promise +class TxnResultCallback : public ContexthubCallbackBase { + public: + virtual Return<void> handleTxnResult( + uint32_t txnId, TransactionResult result) override { + ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %" + PRIu32 ") with result %" PRId32, txnId, expectedTxnId, result); + if (txnId == expectedTxnId) { + promise.set_value(result); + } + return Void(); + } + + uint32_t expectedTxnId = 0; + std::promise<TransactionResult> promise; +}; + +// Parameterized fixture that sets the callback to TxnResultCallback +class ContexthubTxnTest : public ContexthubHidlTest { + public: + virtual void SetUp() override { + ContexthubHidlTest::SetUp(); + ASSERT_OK(registerCallback(cb)); + } + + sp<TxnResultCallback> cb = new TxnResultCallback(); +}; + + +// Checks cases where the hub implementation is expected to return an error, but +// that error can be returned either synchronously or in the asynchronous +// transaction callback. Returns an AssertionResult that can be used in +// ASSERT/EXPECT_TRUE. Allows checking the sync result against 1 additional +// allowed error code apart from OK and TRANSACTION_FAILED, which are always +// allowed. +::testing::AssertionResult checkFailureSyncOrAsync( + Result result, Result allowedSyncResult, + std::future<TransactionResult>&& future) { + if (result == Result::OK) { + // No error reported synchronously - this is OK, but then we should get an + // async callback with a failure status + TransactionResult asyncResult; + if (!waitForCallback(std::forward<std::future<TransactionResult>>(future), + &asyncResult)) { + return ::testing::AssertionFailure() + << "Got successful sync result, then failed to receive async cb"; + } else if (asyncResult == TransactionResult::SUCCESS) { + return ::testing::AssertionFailure() + << "Got successful sync result, then unexpected successful async " + "result"; + } + } else if (result != allowedSyncResult && + result != Result::TRANSACTION_FAILED) { + return ::testing::AssertionFailure() << "Got sync result " + << asBaseType(result) << ", expected TRANSACTION_FAILED or " + << asBaseType(allowedSyncResult); + } + + return ::testing::AssertionSuccess(); +} + +TEST_P(ContexthubTxnTest, TestSendMessageToNonExistentNanoApp) { + ContextHubMsg msg; + msg.appName = kNonExistentAppId; + msg.msgType = 1; + msg.msg.resize(4); + std::fill(msg.msg.begin(), msg.msg.end(), 0); + + ALOGD("Sending message to non-existent nanoapp"); + Result result = hubApi->sendMessageToHub(getHubId(), msg); + if (result != Result::OK && + result != Result::BAD_PARAMS && + result != Result::TRANSACTION_FAILED) { + FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS" + << ", or TRANSACTION_FAILED"; + } +} + +TEST_P(ContexthubTxnTest, TestLoadEmptyNanoApp) { + cb->expectedTxnId = 0123; + NanoAppBinary emptyApp; + + emptyApp.appId = kNonExistentAppId; + emptyApp.appVersion = 1; + emptyApp.flags = 0; + emptyApp.targetChreApiMajorVersion = 1; + emptyApp.targetChreApiMinorVersion = 0; + + ALOGD("Loading empty nanoapp"); + Result result = hubApi->loadNanoApp(getHubId(), emptyApp, cb->expectedTxnId); + EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, + cb->promise.get_future())); +} + +TEST_P(ContexthubTxnTest, TestUnloadNonexistentNanoApp) { + cb->expectedTxnId = 1234; + + ALOGD("Unloading nonexistent nanoapp"); + Result result = hubApi->unloadNanoApp(getHubId(), kNonExistentAppId, + cb->expectedTxnId); + EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, + cb->promise.get_future())); +} + +TEST_P(ContexthubTxnTest, TestEnableNonexistentNanoApp) { + cb->expectedTxnId = 2345; + + ALOGD("Enabling nonexistent nanoapp"); + Result result = hubApi->enableNanoApp(getHubId(), kNonExistentAppId, + cb->expectedTxnId); + EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, + cb->promise.get_future())); +} + +TEST_P(ContexthubTxnTest, TestDisableNonexistentNanoApp) { + cb->expectedTxnId = 3456; + + ALOGD("Disabling nonexistent nanoapp"); + Result result = hubApi->disableNanoApp(getHubId(), kNonExistentAppId, + cb->expectedTxnId); + EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, + cb->promise.get_future())); +} + +// Parameterize all SingleContexthubTest tests against each valid hub ID +INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubHidlTest, + ::testing::ValuesIn(getHubIds())); +INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubTxnTest, + ::testing::ValuesIn(getHubIds())); + +} // anonymous namespace + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +
diff --git a/contexthub/Android.bp b/contexthub/Android.bp new file mode 100644 index 0000000..ed19a37 --- /dev/null +++ b/contexthub/Android.bp
@@ -0,0 +1,6 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/default", + "1.0/vts/functional", +]
diff --git a/drm/1.0/Android.bp b/drm/1.0/Android.bp new file mode 100644 index 0000000..0241984 --- /dev/null +++ b/drm/1.0/Android.bp
@@ -0,0 +1,90 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.drm@1.0_hal", + srcs: [ + "types.hal", + "ICryptoFactory.hal", + "ICryptoPlugin.hal", + "IDrmFactory.hal", + "IDrmPlugin.hal", + "IDrmPluginListener.hal", + ], +} + +genrule { + name: "android.hardware.drm@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.drm@1.0", + srcs: [ + ":android.hardware.drm@1.0_hal", + ], + out: [ + "android/hardware/drm/1.0/types.cpp", + "android/hardware/drm/1.0/CryptoFactoryAll.cpp", + "android/hardware/drm/1.0/CryptoPluginAll.cpp", + "android/hardware/drm/1.0/DrmFactoryAll.cpp", + "android/hardware/drm/1.0/DrmPluginAll.cpp", + "android/hardware/drm/1.0/DrmPluginListenerAll.cpp", + ], +} + +genrule { + name: "android.hardware.drm@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.drm@1.0", + srcs: [ + ":android.hardware.drm@1.0_hal", + ], + out: [ + "android/hardware/drm/1.0/types.h", + "android/hardware/drm/1.0/ICryptoFactory.h", + "android/hardware/drm/1.0/IHwCryptoFactory.h", + "android/hardware/drm/1.0/BnHwCryptoFactory.h", + "android/hardware/drm/1.0/BpHwCryptoFactory.h", + "android/hardware/drm/1.0/BsCryptoFactory.h", + "android/hardware/drm/1.0/ICryptoPlugin.h", + "android/hardware/drm/1.0/IHwCryptoPlugin.h", + "android/hardware/drm/1.0/BnHwCryptoPlugin.h", + "android/hardware/drm/1.0/BpHwCryptoPlugin.h", + "android/hardware/drm/1.0/BsCryptoPlugin.h", + "android/hardware/drm/1.0/IDrmFactory.h", + "android/hardware/drm/1.0/IHwDrmFactory.h", + "android/hardware/drm/1.0/BnHwDrmFactory.h", + "android/hardware/drm/1.0/BpHwDrmFactory.h", + "android/hardware/drm/1.0/BsDrmFactory.h", + "android/hardware/drm/1.0/IDrmPlugin.h", + "android/hardware/drm/1.0/IHwDrmPlugin.h", + "android/hardware/drm/1.0/BnHwDrmPlugin.h", + "android/hardware/drm/1.0/BpHwDrmPlugin.h", + "android/hardware/drm/1.0/BsDrmPlugin.h", + "android/hardware/drm/1.0/IDrmPluginListener.h", + "android/hardware/drm/1.0/IHwDrmPluginListener.h", + "android/hardware/drm/1.0/BnHwDrmPluginListener.h", + "android/hardware/drm/1.0/BpHwDrmPluginListener.h", + "android/hardware/drm/1.0/BsDrmPluginListener.h", + ], +} + +cc_library_shared { + name: "android.hardware.drm@1.0", + generated_sources: ["android.hardware.drm@1.0_genc++"], + generated_headers: ["android.hardware.drm@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.drm@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/drm/1.0/ICryptoFactory.hal b/drm/1.0/ICryptoFactory.hal new file mode 100644 index 0000000..aeab9bc --- /dev/null +++ b/drm/1.0/ICryptoFactory.hal
@@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 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.drm@1.0; + +import ICryptoPlugin; + +/** + * Ref: frameworks/native/include/media/hardware/CryptoAPI.h:CryptoFactory + * + * ICryptoFactory is the main entry point for interacting with a vendor's + * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions + * which are used by a codec to decrypt protected video content. + */ +interface ICryptoFactory { + /** + * Determine if a crypto scheme is supported by this HAL + * + * @param uuid identifies the crypto scheme in question + * @return isSupported must be true only if the scheme is supported + */ + isCryptoSchemeSupported(uint8_t[16] uuid) generates(bool isSupported); + + /** + * Create a crypto plugin for the specified uuid and scheme-specific + * initialization data. + * + * @param uuid uniquely identifies the drm scheme. See + * http://dashif.org/identifiers/protection for uuid assignments + * @param initData scheme-specific init data. + * @return status the status of the call. The HAL implementation must return + * OK if the plugin is created and ERROR_DRM_CANNOT_HANDLE if the plugin + * cannot be created. + * @return cryptoPlugin the created ICryptoPlugin + */ + createPlugin(uint8_t[16] uuid, vec<uint8_t> initData) + generates (Status status, ICryptoPlugin cryptoPlugin); +};
diff --git a/drm/1.0/ICryptoPlugin.hal b/drm/1.0/ICryptoPlugin.hal new file mode 100644 index 0000000..ca8fa50 --- /dev/null +++ b/drm/1.0/ICryptoPlugin.hal
@@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 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.drm@1.0; + +import android.hardware.drm@1.0::types; + +/** + * Ref: frameworks/native/include/media/hardware/CryptoAPI.h:CryptoPlugin + * + * ICryptoPlugin is the HAL for vendor-provided crypto plugins. + * It allows crypto sessions to be opened and operated on, to + * load crypto keys for a codec to decrypt protected video content. + */ +interface ICryptoPlugin { + /** + * Check if the specified mime-type requires a secure decoder + * component. + * + * @param mime The content mime-type + * @return secureRequired must be true only if a secure decoder is required + * for the specified mime-type + */ + requiresSecureDecoderComponent(string mime) + generates(bool secureRequired); + + /** + * Notify a plugin of the currently configured resolution + * + * @param width - the display resolutions's width + * @param height - the display resolution's height + */ + notifyResolution(uint32_t width, uint32_t height); + + /** + * Associate a mediadrm session with this crypto session + * + * @param sessionId the MediaDrm session ID to associate with this crypto + * session + * @return status the status of the call, status must be + * ERROR_DRM_SESSION_NOT_OPENED if the session is not opened, or + * ERROR_DRM_CANNOT_HANDLE if the operation is not supported by the drm + * scheme. + */ + setMediaDrmSession(vec<uint8_t> sessionId) generates(Status status); + + /** + * Set a shared memory base for subsequent decrypt operations. The buffer + * base is a hidl_memory which maps shared memory in the HAL module. + * After the shared buffer base is established, the decrypt() method + * receives SharedBuffer instances which specify the buffer address range + * for decrypt source and destination addresses. + * + * There can be multiple shared buffers per crypto plugin. The buffers + * are distinguished by the bufferId. + * + * @param base the base IMemory of the memory buffer identified by + * bufferId + * @param bufferId identifies the specific shared buffer for which + * the base is being set. + */ + setSharedBufferBase(memory base, uint32_t bufferId); + + /** + * Decrypt an array of subsamples from the source memory buffer to the + * destination memory buffer. + * + * @param secure a flag to indicate if a secure decoder is being used. This + * enables the plugin to configure buffer modes to work consistently with + * a secure decoder. + * @param the keyId for the key that should be used to do the + * the decryption. The keyId refers to a key in the associated + * MediaDrm instance. + * @param iv the initialization vector to use + * @param mode the crypto mode to use + * @param pattern the crypto pattern to use + * @param subSamples a vector of subsamples indicating the number + * of clear and encrypted bytes to process. This allows the decrypt + * call to operate on a range of subsamples in a single call + * @param source the input buffer for the decryption + * @param offset the offset of the first byte of encrypted data from + * the base of the source buffer + * @param destination the output buffer for the decryption + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_NO_LICENSE if no license keys have been + * loaded, ERROR_DRM_LICENSE_EXPIRED if the license keys have expired, + * ERROR_DRM_RESOURCE_BUSY if the resources required to perform the + * decryption are not available, ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION + * if required output protections are not active, + * ERROR_DRM_SESSION_NOT_OPENED if the decrypt session is not opened, or + * ERROR_DRM_CANNOT_HANDLE in other failure cases. + * @return bytesWritten the number of bytes output from the decryption + * @return detailedError if the error is a vendor-specific error, the + * vendor's crypto HAL may provide a detailed error string to help + * describe the error. + */ + decrypt(bool secure, uint8_t[16] keyId, uint8_t[16] iv, Mode mode, + Pattern pattern, vec<SubSample> subSamples, + SharedBuffer source, uint64_t offset, DestinationBuffer destination) + generates(Status status, uint32_t bytesWritten, string detailedError); +};
diff --git a/drm/1.0/IDrmFactory.hal b/drm/1.0/IDrmFactory.hal new file mode 100644 index 0000000..f8e4779 --- /dev/null +++ b/drm/1.0/IDrmFactory.hal
@@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 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.drm@1.0; + +import IDrmPlugin; + +/** + * Ref: frameworks/native/include/media/drm/DrmAPI.h:DrmFactory + * + * IDrmFactory is the main entry point for interacting with a vendor's + * drm HAL to create drm plugin instances. A drm plugin instance + * creates drm sessions which are used to obtain keys for a crypto + * session so it can decrypt* protected video content. + */ + +interface IDrmFactory { + /** + * Determine if a crypto scheme is supported by this HAL + * + * @param uuid identifies the crypto scheme in question + * @return isSupported must be true only if the scheme is supported + */ + isCryptoSchemeSupported(uint8_t[16] uuid) generates(bool isSupported); + + /** + * Determine if the HAL factory is able to construct plugins that support a + * given media container format specified by mimeType + * + * @param mimeType identifies the mime type in question + * @return isSupported must be true only if the scheme is supported + */ + isContentTypeSupported(string mimeType) generates(bool isSupported); + + /** + * Create a drm plugin instance for the specified uuid and scheme-specific + * initialization data. + * + * @param uuid uniquely identifies the drm scheme. See + * http://dashif.org/identifiers/protection for uuid assignments + * @param appPackageName identifies the package name of the calling + * application. + * @return status the status of the call. The HAL implementation must return + * OK if the plugin is created and ERROR_DRM_CANNOT_HANDLE if the plugin + * cannot be created. + */ + createPlugin(uint8_t[16] uuid, string appPackageName) + generates (Status status, IDrmPlugin drmPlugin); +};
diff --git a/drm/1.0/IDrmPlugin.hal b/drm/1.0/IDrmPlugin.hal new file mode 100644 index 0000000..083b311 --- /dev/null +++ b/drm/1.0/IDrmPlugin.hal
@@ -0,0 +1,543 @@ +/** + * Copyright (C) 2016 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.drm@1.0; + +import IDrmPluginListener; + +/** + * Ref: frameworks/native/include/media/drm/DrmAPI.h:DrmPlugin + * + * IDrmPlugin is used to interact with a specific drm plugin that was + * created by IDrm::createPlugin. A drm plugin provides methods for + * obtaining drm keys that may be used by a codec to decrypt protected + * video content. + */ +interface IDrmPlugin { + + /** + * Open a new session with the DrmPlugin object. A session ID is returned + * in the sessionId parameter. + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_NOT_PROVISIONED if the device requires + * provisioning before it can open a session, ERROR_DRM_RESOURCE_BUSY if + * there are insufficent resources available to open a session, + * ERROR_DRM_CANNOT_HANDLE, if openSession is not supported at the time of + * the call or ERROR_DRM_INVALID_STATE if the HAL is in a state where a + * session cannot be opened. + * @return sessionId the session ID for the newly opened session + */ + openSession() generates (Status status, SessionId sessionId); + + /** + * Close a session on the DrmPlugin object + * + * @param sessionId the session id the call applies to + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where the session cannot be closed. + */ + closeSession(SessionId sessionId) generates (Status status); + + /** + * A key request/response exchange occurs between the app and a License + * Server to obtain the keys required to decrypt the content. + * getKeyRequest() is used to obtain an opaque key request blob that is + * delivered to the license server. + * + * @param scope may be a sessionId or a keySetId, depending on the + * specified keyType. When the keyType is OFFLINE or STREAMING, + * scope should be set to the sessionId the keys will be provided to. + * When the keyType is RELEASE, scope should be set to the keySetId + * of the keys being released. + * @param initData container-specific data, its meaning is interpreted + * based on the mime type provided in the mimeType parameter. It could + * contain, for example, the content ID, key ID or other data obtained + * from the content metadata that is required to generate the key request. + * initData may be empty when keyType is RELEASE. + * @param mimeType identifies the mime type of the content + * @param keyType specifies if the keys are to be used for streaming, + * offline or a release + * @param optionalParameters included in the key request message to + * allow a client application to provide additional message parameters to + * the server. + * + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, ERROR_DRM_NOT_PROVISIONED if the device requires provisioning + * before it can generate a key request, ERROR_DRM_CANNOT_HANDLE if + * getKeyRequest is not supported at the time of the call, BAD_VALUE if any + * parameters are invalid or ERROR_DRM_INVALID_STATE if the HAL is in a state + * where a key request cannot be generated. + * @return request if successful, the opaque key request blob is returned + * @return requestType indicates type information about the returned + * request. The type may be one of INITIAL, RENEWAL or RELEASE. An + * INITIAL request is the first key request for a license. RENEWAL is a + * subsequent key request used to refresh the keys in a license. RELEASE + * corresponds to a keyType of RELEASE, which indicates keys are being + * released. + * @return defaultUrl the URL that the request may be sent to, if + * provided by the drm HAL. The app may choose to override this + * URL. + */ + getKeyRequest(vec<uint8_t> scope, vec<uint8_t> initData, + string mimeType, KeyType keyType, KeyedVector optionalParameters) + generates (Status status, vec<uint8_t> request, + KeyRequestType requestType, string defaultUrl); + + /** + * After a key response is received by the app, it is provided to the + * Drm plugin using provideKeyResponse. + * + * @param scope may be a sessionId or a keySetId depending on the type + * of the response. Scope should be set to the sessionId when the response + * is for either streaming or offline key requests. Scope should be set to + * the keySetId when the response is for a release request. + * @param response the response from the key server that is being + * provided to the drm HAL. + * + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, ERROR_DRM_NOT_PROVISIONED if the device requires provisioning + * before it can handle the key response, ERROR_DRM_DEVICE_REVOKED if the + * device has been disabled by the license policy, ERROR_DRM_CANNOT_HANDLE + * if provideKeyResponse is not supported at the time of the call, BAD_VALUE + * if any parameters are invalid or ERROR_DRM_INVALID_STATE if the HAL is + * in a state where a key response cannot be handled. + * @return keySetId when the response is for an offline key request, a + * keySetId is returned in the keySetId vector parameter that can be used + * to later restore the keys to a new session with the method restoreKeys. + * When the response is for a streaming or release request, no keySetId is + * returned. + */ + provideKeyResponse(vec<uint8_t> scope, vec<uint8_t> response) + generates (Status status, vec<uint8_t> keySetId); + + /** + * Remove the current keys from a session + * + * @param sessionId the session id the call applies to + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where the keys cannot be removed. + */ + removeKeys(SessionId sessionId) generates (Status status); + + /** + * Restore persisted offline keys into a new session + * + * @param sessionId the session id the call applies to + * @param keySetId identifies the keys to load, obtained from a prior + * call to provideKeyResponse(). + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where keys cannot be restored. + */ + restoreKeys(SessionId sessionId, + vec<uint8_t> keySetId) generates (Status status); + + /** + * Request an informative description of the license for the session. The + * status is in the form of {name, value} pairs. Since DRM license policies + * vary by vendor, the specific status field names are determined by each + * DRM vendor. Refer to your DRM provider documentation for definitions of + * the field names for a particular drm scheme. + * + * @param sessionId the session id the call applies to + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, BAD_VALUE if the sessionId is invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where key status cannot be queried. + * @return infoList a list of name value pairs describing the license + */ + queryKeyStatus(SessionId sessionId) + generates (Status status, KeyedVector infoList); + + /** + * A provision request/response exchange occurs between the app and a + * provisioning server to retrieve a device certificate. getProvisionRequest + * is used to obtain an opaque provisioning request blob that is delivered + * to the provisioning server. + * + * @param certificateType the type of certificate requested, e.g. "X.509" + * @param certificateAuthority identifies the certificate authority. A + * certificate authority (CA) is an entity which issues digital certificates + * for use by other parties. It is an example of a trusted third party. + * @return status the status of the call. The status must be OK or one of + * the following errors: BAD_VALUE if the sessionId is invalid, + * ERROR_DRM_CANNOT_HANDLE if the drm scheme does not require provisioning + * or ERROR_DRM_INVALID_STATE if the HAL is in a state where the provision + * request cannot be generated. + * @return request if successful the opaque certificate request blob + * is returned + * @return defaultUrl URL that the provisioning request should be + * sent to, if known by the HAL implementation. If the HAL implementation + * does not provide a defaultUrl, the returned string must be empty. + */ + getProvisionRequest(string certificateType, string certificateAuthority) + generates (Status status, vec<uint8_t> request, string defaultUrl); + + /** + * After a provision response is received by the app from a provisioning + * server, it is provided to the Drm HAL using provideProvisionResponse. + * The HAL implementation must receive the provision request and + * store the provisioned credentials. + * + * @param response the opaque provisioning response received by the + * app from a provisioning server. + + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_DEVICE_REVOKED if the device has been + * disabled by the license policy, BAD_VALUE if any parameters are invalid + * or ERROR_DRM_INVALID_STATE if the HAL is in a state where the provision + * response cannot be handled. + * @return certificate the public certificate resulting from the provisioning + * operation, if any. An empty vector indicates that no certificate was + * returned. + * @return wrappedKey an opaque object containing encrypted private key + * material to be used by signRSA when computing an RSA signature on a + * message, see the signRSA method. + */ + provideProvisionResponse(vec<uint8_t> response) generates (Status status, + vec<uint8_t> certificate, vec<uint8_t> wrappedKey); + + /** + * SecureStop is a way of enforcing the concurrent stream limit per + * subscriber. It can securely monitor the lifetime of sessions across + * device reboots by periodically persisting the session lifetime + * status in secure storage. + * + * A signed version of the sessionID is written to persistent storage on the + * device when each MediaCrypto object is created and periodically during + * playback. The sessionID is signed by the device private key to prevent + * tampering. + * + * When playback is completed the session is destroyed, and the secure + * stops are queried by the app. The app then delivers the secure stop + * message to a server which verifies the signature to confirm that the + * session and its keys have been removed from the device. The persisted + * record on the device is removed after receiving and verifying the + * signed response from the server. + */ + + /** + * Get all secure stops on the device + * + * @return status the status of the call. The status must be OK or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stops + * cannot be returned. + * @return secureStops a list of the secure stop opaque objects + */ + getSecureStops() generates + (Status status, vec<SecureStop> secureStops); + + /** + * Get all secure stops by secure stop ID + * + * @param secureStopId the ID of the secure stop to return. The + * secure stop ID is delivered by the key server as part of the key + * response and must also be known by the app. + * + * @return status the status of the call. The status must be OK or one of + * the following errors: BAD_VALUE if the secureStopId is invalid or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop + * cannot be returned. + * @return secureStop the secure stop opaque object + */ + + getSecureStop(SecureStopId secureStopId) + generates (Status status, SecureStop secureStop); + + /** + * Release all secure stops on the device + * + * @return status the status of the call. The status must be OK or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure + * stops cannot be released. + */ + releaseAllSecureStops() generates (Status status); + + /** + * Release a secure stop by secure stop ID + * + * @param secureStopId the ID of the secure stop to release. The + * secure stop ID is delivered by the key server as part of the key + * response and must also be known by the app. + * + * @return status the status of the call. The status must be OK or one of + * the following errors: BAD_VALUE if the secureStopId is invalid or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop + * cannot be released. + */ + releaseSecureStop(vec<uint8_t> secureStopId) generates (Status status); + + /** + * A drm scheme can have properties that are settable and readable + * by an app. There are a few forms of property access methods, + * depending on the data type of the property. + * + * Property values defined by the public API are: + * "vendor" [string] identifies the maker of the drm scheme + * "version" [string] identifies the version of the drm scheme + * "description" [string] describes the drm scheme + * 'deviceUniqueId' [byte array] The device unique identifier is + * established during device provisioning and provides a means of + * uniquely identifying each device. + * + * Since drm scheme properties may vary, additional field names may be + * defined by each DRM vendor. Refer to your DRM provider documentation + * for definitions of its additional field names. + */ + + /** + * Read a string property value given the property name. + * + * @param propertyName the name of the property + * @return status the status of the call. The status must be OK or one of + * the following errors: BAD_VALUE if the property name is invalid, + * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property + * cannot be obtained. + * @return value the property value string + */ + getPropertyString(string propertyName) + generates (Status status, string value); + + /** + * Read a byte array property value given the property name. + * + * @param propertyName the name of the property + * @return status the status of the call. The status must be OK or one of + * the following errors: BAD_VALUE if the property name is invalid, + * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property + * cannot be obtained. + * @return value the property value byte array + */ + getPropertyByteArray(string propertyName) + generates (Status status, vec<uint8_t> value); + + /** + * Write a property string value given the property name + * + * @param propertyName the name of the property + * @param value the value to write + * @return status the status of the call. The status must be OK or one of + * the following errors: BAD_VALUE if the property name is invalid, + * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property + * cannot be set. + */ + setPropertyString(string propertyName, string value) + generates (Status status); + + /** + * Write a property byte array value given the property name + * + * @param propertyName the name of the property + * @param value the value to write + * @return status the status of the call. The status must be OK or one of + * the following errors: BAD_VALUE if the property name is invalid, + * ERROR_DRM_CANNOT_HANDLE if the property is not supported, or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the property + * cannot be set. + */ + setPropertyByteArray(string propertyName, vec<uint8_t> value ) + generates (Status status); + + /** + * The following methods implement operations on a CryptoSession to support + * encrypt, decrypt, sign verify operations on operator-provided + * session keys. + */ + + /** + * Set the cipher algorithm to be used for the specified session. + * + * @param sessionId the session id the call applies to + * @param algorithm the algorithm to use. The string conforms to JCA + * Standard Names for Cipher Transforms and is case insensitive. An + * example algorithm is "AES/CBC/PKCS5Padding". + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where the algorithm cannot be set. + */ + setCipherAlgorithm(SessionId sessionId, string algorithm) + generates (Status status); + + /** + * Set the MAC algorithm to be used for computing hashes in a session. + * + * @param sessionId the session id the call applies to + * @param algorithm the algorithm to use. The string conforms to JCA + * Standard Names for Mac Algorithms and is case insensitive. An example MAC + * algorithm string is "HmacSHA256". + * @return status the status of the call. The status must be OK or one of the + * following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where the algorithm cannot be set. + */ + setMacAlgorithm(SessionId sessionId, string algorithm) + generates (Status status); + + /** + * Encrypt the provided input buffer with the cipher algorithm specified by + * setCipherAlgorithm and the key selected by keyId, and return the + * encrypted data. + * + * @param sessionId the session id the call applies to + * @param keyId the ID of the key to use for encryption + * @param input the input data to encrypt + * @param iv the initialization vector to use for encryption + * @return status the status of the call. The status must be OK or one of the + * following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not opened, + * BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where the encrypt operation cannot be performed. + * @return output the decrypted data + */ + encrypt(SessionId sessionId, vec<uint8_t> keyId, vec<uint8_t> input, + vec<uint8_t> iv) generates (Status status, vec<uint8_t> output); + + /** + * Decrypt the provided input buffer with the cipher algorithm + * specified by setCipherAlgorithm and the key selected by keyId, + * and return the decrypted data. + * + * @param sessionId the session id the call applies to + * @param keyId the ID of the key to use for decryption + * @param input the input data to decrypt + * @param iv the initialization vector to use for decryption + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where the decrypt operation cannot be + * performed. + * @return output the decrypted data + */ + decrypt(SessionId sessionId, vec<uint8_t> keyId, vec<uint8_t> input, + vec<uint8_t> iv) generates (Status status, vec<uint8_t> output); + + /** + * Compute a signature over the provided message using the mac algorithm + * specified by setMacAlgorithm and the key selected by keyId and return + * the signature. + * + * @param sessionId the session id the call applies to + * @param keyId the ID of the key to use for decryption + * @param message the message to compute a signature over + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where the sign operation cannot be + * performed. + * @return signature the computed signature + */ + sign(SessionId sessionId, vec<uint8_t> keyId, vec<uint8_t> message) + generates (Status status, vec<uint8_t> signature); + + /** + * Compute a hash of the provided message using the mac algorithm specified + * by setMacAlgorithm and the key selected by keyId, and compare with the + * expected result. + * + * @param sessionId the session id the call applies to + * @param keyId the ID of the key to use for decryption + * @param message the message to compute a hash of + * @param signature the signature to verify + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is not + * opened, BAD_VALUE if any parameters are invalid or ERROR_DRM_INVALID_STATE + * if the HAL is in a state where the verify operation cannot be + * performed. + * @return match true if the signature is verified positively, + * false otherwise. + */ + verify(SessionId sessionId, vec<uint8_t> keyId, vec<uint8_t> message, + vec<uint8_t> signature) generates (Status status, bool match); + + /** + * Compute an RSA signature on the provided message using the specified + * algorithm. + * + * @param sessionId the session id the call applies to + * @param algorithm the signing algorithm, such as "RSASSA-PSS-SHA1" + * or "PKCS1-BlockType1" + * @param message the message to compute the signature on + * @param wrappedKey the private key returned during provisioning as + * returned by provideProvisionResponse. + * @return status the status of the call. The status must be OK or one of + * the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session is + * not opened, BAD_VALUE if any parameters are invalid or + * ERROR_DRM_INVALID_STATE if the HAL is in a state where the signRSA + * operation cannot be performed. + * @return signature the RSA signature computed over the message + */ + signRSA(SessionId sessionId, string algorithm, vec<uint8_t> message, + vec<uint8_t> wrappedkey) + generates (Status status, vec<uint8_t> signature); + + /** + * Plugins call the following methods to deliver events to the + * java app. + */ + + /** + * Set a listener for a drm session. This allows the drm HAL to + * make asynchronous calls back to the client of IDrm. + * + * @param listener instance of IDrmPluginListener to receive the events + */ + setListener(IDrmPluginListener listener); + + /** + * Legacy event sending method, it sends events of various types using a + * single overloaded set of parameters. This form is deprecated. + * + * @param eventType the type of the event + * @param sessionId identifies the session the event originated from + * @param data event-specific data blob + */ + sendEvent(EventType eventType, SessionId sessionId, vec<uint8_t> data); + + /** + * Send a license expiration update to the listener. The expiration + * update indicates how long the current license is valid before it + * needs to be renewed. + * + * @param sessionId identifies the session the event originated from + * @param expiryTimeInMS the time when the keys need to be renewed. + * The time is in milliseconds, relative to the Unix epoch. A time of 0 + * indicates that the keys never expire. + */ + sendExpirationUpdate(SessionId sessionId, int64_t expiryTimeInMS); + + /** + * Send a keys change event to the listener. The keys change event + * indicates the status of each key in the session. Keys can be + * indicated as being usable, expired, outputnotallowed or statuspending. + * + * @param sessionId identifies the session the event originated from + * @param keyStatusList indicates the status for each key ID in the + * session. + * @param hasNewUsableKey indicates if the event includes at least one + * key that has become usable. + */ + sendKeysChange(SessionId sessionId, vec<KeyStatus> keyStatusList, + bool hasNewUsableKey); +};
diff --git a/drm/1.0/IDrmPluginListener.hal b/drm/1.0/IDrmPluginListener.hal new file mode 100644 index 0000000..15ce008 --- /dev/null +++ b/drm/1.0/IDrmPluginListener.hal
@@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016 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.drm@1.0; + +import android.hardware.drm@1.0::types; + +/** + * Ref: frameworks/native/include/media/drm/DrmAPI.h:DrmPluginListener + */ + +/** + * IDrmPluginListener is a listener interface for Drm events sent from an + * IDrmPlugin instance. + */ +interface IDrmPluginListener { + + /** + * Legacy event sending method, it sends events of various types using a + * single overloaded set of parameters. This form is deprecated. + * + * @param eventType the type of the event + * @param sessionId identifies the session the event originated from + * @param data event-specific data blob + */ + oneway sendEvent(EventType eventType, SessionId sessionId, + vec<uint8_t> data); + + /** + * Send a license expiration update to the listener. The expiration + * update indicates how long the current keys are valid before they + * need to be renewed. + * + * @param sessionId identifies the session the event originated from + * @param expiryTimeInMS the time when the keys need to be renewed. + * The time is in milliseconds, relative to the Unix epoch. A time + * of 0 indicates that the keys never expire. + */ + oneway sendExpirationUpdate(SessionId sessionId, int64_t expiryTimeInMS); + + /** + * Send a keys change event to the listener. The keys change event + * indicates the status of each key in the session. Keys can be + * indicated as being usable, expired, outputnotallowed or statuspending. + * + * @param sessionId identifies the session the event originated from + * @param keyStatusList indicates the status for each key ID in the + * session. + * @param hasNewUsableKey indicates if the event includes at least one + * key that has become usable. + */ + oneway sendKeysChange(SessionId sessionId, vec<KeyStatus> keyStatusList, + bool hasNewUsableKey); +};
diff --git a/drm/1.0/default/Android.mk b/drm/1.0/default/Android.mk new file mode 100644 index 0000000..f2334a0 --- /dev/null +++ b/drm/1.0/default/Android.mk
@@ -0,0 +1,79 @@ +# +# Copyright (C) 2016 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. + + +############# Build legacy drm service ############ + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.drm@1.0-service +LOCAL_INIT_RC := android.hardware.drm@1.0-service.rc +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + android.hardware.drm@1.0 \ + android.hidl.memory@1.0 \ + libhidlbase \ + libhidltransport \ + libhardware \ + liblog \ + libutils \ + +LOCAL_C_INCLUDES := \ + hardware/interfaces/drm + +# TODO: The legacy DRM plugins only support 32-bit. They need +# to be migrated to 64-bit (b/18948909) +LOCAL_32_BIT_ONLY := true + +include $(BUILD_EXECUTABLE) + +############# Build legacy drm impl library ############ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.drm@1.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + DrmFactory.cpp \ + DrmPlugin.cpp \ + CryptoFactory.cpp \ + CryptoPlugin.cpp \ + TypeConvert.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + android.hardware.drm@1.0 \ + android.hidl.memory@1.0 \ + libhidlbase \ + libhidlmemory \ + libhidltransport \ + liblog \ + libmediadrm \ + libstagefright_foundation \ + libutils \ + +LOCAL_C_INCLUDES := \ + frameworks/native/include \ + frameworks/av/include + +# TODO: The legacy DRM plugins only support 32-bit. They need +# to be migrated to 64-bit (b/18948909) +LOCAL_32_BIT_ONLY := true + +include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/1.0/default/CryptoFactory.cpp b/drm/1.0/default/CryptoFactory.cpp new file mode 100644 index 0000000..e46233d --- /dev/null +++ b/drm/1.0/default/CryptoFactory.cpp
@@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.drm@1.0-impl" + +#include "CryptoFactory.h" +#include "CryptoPlugin.h" +#include "TypeConvert.h" +#include <utils/Log.h> + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + + CryptoFactory::CryptoFactory() : + loader("/vendor/lib/mediadrm", "createCryptoFactory") { + } + + // Methods from ::android::hardware::drm::V1_0::ICryptoFactory follow. + Return<bool> CryptoFactory::isCryptoSchemeSupported( + const hidl_array<uint8_t, 16>& uuid) { + for (size_t i = 0; i < loader.factoryCount(); i++) { + if (loader.getFactory(i)->isCryptoSchemeSupported(uuid.data())) { + return true; + } + } + return false; + } + + Return<void> CryptoFactory::createPlugin(const hidl_array<uint8_t, 16>& uuid, + const hidl_vec<uint8_t>& initData, createPlugin_cb _hidl_cb) { + for (size_t i = 0; i < loader.factoryCount(); i++) { + if (loader.getFactory(i)->isCryptoSchemeSupported(uuid.data())) { + android::CryptoPlugin *legacyPlugin = NULL; + status_t status = loader.getFactory(i)->createPlugin(uuid.data(), + initData.data(), initData.size(), &legacyPlugin); + CryptoPlugin *newPlugin = NULL; + if (legacyPlugin == NULL) { + ALOGE("Crypto legacy HAL: failed to create crypto plugin"); + } else { + newPlugin = new CryptoPlugin(legacyPlugin); + } + _hidl_cb(toStatus(status), newPlugin); + return Void(); + } + } + _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, NULL); + return Void(); + } + + ICryptoFactory* HIDL_FETCH_ICryptoFactory(const char* /* name */) { + return new CryptoFactory(); + } + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android
diff --git a/drm/1.0/default/CryptoFactory.h b/drm/1.0/default/CryptoFactory.h new file mode 100644 index 0000000..412b557 --- /dev/null +++ b/drm/1.0/default/CryptoFactory.h
@@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_DRM_V1_0__CRYPTOFACTORY_H +#define ANDROID_HARDWARE_DRM_V1_0__CRYPTOFACTORY_H + +#include <android/hardware/drm/1.0/ICryptoFactory.h> +#include <hidl/Status.h> +#include <media/hardware/CryptoAPI.h> +#include <media/PluginLoader.h> +#include <media/SharedLibrary.h> + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::drm::V1_0::ICryptoFactory; +using ::android::hardware::drm::V1_0::ICryptoPlugin; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +struct CryptoFactory : public ICryptoFactory { + CryptoFactory(); + virtual ~CryptoFactory() {} + + // Methods from ::android::hardware::drm::V1_0::ICryptoFactory follow. + + Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>& uuid) + override; + + Return<void> createPlugin(const hidl_array<uint8_t, 16>& uuid, + const hidl_vec<uint8_t>& initData, createPlugin_cb _hidl_cb) + override; + +private: + android::PluginLoader<android::CryptoFactory> loader; + + CryptoFactory(const CryptoFactory &) = delete; + void operator=(const CryptoFactory &) = delete; +}; + +extern "C" ICryptoFactory* HIDL_FETCH_ICryptoFactory(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_DRM_V1_0__CRYPTOFACTORY_H
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp new file mode 100644 index 0000000..9c51b15 --- /dev/null +++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.drm@1.0-impl" + +#include "CryptoPlugin.h" +#include "TypeConvert.h" + +#include <android/hidl/memory/1.0/IMemory.h> +#include <hidlmemory/mapping.h> +#include <media/stagefright/foundation/AString.h> +#include <utils/Log.h> + +using android::hardware::hidl_memory; +using android::hidl::memory::V1_0::IMemory; + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + + // Methods from ::android::hardware::drm::V1_0::ICryptoPlugin follow + Return<bool> CryptoPlugin::requiresSecureDecoderComponent( + const hidl_string& mime) { + return mLegacyPlugin->requiresSecureDecoderComponent(mime); + } + + Return<void> CryptoPlugin::notifyResolution(uint32_t width, + uint32_t height) { + mLegacyPlugin->notifyResolution(width, height); + return Void(); + } + + Return<Status> CryptoPlugin::setMediaDrmSession( + const hidl_vec<uint8_t>& sessionId) { + return toStatus(mLegacyPlugin->setMediaDrmSession(toVector(sessionId))); + } + + Return<void> CryptoPlugin::setSharedBufferBase(const hidl_memory& base, + uint32_t bufferId) { + mSharedBufferMap[bufferId] = mapMemory(base); + return Void(); + } + + Return<void> CryptoPlugin::decrypt(bool secure, + const hidl_array<uint8_t, 16>& keyId, + const hidl_array<uint8_t, 16>& iv, Mode mode, + const Pattern& pattern, const hidl_vec<SubSample>& subSamples, + const SharedBuffer& source, uint64_t offset, + const DestinationBuffer& destination, + decrypt_cb _hidl_cb) { + + if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) { + _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source decrypt buffer base not set"); + return Void(); + } + + if (destination.type == BufferType::SHARED_MEMORY) { + const SharedBuffer& dest = destination.nonsecureMemory; + if (mSharedBufferMap.find(dest.bufferId) == mSharedBufferMap.end()) { + _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "destination decrypt buffer base not set"); + return Void(); + } + } + + android::CryptoPlugin::Mode legacyMode; + switch(mode) { + case Mode::UNENCRYPTED: + legacyMode = android::CryptoPlugin::kMode_Unencrypted; + break; + case Mode::AES_CTR: + legacyMode = android::CryptoPlugin::kMode_AES_CTR; + break; + case Mode::AES_CBC_CTS: + legacyMode = android::CryptoPlugin::kMode_AES_WV; + break; + case Mode::AES_CBC: + legacyMode = android::CryptoPlugin::kMode_AES_CBC; + break; + } + android::CryptoPlugin::Pattern legacyPattern; + legacyPattern.mEncryptBlocks = pattern.encryptBlocks; + legacyPattern.mSkipBlocks = pattern.skipBlocks; + + android::CryptoPlugin::SubSample *legacySubSamples = + new android::CryptoPlugin::SubSample[subSamples.size()]; + + for (size_t i = 0; i < subSamples.size(); i++) { + legacySubSamples[i].mNumBytesOfClearData + = subSamples[i].numBytesOfClearData; + legacySubSamples[i].mNumBytesOfEncryptedData + = subSamples[i].numBytesOfEncryptedData; + } + + AString detailMessage; + sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId]; + + if (source.offset + offset + source.size > sourceBase->getSize()) { + _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size"); + return Void(); + } + + uint8_t *base = static_cast<uint8_t *> + (static_cast<void *>(sourceBase->getPointer())); + void *srcPtr = static_cast<void *>(base + source.offset + offset); + + void *destPtr = NULL; + if (destination.type == BufferType::SHARED_MEMORY) { + const SharedBuffer& destBuffer = destination.nonsecureMemory; + sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId]; + if (destBuffer.offset + destBuffer.size > destBase->getSize()) { + _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size"); + return Void(); + } + destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset); + } else if (destination.type == BufferType::NATIVE_HANDLE) { + native_handle_t *handle = const_cast<native_handle_t *>( + destination.secureMemory.getNativeHandle()); + destPtr = static_cast<void *>(handle); + } + ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(), + legacyMode, legacyPattern, srcPtr, legacySubSamples, + subSamples.size(), destPtr, &detailMessage); + + delete[] legacySubSamples; + + uint32_t status; + uint32_t bytesWritten; + + if (result >= 0) { + status = android::OK; + bytesWritten = result; + } else { + status = result; + bytesWritten = 0; + } + + _hidl_cb(toStatus(status), bytesWritten, detailMessage.c_str()); + return Void(); + } + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android
diff --git a/drm/1.0/default/CryptoPlugin.h b/drm/1.0/default/CryptoPlugin.h new file mode 100644 index 0000000..11cc2aa --- /dev/null +++ b/drm/1.0/default/CryptoPlugin.h
@@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H +#define ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H + +#include <android/hidl/memory/1.0/IMemory.h> +#include <android/hardware/drm/1.0/ICryptoPlugin.h> +#include <hidl/Status.h> +#include <media/hardware/CryptoAPI.h> + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::drm::V1_0::DestinationBuffer; +using ::android::hardware::drm::V1_0::ICryptoPlugin; +using ::android::hardware::drm::V1_0::Mode; +using ::android::hardware::drm::V1_0::Pattern; +using ::android::hardware::drm::V1_0::SubSample; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hidl::memory::V1_0::IMemory; +using ::android::sp; + +struct CryptoPlugin : public ICryptoPlugin { + CryptoPlugin(android::CryptoPlugin *plugin) : mLegacyPlugin(plugin) {} + + ~CryptoPlugin() {delete mLegacyPlugin;} + + // Methods from ::android::hardware::drm::V1_0::ICryptoPlugin + // follow. + + Return<bool> requiresSecureDecoderComponent(const hidl_string& mime) + override; + + Return<void> notifyResolution(uint32_t width, uint32_t height) override; + + Return<Status> setMediaDrmSession(const hidl_vec<uint8_t>& sessionId) + override; + + Return<void> setSharedBufferBase(const ::android::hardware::hidl_memory& base, + uint32_t bufferId) override; + + Return<void> decrypt(bool secure, const hidl_array<uint8_t, 16>& keyId, + const hidl_array<uint8_t, 16>& iv, Mode mode, const Pattern& pattern, + const hidl_vec<SubSample>& subSamples, const SharedBuffer& source, + uint64_t offset, const DestinationBuffer& destination, + decrypt_cb _hidl_cb) override; + +private: + android::CryptoPlugin *mLegacyPlugin; + std::map<uint32_t, sp<IMemory> > mSharedBufferMap; + + CryptoPlugin() = delete; + CryptoPlugin(const CryptoPlugin &) = delete; + void operator=(const CryptoPlugin &) = delete; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
diff --git a/drm/1.0/default/DrmFactory.cpp b/drm/1.0/default/DrmFactory.cpp new file mode 100644 index 0000000..9ec0ab7 --- /dev/null +++ b/drm/1.0/default/DrmFactory.cpp
@@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.drm@1.0-impl" + +#include "DrmFactory.h" +#include "DrmPlugin.h" +#include "TypeConvert.h" +#include <utils/Log.h> + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + + DrmFactory::DrmFactory() : + loader("/vendor/lib/mediadrm", "createDrmFactory") { + } + + // Methods from ::android::hardware::drm::V1_0::IDrmFactory follow. + Return<bool> DrmFactory::isCryptoSchemeSupported ( + const hidl_array<uint8_t, 16>& uuid) { + for (size_t i = 0; i < loader.factoryCount(); i++) { + if (loader.getFactory(i)->isCryptoSchemeSupported(uuid.data())) { + return true; + } + } + return false; + } + + Return<bool> DrmFactory::isContentTypeSupported ( + const hidl_string& mimeType) { + for (size_t i = 0; i < loader.factoryCount(); i++) { + if (loader.getFactory(i)->isContentTypeSupported(String8(mimeType.c_str()))) { + return true; + } + } + return false; + } + + Return<void> DrmFactory::createPlugin(const hidl_array<uint8_t, 16>& uuid, + const hidl_string& /* appPackageName */, createPlugin_cb _hidl_cb) { + + for (size_t i = 0; i < loader.factoryCount(); i++) { + if (loader.getFactory(i)->isCryptoSchemeSupported(uuid.data())) { + android::DrmPlugin *legacyPlugin = NULL; + status_t status = loader.getFactory(i)->createDrmPlugin( + uuid.data(), &legacyPlugin); + DrmPlugin *newPlugin = NULL; + if (legacyPlugin == NULL) { + ALOGE("Drm legacy HAL: failed to create drm plugin"); + } else { + newPlugin = new DrmPlugin(legacyPlugin); + } + _hidl_cb(toStatus(status), newPlugin); + return Void(); + } + } + _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, NULL); + return Void(); + } + + IDrmFactory* HIDL_FETCH_IDrmFactory(const char* /* name */) { + return new DrmFactory(); + } + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android
diff --git a/drm/1.0/default/DrmFactory.h b/drm/1.0/default/DrmFactory.h new file mode 100644 index 0000000..a008844 --- /dev/null +++ b/drm/1.0/default/DrmFactory.h
@@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_DRM_V1_0__DRMFACTORY_H +#define ANDROID_HARDWARE_DRM_V1_0__DRMFACTORY_H + +#include <android/hardware/drm/1.0/IDrmFactory.h> +#include <hidl/Status.h> +#include <media/drm/DrmAPI.h> +#include <media/PluginLoader.h> +#include <media/SharedLibrary.h> + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::drm::V1_0::IDrmFactory; +using ::android::hardware::drm::V1_0::IDrmPlugin; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +struct DrmFactory : public IDrmFactory { + DrmFactory(); + virtual ~DrmFactory() {} + + // Methods from ::android::hardware::drm::V1_0::IDrmFactory follow. + + Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>& uuid) + override; + + Return<bool> isContentTypeSupported(const hidl_string &mimeType) + override; + + Return<void> createPlugin(const hidl_array<uint8_t, 16>& uuid, + const hidl_string& appPackageName, createPlugin_cb _hidl_cb) override; + +private: + android::PluginLoader<android::DrmFactory> loader; + + DrmFactory(const DrmFactory &) = delete; + void operator=(const DrmFactory &) = delete; +}; + +extern "C" IDrmFactory* HIDL_FETCH_IDrmFactory(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_DRM_V1_0__DRMFACTORY_H
diff --git a/drm/1.0/default/DrmPlugin.cpp b/drm/1.0/default/DrmPlugin.cpp new file mode 100644 index 0000000..6f51e0e --- /dev/null +++ b/drm/1.0/default/DrmPlugin.cpp
@@ -0,0 +1,429 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.drm@1.0-impl" + +#include <utils/KeyedVector.h> +#include <utils/String8.h> + +#include "DrmPlugin.h" +#include "TypeConvert.h" + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + + // Methods from ::android::hardware::drm::V1_0::IDrmPlugin follow. + + Return<void> DrmPlugin::openSession(openSession_cb _hidl_cb) { + Vector<uint8_t> legacySessionId; + status_t status = mLegacyPlugin->openSession(legacySessionId); + _hidl_cb(toStatus(status), toHidlVec(legacySessionId)); + return Void(); + } + + Return<Status> DrmPlugin::closeSession(const hidl_vec<uint8_t>& sessionId) { + return toStatus(mLegacyPlugin->closeSession(toVector(sessionId))); + } + + Return<void> DrmPlugin::getKeyRequest(const hidl_vec<uint8_t>& scope, + const hidl_vec<uint8_t>& initData, const hidl_string& mimeType, + KeyType keyType, const hidl_vec<KeyValue>& optionalParameters, + getKeyRequest_cb _hidl_cb) { + + status_t status = android::OK; + + android::DrmPlugin::KeyType legacyKeyType; + switch(keyType) { + case KeyType::OFFLINE: + legacyKeyType = android::DrmPlugin::kKeyType_Offline; + break; + case KeyType::STREAMING: + legacyKeyType = android::DrmPlugin::kKeyType_Streaming; + break; + case KeyType::RELEASE: + legacyKeyType = android::DrmPlugin::kKeyType_Release; + break; + default: + status = android::BAD_VALUE; + break; + } + + Vector<uint8_t> legacyRequest; + KeyRequestType requestType = KeyRequestType::UNKNOWN; + String8 defaultUrl; + + if (status == android::OK) { + android::KeyedVector<String8, String8> legacyOptionalParameters; + for (size_t i = 0; i < optionalParameters.size(); i++) { + legacyOptionalParameters.add(String8(optionalParameters[i].key), + String8(optionalParameters[i].value)); + } + + android::DrmPlugin::KeyRequestType legacyRequestType = + android::DrmPlugin::kKeyRequestType_Unknown; + + status_t status = mLegacyPlugin->getKeyRequest(toVector(scope), + toVector(initData), String8(mimeType), legacyKeyType, + legacyOptionalParameters, legacyRequest, defaultUrl, + &legacyRequestType); + + switch(legacyRequestType) { + case android::DrmPlugin::kKeyRequestType_Initial: + requestType = KeyRequestType::INITIAL; + break; + case android::DrmPlugin::kKeyRequestType_Renewal: + requestType = KeyRequestType::RENEWAL; + break; + case android::DrmPlugin::kKeyRequestType_Release: + requestType = KeyRequestType::RELEASE; + break; + case android::DrmPlugin::kKeyRequestType_Unknown: + status = android::BAD_VALUE; + break; + } + } + _hidl_cb(toStatus(status), toHidlVec(legacyRequest), requestType, + defaultUrl.string()); + return Void(); + } + + Return<void> DrmPlugin::provideKeyResponse(const hidl_vec<uint8_t>& scope, + const hidl_vec<uint8_t>& response, provideKeyResponse_cb _hidl_cb) { + + Vector<uint8_t> keySetId; + status_t status = mLegacyPlugin->provideKeyResponse(toVector(scope), + toVector(response), keySetId); + _hidl_cb(toStatus(status), toHidlVec(keySetId)); + return Void(); + } + + Return<Status> DrmPlugin::removeKeys(const hidl_vec<uint8_t>& sessionId) { + return toStatus(mLegacyPlugin->removeKeys(toVector(sessionId))); + } + + Return<Status> DrmPlugin::restoreKeys(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keySetId) { + status_t legacyStatus = mLegacyPlugin->restoreKeys(toVector(sessionId), + toVector(keySetId)); + return toStatus(legacyStatus); + } + + Return<void> DrmPlugin::queryKeyStatus(const hidl_vec<uint8_t>& sessionId, + queryKeyStatus_cb _hidl_cb) { + + android::KeyedVector<String8, String8> legacyInfoMap; + status_t status = mLegacyPlugin->queryKeyStatus(toVector(sessionId), + legacyInfoMap); + + Vector<KeyValue> infoMapVec; + for (size_t i = 0; i < legacyInfoMap.size(); i++) { + KeyValue keyValuePair; + keyValuePair.key = String8(legacyInfoMap.keyAt(i)); + keyValuePair.value = String8(legacyInfoMap.valueAt(i)); + infoMapVec.push_back(keyValuePair); + } + _hidl_cb(toStatus(status), toHidlVec(infoMapVec)); + return Void(); + } + + Return<void> DrmPlugin::getProvisionRequest( + const hidl_string& certificateType, + const hidl_string& certificateAuthority, + getProvisionRequest_cb _hidl_cb) { + + Vector<uint8_t> legacyRequest; + String8 legacyDefaultUrl; + status_t status = mLegacyPlugin->getProvisionRequest( + String8(certificateType), String8(certificateAuthority), + legacyRequest, legacyDefaultUrl); + + _hidl_cb(toStatus(status), toHidlVec(legacyRequest), + hidl_string(legacyDefaultUrl)); + return Void(); + } + + Return<void> DrmPlugin::provideProvisionResponse( + const hidl_vec<uint8_t>& response, + provideProvisionResponse_cb _hidl_cb) { + + Vector<uint8_t> certificate; + Vector<uint8_t> wrappedKey; + + status_t legacyStatus = mLegacyPlugin->provideProvisionResponse( + toVector(response), certificate, wrappedKey); + + _hidl_cb(toStatus(legacyStatus), toHidlVec(certificate), + toHidlVec(wrappedKey)); + return Void(); + } + + Return<void> DrmPlugin::getSecureStops(getSecureStops_cb _hidl_cb) { + List<Vector<uint8_t> > legacySecureStops; + status_t status = mLegacyPlugin->getSecureStops(legacySecureStops); + + Vector<SecureStop> secureStopsVec; + List<Vector<uint8_t> >::iterator iter = legacySecureStops.begin(); + + while (iter != legacySecureStops.end()) { + SecureStop secureStop; + secureStop.opaqueData = toHidlVec(*iter++); + secureStopsVec.push_back(secureStop); + } + + _hidl_cb(toStatus(status), toHidlVec(secureStopsVec)); + return Void(); + } + + Return<void> DrmPlugin::getSecureStop(const hidl_vec<uint8_t>& secureStopId, + getSecureStop_cb _hidl_cb) { + + Vector<uint8_t> legacySecureStop; + status_t status = mLegacyPlugin->getSecureStop(toVector(secureStopId), + legacySecureStop); + + SecureStop secureStop; + secureStop.opaqueData = toHidlVec(legacySecureStop); + _hidl_cb(toStatus(status), secureStop); + return Void(); + } + + Return<Status> DrmPlugin::releaseAllSecureStops() { + return toStatus(mLegacyPlugin->releaseAllSecureStops()); + } + + Return<Status> DrmPlugin::releaseSecureStop( + const hidl_vec<uint8_t>& secureStopId) { + status_t legacyStatus = + mLegacyPlugin->releaseSecureStops(toVector(secureStopId)); + return toStatus(legacyStatus); + } + + Return<void> DrmPlugin::getPropertyString(const hidl_string& propertyName, + getPropertyString_cb _hidl_cb) { + String8 legacyValue; + status_t status = mLegacyPlugin->getPropertyString( + String8(propertyName), legacyValue); + _hidl_cb(toStatus(status), legacyValue.string()); + return Void(); + } + + Return<void> DrmPlugin::getPropertyByteArray(const hidl_string& propertyName, + getPropertyByteArray_cb _hidl_cb) { + Vector<uint8_t> legacyValue; + status_t status = mLegacyPlugin->getPropertyByteArray( + String8(propertyName), legacyValue); + _hidl_cb(toStatus(status), toHidlVec(legacyValue)); + return Void(); + } + + Return<Status> DrmPlugin::setPropertyString(const hidl_string& propertyName, + const hidl_string& value) { + status_t legacyStatus = + mLegacyPlugin->setPropertyString(String8(propertyName), + String8(value)); + return toStatus(legacyStatus); + } + + Return<Status> DrmPlugin::setPropertyByteArray( + const hidl_string& propertyName, const hidl_vec<uint8_t>& value) { + status_t legacyStatus = + mLegacyPlugin->setPropertyByteArray(String8(propertyName), + toVector(value)); + return toStatus(legacyStatus); + } + + Return<Status> DrmPlugin::setCipherAlgorithm( + const hidl_vec<uint8_t>& sessionId, const hidl_string& algorithm) { + status_t legacyStatus = + mLegacyPlugin->setCipherAlgorithm(toVector(sessionId), + String8(algorithm)); + return toStatus(legacyStatus); + } + + Return<Status> DrmPlugin::setMacAlgorithm( + const hidl_vec<uint8_t>& sessionId, const hidl_string& algorithm) { + status_t legacyStatus = + mLegacyPlugin->setMacAlgorithm(toVector(sessionId), + String8(algorithm)); + return toStatus(legacyStatus); + } + + Return<void> DrmPlugin::encrypt(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& input, + const hidl_vec<uint8_t>& iv, encrypt_cb _hidl_cb) { + + Vector<uint8_t> legacyOutput; + status_t status = mLegacyPlugin->encrypt(toVector(sessionId), + toVector(keyId), toVector(input), toVector(iv), legacyOutput); + _hidl_cb(toStatus(status), toHidlVec(legacyOutput)); + return Void(); + } + + Return<void> DrmPlugin::decrypt(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& input, + const hidl_vec<uint8_t>& iv, decrypt_cb _hidl_cb) { + + Vector<uint8_t> legacyOutput; + status_t status = mLegacyPlugin->decrypt(toVector(sessionId), + toVector(keyId), toVector(input), toVector(iv), legacyOutput); + _hidl_cb(toStatus(status), toHidlVec(legacyOutput)); + return Void(); + } + + Return<void> DrmPlugin::sign(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& message, + sign_cb _hidl_cb) { + Vector<uint8_t> legacySignature; + status_t status = mLegacyPlugin->sign(toVector(sessionId), + toVector(keyId), toVector(message), legacySignature); + _hidl_cb(toStatus(status), toHidlVec(legacySignature)); + return Void(); + } + + Return<void> DrmPlugin::verify(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& message, + const hidl_vec<uint8_t>& signature, verify_cb _hidl_cb) { + + bool match; + status_t status = mLegacyPlugin->verify(toVector(sessionId), + toVector(keyId), toVector(message), toVector(signature), + match); + _hidl_cb(toStatus(status), match); + return Void(); + } + + Return<void> DrmPlugin::signRSA(const hidl_vec<uint8_t>& sessionId, + const hidl_string& algorithm, const hidl_vec<uint8_t>& message, + const hidl_vec<uint8_t>& wrappedKey, signRSA_cb _hidl_cb) { + + Vector<uint8_t> legacySignature; + status_t status = mLegacyPlugin->signRSA(toVector(sessionId), + String8(algorithm), toVector(message), toVector(wrappedKey), + legacySignature); + _hidl_cb(toStatus(status), toHidlVec(legacySignature)); + return Void(); + } + + Return<void> DrmPlugin::setListener(const sp<IDrmPluginListener>& listener) { + mListener = listener; + mLegacyPlugin->setListener(listener == NULL ? NULL : this); + return Void(); + } + + Return<void> DrmPlugin::sendEvent(EventType eventType, + const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data) { + mListener->sendEvent(eventType, sessionId, data); + return Void(); + } + + Return<void> DrmPlugin::sendExpirationUpdate( + const hidl_vec<uint8_t>& sessionId, int64_t expiryTimeInMS) { + mListener->sendExpirationUpdate(sessionId, expiryTimeInMS); + return Void(); + } + + Return<void> DrmPlugin::sendKeysChange(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) { + mListener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey); + return Void(); + } + + + // Methods from android::DrmPluginListener + + void DrmPlugin::sendEvent(android::DrmPlugin::EventType legacyEventType, + int /*unused*/, Vector<uint8_t> const *sessionId, + Vector<uint8_t> const *data) { + + EventType eventType; + bool sendEvent = true; + switch(legacyEventType) { + case android::DrmPlugin::kDrmPluginEventProvisionRequired: + eventType = EventType::PROVISION_REQUIRED; + break; + case android::DrmPlugin::kDrmPluginEventKeyNeeded: + eventType = EventType::KEY_NEEDED; + break; + case android::DrmPlugin::kDrmPluginEventKeyExpired: + eventType = EventType::KEY_EXPIRED; + break; + case android::DrmPlugin::kDrmPluginEventVendorDefined: + eventType = EventType::VENDOR_DEFINED; + break; + case android::DrmPlugin::kDrmPluginEventSessionReclaimed: + eventType = EventType::SESSION_RECLAIMED; + break; + default: + sendEvent = false; + break; + } + if (sendEvent) { + Vector<uint8_t> emptyVector; + mListener->sendEvent(eventType, + toHidlVec(sessionId == NULL ? emptyVector: *sessionId), + toHidlVec(data == NULL ? emptyVector: *data)); + } + } + + void DrmPlugin::sendExpirationUpdate(Vector<uint8_t> const *sessionId, + int64_t expiryTimeInMS) { + mListener->sendExpirationUpdate(toHidlVec(*sessionId), expiryTimeInMS); + } + + void DrmPlugin::sendKeysChange(Vector<uint8_t> const *sessionId, + Vector<android::DrmPlugin::KeyStatus> const *legacyKeyStatusList, + bool hasNewUsableKey) { + + Vector<KeyStatus> keyStatusVec; + for (size_t i = 0; i < legacyKeyStatusList->size(); i++) { + const android::DrmPlugin::KeyStatus &legacyKeyStatus = + legacyKeyStatusList->itemAt(i); + + KeyStatus keyStatus; + + switch(legacyKeyStatus.mType) { + case android::DrmPlugin::kKeyStatusType_Usable: + keyStatus.type = KeyStatusType::USABLE; + break; + case android::DrmPlugin::kKeyStatusType_Expired: + keyStatus.type = KeyStatusType::EXPIRED; + break; + case android::DrmPlugin::kKeyStatusType_OutputNotAllowed: + keyStatus.type = KeyStatusType::OUTPUTNOTALLOWED; + break; + case android::DrmPlugin::kKeyStatusType_StatusPending: + keyStatus.type = KeyStatusType::STATUSPENDING; + break; + case android::DrmPlugin::kKeyStatusType_InternalError: + default: + keyStatus.type = KeyStatusType::INTERNALERROR; + break; + } + + keyStatus.keyId = toHidlVec(legacyKeyStatus.mKeyId); + keyStatusVec.push_back(keyStatus); + } + mListener->sendKeysChange(toHidlVec(*sessionId), + toHidlVec(keyStatusVec), hasNewUsableKey); + } + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android
diff --git a/drm/1.0/default/DrmPlugin.h b/drm/1.0/default/DrmPlugin.h new file mode 100644 index 0000000..dce6c0c --- /dev/null +++ b/drm/1.0/default/DrmPlugin.h
@@ -0,0 +1,169 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_DRM_V1_0__DRMPLUGIN_H +#define ANDROID_HARDWARE_DRM_V1_0__DRMPLUGIN_H + +#include <android/hardware/drm/1.0/IDrmPlugin.h> +#include <android/hardware/drm/1.0/IDrmPluginListener.h> +#include <hidl/Status.h> +#include <media/drm/DrmAPI.h> + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::drm::V1_0::EventType; +using ::android::hardware::drm::V1_0::IDrmPlugin; +using ::android::hardware::drm::V1_0::IDrmPluginListener; +using ::android::hardware::drm::V1_0::KeyRequestType; +using ::android::hardware::drm::V1_0::KeyStatus; +using ::android::hardware::drm::V1_0::KeyType; +using ::android::hardware::drm::V1_0::KeyValue; +using ::android::hardware::drm::V1_0::SecureStop; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +struct DrmPlugin : public IDrmPlugin, android::DrmPluginListener { + + DrmPlugin(android::DrmPlugin *plugin) : mLegacyPlugin(plugin) {} + ~DrmPlugin() {delete mLegacyPlugin;} + + // Methods from ::android::hardware::drm::V1_0::IDrmPlugin follow. + + Return<void> openSession(openSession_cb _hidl_cb) override; + + Return<Status> closeSession(const hidl_vec<uint8_t>& sessionId) override; + + Return<void> getKeyRequest(const hidl_vec<uint8_t>& scope, + const hidl_vec<uint8_t>& initData, const hidl_string& mimeType, + KeyType keyType, const hidl_vec<KeyValue>& optionalParameters, + getKeyRequest_cb _hidl_cb) override; + + Return<void> provideKeyResponse(const hidl_vec<uint8_t>& scope, + const hidl_vec<uint8_t>& response, provideKeyResponse_cb _hidl_cb) + override; + + Return<Status> removeKeys(const hidl_vec<uint8_t>& sessionId) override; + + Return<Status> restoreKeys(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keySetId) override; + + Return<void> queryKeyStatus(const hidl_vec<uint8_t>& sessionId, + queryKeyStatus_cb _hidl_cb) override; + + Return<void> getProvisionRequest(const hidl_string& certificateType, + const hidl_string& certificateAuthority, + getProvisionRequest_cb _hidl_cb) override; + + Return<void> provideProvisionResponse(const hidl_vec<uint8_t>& response, + provideProvisionResponse_cb _hidl_cb) override; + + Return<void> getSecureStops(getSecureStops_cb _hidl_cb) override; + + Return<void> getSecureStop(const hidl_vec<uint8_t>& secureStopId, + getSecureStop_cb _hidl_cb) override; + + Return<Status> releaseAllSecureStops() override; + + Return<Status> releaseSecureStop(const hidl_vec<uint8_t>& secureStopId) + override; + + Return<void> getPropertyString(const hidl_string& propertyName, + getPropertyString_cb _hidl_cb) override; + + Return<void> getPropertyByteArray(const hidl_string& propertyName, + getPropertyByteArray_cb _hidl_cb) override; + + Return<Status> setPropertyString(const hidl_string& propertyName, + const hidl_string& value) override; + + Return<Status> setPropertyByteArray(const hidl_string& propertyName, + const hidl_vec<uint8_t>& value) override; + + Return<Status> setCipherAlgorithm(const hidl_vec<uint8_t>& sessionId, + const hidl_string& algorithm) override; + + Return<Status> setMacAlgorithm(const hidl_vec<uint8_t>& sessionId, + const hidl_string& algorithm) override; + + Return<void> encrypt(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& input, + const hidl_vec<uint8_t>& iv, encrypt_cb _hidl_cb) override; + + Return<void> decrypt(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& input, + const hidl_vec<uint8_t>& iv, decrypt_cb _hidl_cb) override; + + Return<void> sign(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& message, + sign_cb _hidl_cb) override; + + Return<void> verify(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& message, + const hidl_vec<uint8_t>& signature, verify_cb _hidl_cb) override; + + Return<void> signRSA(const hidl_vec<uint8_t>& sessionId, + const hidl_string& algorithm, const hidl_vec<uint8_t>& message, + const hidl_vec<uint8_t>& wrappedkey, signRSA_cb _hidl_cb) override; + + Return<void> setListener(const sp<IDrmPluginListener>& listener) override; + + Return<void> sendEvent(EventType eventType, + const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data) + override; + + Return<void> sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId, + int64_t expiryTimeInMS) override; + + Return<void> sendKeysChange(const hidl_vec<uint8_t>& sessionId, + const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) + override; + + // Methods from android::DrmPluginListener follow + + virtual void sendEvent(android::DrmPlugin::EventType eventType, int extra, + Vector<uint8_t> const *sessionId, Vector<uint8_t> const *data); + + virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId, + int64_t expiryTimeInMS); + + virtual void sendKeysChange(Vector<uint8_t> const *sessionId, + Vector<android::DrmPlugin::KeyStatus> const *keyStatusList, + bool hasNewUsableKey); + +private: + android::DrmPlugin *mLegacyPlugin; + sp<IDrmPluginListener> mListener; + + DrmPlugin() = delete; + DrmPlugin(const DrmPlugin &) = delete; + void operator=(const DrmPlugin &) = delete; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_DRM_V1_0__DRMPLUGIN_H
diff --git a/drm/1.0/default/TypeConvert.cpp b/drm/1.0/default/TypeConvert.cpp new file mode 100644 index 0000000..ede2a38 --- /dev/null +++ b/drm/1.0/default/TypeConvert.cpp
@@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.drm@1.0-impl" + +#include "TypeConvert.h" + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + +Status toStatus(status_t legacyStatus) { + Status status; + switch(legacyStatus) { + case android::OK: + status = Status::OK; + break; + case android::ERROR_DRM_NO_LICENSE: + status = Status::ERROR_DRM_NO_LICENSE; + break; + case android::ERROR_DRM_LICENSE_EXPIRED: + status = Status::ERROR_DRM_LICENSE_EXPIRED; + break; + case android::ERROR_DRM_SESSION_NOT_OPENED: + status = Status::ERROR_DRM_SESSION_NOT_OPENED; + break; + case android::ERROR_DRM_CANNOT_HANDLE: + status = Status::ERROR_DRM_CANNOT_HANDLE; + break; + case android::ERROR_DRM_TAMPER_DETECTED: + status = Status::ERROR_DRM_INVALID_STATE; + break; + case android::BAD_VALUE: + status = Status::BAD_VALUE; + break; + case android::ERROR_DRM_NOT_PROVISIONED: + status = Status::ERROR_DRM_NOT_PROVISIONED; + break; + case android::ERROR_DRM_RESOURCE_BUSY: + status = Status::ERROR_DRM_RESOURCE_BUSY; + break; + case android::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION: + status = Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION; + break; + case android::ERROR_DRM_DEVICE_REVOKED: + status = Status::ERROR_DRM_DEVICE_REVOKED; + break; + default: + ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN", + legacyStatus); + status = Status::ERROR_DRM_UNKNOWN; + break; + } + return status; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android
diff --git a/drm/1.0/default/TypeConvert.h b/drm/1.0/default/TypeConvert.h new file mode 100644 index 0000000..107fda5 --- /dev/null +++ b/drm/1.0/default/TypeConvert.h
@@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_DRM_V1_0_TYPECONVERT +#define ANDROID_HARDWARE_DRM_V1_0_TYPECONVERT + +#include <android/hardware/drm/1.0/types.h> +#include <media/stagefright/MediaErrors.h> +#include <utils/Vector.h> + +namespace android { +namespace hardware { +namespace drm { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::hidl_vec; + +template<typename T> const hidl_vec<T> toHidlVec(const Vector<T> &Vector) { + hidl_vec<T> vec; + vec.setToExternal(const_cast<T *>(Vector.array()), Vector.size()); + return vec; +} + +template<typename T> hidl_vec<T> toHidlVec(Vector<T> &Vector) { + hidl_vec<T> vec; + vec.setToExternal(Vector.editArray(), Vector.size()); + return vec; +} + +template<typename T> const Vector<T> toVector(const hidl_vec<T> &vec) { + Vector<T> vector; + vector.appendArray(vec.data(), vec.size()); + return *const_cast<const Vector<T> *>(&vector); +} + +template<typename T> Vector<T> toVector(hidl_vec<T> &vec) { + Vector<T> vector; + vector.appendArray(vec.data(), vec.size()); + return vector; +} + +template<typename T, size_t SIZE> const Vector<T> toVector( + const hidl_array<T, SIZE> &array) { + Vector<T> vector; + vector.appendArray(array.data(), array.size()); + return vector; +} + +template<typename T, size_t SIZE> Vector<T> toVector( + hidl_array<T, SIZE> &array) { + Vector<T> vector; + vector.appendArray(array.data(), array.size()); + return vector; +} + +Status toStatus(status_t legacyStatus); + +} // namespace implementation +} // namespace V1_0 +} // namespace drm +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_DRM_V1_0_TYPECONVERT
diff --git a/drm/1.0/default/android.hardware.drm@1.0-service.rc b/drm/1.0/default/android.hardware.drm@1.0-service.rc new file mode 100644 index 0000000..e7beca3 --- /dev/null +++ b/drm/1.0/default/android.hardware.drm@1.0-service.rc
@@ -0,0 +1,6 @@ +service drm-hal-1-0 /vendor/bin/hw/android.hardware.drm@1.0-service + class hal + user media + group mediadrm drmrpc + ioprio rt 4 + writepid /dev/cpuset/foreground/tasks
diff --git a/drm/1.0/default/service.cpp b/drm/1.0/default/service.cpp new file mode 100644 index 0000000..d2507c4 --- /dev/null +++ b/drm/1.0/default/service.cpp
@@ -0,0 +1,37 @@ +/* + * Copyright 2016 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. + */ +#define LOG_TAG "android.hardware.drm@1.0-service" + +#include <1.0/default/CryptoFactory.h> +#include <1.0/default/DrmFactory.h> + +#include <hidl/HidlTransportSupport.h> +#include <hidl/LegacySupport.h> + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::registerPassthroughServiceImplementation; + +using android::hardware::drm::V1_0::ICryptoFactory; +using android::hardware::drm::V1_0::IDrmFactory; + +int main() { + ALOGD("android.hardware.drm@1.0-service starting..."); + configureRpcThreadpool(8, true /* callerWillJoin */); + registerPassthroughServiceImplementation<IDrmFactory>("drm"); + registerPassthroughServiceImplementation<ICryptoFactory>("crypto"); + joinRpcThreadpool(); +}
diff --git a/drm/1.0/types.hal b/drm/1.0/types.hal new file mode 100644 index 0000000..5273044 --- /dev/null +++ b/drm/1.0/types.hal
@@ -0,0 +1,342 @@ +/** + * Copyright (C) 2016 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.drm@1.0; + +enum Status : uint32_t { + /** + * The DRM plugin must return OK when an operation completes without any + * errors. + */ + OK, + + /** + * The DRM plugin must return ERROR_DRM_NO_LICENSE, when decryption is + * attempted and no license keys have been provided. + */ + ERROR_DRM_NO_LICENSE, + + /** + * ERROR_DRM_LICENSE_EXPIRED must be returned when an attempt is made + * to use a license and the keys in that license have expired. + */ + ERROR_DRM_LICENSE_EXPIRED, + + /** + * The DRM plugin must return ERROR_DRM_SESSION_NOT_OPENED when an + * attempt is made to use a session that has not been opened. + */ + ERROR_DRM_SESSION_NOT_OPENED, + + /** + * The DRM plugin must return ERROR_DRM_CANNOT_HANDLE when an unsupported + * data format or operation is attempted. + */ + ERROR_DRM_CANNOT_HANDLE, + + /** + * ERROR_DRM_INVALID_STATE must be returned when the device is in a state + * where it is not able to perform decryption. + */ + ERROR_DRM_INVALID_STATE, + + /** + * The DRM plugin must return BAD_VALUE whenever an illegal parameter is + * passed to one of the interface functions. + */ + BAD_VALUE, + + /** + * The DRM plugin must return ERROR_DRM_NOT_PROVISIONED from getKeyRequest, + * openSession or provideKeyResponse when the device has not yet been + * provisioned. + */ + ERROR_DRM_NOT_PROVISIONED, + + /** + * ERROR_DRM_RESOURCE_BUSY must be returned when resources, such as drm + * sessions or secure buffers are not available to perform a requested + * operation because they are already in use. + */ + ERROR_DRM_RESOURCE_BUSY, + + /** + * The DRM Plugin must return ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION + * when the output protection level enabled on the device is not + * sufficient to meet the requirements in the license policy. HDCP is an + * example of a form of output protection. + */ + ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION, + + /** + * The DRM Plugin must return ERROR_DRM_DEVICE_REVOKED from + * provideProvisionResponse and provideKeyResponse if the response indicates + * that the device has been revoked. Device revocation means that the device + * is no longer permitted to play content. + */ + ERROR_DRM_DEVICE_REVOKED, + + /** + * ERROR_DRM_UNKNOWN must be returned when a fatal failure occurs and no + * other defined error is appropriate. + */ + ERROR_DRM_UNKNOWN, +}; + + +/** + * EventType enumerates the events that can be delivered by sendEvent + */ +enum EventType : uint32_t { + /** + * This event type indicates that the app needs to request a certificate + * from the provisioning server. The request message data is obtained using + * getProvisionRequest(). + */ + PROVISION_REQUIRED, + + /** + * This event type indicates that the app needs to request keys from a + * license server. The request message data is obtained using getKeyRequest. + */ + KEY_NEEDED, + + /** + * This event type indicates that the licensed usage duration for keys in a + * session has expired. The keys are no longer valid. + */ + KEY_EXPIRED, + + /** + * This event may indicate some specific vendor-defined condition, see your + * DRM provider documentation for details. + */ + VENDOR_DEFINED, + + /** + * This event indicates that a session opened by the app has been reclaimed + * by the resource manager. + */ + SESSION_RECLAIMED, +}; + +enum KeyType : uint32_t { + /** + * Drm keys can be for offline content or for online streaming. + * Offline keys are persisted on the device and may be used when the device + * is disconnected from the network. + */ + OFFLINE, + + /** + * Keys for streaming are not persisted and require the device to be + * connected to the network for periodic renewal. + */ + STREAMING, + + /** + * The Release type is used to request that offline keys be no longer + * restricted to offline use. + */ + RELEASE, +}; + +/** + * Enumerate KeyRequestTypes to allow an app to determine the type of a key + * request returned from getKeyRequest. + */ +enum KeyRequestType : uint32_t { + /** + * Key request type is for an initial license request + */ + INITIAL, + + /** + * Key request type is for license renewal. Renewal requests are used + * to extend the validity period for streaming keys. + */ + RENEWAL, + + /** + * Key request type is a release. A key release causes offline keys + * to become available for streaming. + */ + RELEASE, + + /** + * Key request type is unknown due to some error condition. + */ + UNKNOWN, +}; + +/** + * Enumerate KeyStatusTypes which indicate the state of a key + */ +enum KeyStatusType : uint32_t { + /** + * The key is currently usable to decrypt media data. + */ + USABLE, + + /** + * The key is no longer usable to decrypt media data because its expiration + * time has passed. + */ + EXPIRED, + + /** + * The key is not currently usable to decrypt media data because its output + * requirements cannot currently be met. + */ + OUTPUTNOTALLOWED, + + /** + * The status of the key is not yet known and is being determined. + */ + STATUSPENDING, + + /** + * The key is not currently usable to decrypt media data because of an + * internal error in processing unrelated to input parameters. + */ + INTERNALERROR, +}; + +typedef vec<uint8_t> SessionId; + +/** + * Used by sendKeysChange to report the usability status of each key to the + * app. + */ +struct KeyStatus +{ + vec<uint8_t> keyId; + KeyStatusType type; +}; + +/** + * Simulates a KeyedVector<String8, String8> + */ +struct KeyValue { + string key; + string value; +}; + +typedef vec<KeyValue> KeyedVector; + +/** + * Encapsulates a secure stop opaque object + */ +struct SecureStop { + vec<uint8_t> opaqueData; +}; + +typedef vec<uint8_t> SecureStopId; + + +/** + * Enumerate the supported crypto modes + */ +enum Mode : uint32_t { + UNENCRYPTED = 0, // Samples are unencrypted + AES_CTR = 1, // Samples are encrypted with AES CTR mode + AES_CBC_CTS = 2, // Samples are encrypted with AES CBC CTS mode + AES_CBC = 3, // Samples are encrypted with AES CBC mode +}; + +/** + * A subsample consists of some number of bytes of clear (unencrypted) + * data followed by a number of bytes of encrypted data. + */ +struct SubSample { + uint32_t numBytesOfClearData; + uint32_t numBytesOfEncryptedData; +}; + +/** + * A crypto Pattern is a repeating sequence of encrypted and clear blocks + * occuring within the bytes indicated by mNumBytesOfEncryptedDatad bytes + * of a subsample. Patterns are used to reduce the CPU overhead of + * decrypting samples. As an example, HLS uses 1:9 patterns where every + * 10th block is encrypted. + */ +struct Pattern { + /** + * The number of blocks to be encrypted in the pattern. If zero, + * pattern encryption is inoperative. + */ + uint32_t encryptBlocks; + + /** + * The number of blocks to be skipped (left clear) in the pattern. If + * zero, pattern encryption is inoperative. + */ + uint32_t skipBlocks; +}; + +enum BufferType : uint32_t { + SHARED_MEMORY = 0, + NATIVE_HANDLE = 1, +}; + +/** + * SharedBuffer describes a decrypt buffer which is defined by a bufferId, an + * offset and a size. The offset is relative to the shared memory base for the + * memory region identified by bufferId, which is established by + * setSharedMemoryBase(). + */ +struct SharedBuffer { + /** + * The unique buffer identifier + */ + uint32_t bufferId; + + /** + * The offset from the shared memory base + */ + uint64_t offset; + + /** + * The size of the shared buffer in bytes + */ + uint64_t size; +}; + + +/** + * A decrypt destination buffer can be either normal user-space shared + * memory for the non-secure decrypt case, or it can be a secure buffer + * which is referenced by a native-handle. The native handle is allocated + * by the vendor's buffer allocator. + */ +struct DestinationBuffer { + /** + * The type of the buffer + */ + BufferType type; + + /** + * If type == SHARED_MEMORY, the decrypted data must be written + * to user-space non-secure shared memory. + */ + SharedBuffer nonsecureMemory; + + /** + * If type == NATIVE_HANDLE, the decrypted data must be written + * to secure memory referenced by the vendor's buffer allocator. + */ + handle secureMemory; +};
diff --git a/drm/Android.bp b/drm/Android.bp new file mode 100644 index 0000000..bbb3e4b --- /dev/null +++ b/drm/Android.bp
@@ -0,0 +1,4 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", +]
diff --git a/dumpstate/1.0/Android.bp b/dumpstate/1.0/Android.bp new file mode 100644 index 0000000..1b473bc --- /dev/null +++ b/dumpstate/1.0/Android.bp
@@ -0,0 +1,59 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.dumpstate@1.0_hal", + srcs: [ + "IDumpstateDevice.hal", + ], +} + +genrule { + name: "android.hardware.dumpstate@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.dumpstate@1.0", + srcs: [ + ":android.hardware.dumpstate@1.0_hal", + ], + out: [ + "android/hardware/dumpstate/1.0/DumpstateDeviceAll.cpp", + ], +} + +genrule { + name: "android.hardware.dumpstate@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.dumpstate@1.0", + srcs: [ + ":android.hardware.dumpstate@1.0_hal", + ], + out: [ + "android/hardware/dumpstate/1.0/IDumpstateDevice.h", + "android/hardware/dumpstate/1.0/IHwDumpstateDevice.h", + "android/hardware/dumpstate/1.0/BnHwDumpstateDevice.h", + "android/hardware/dumpstate/1.0/BpHwDumpstateDevice.h", + "android/hardware/dumpstate/1.0/BsDumpstateDevice.h", + ], +} + +cc_library_shared { + name: "android.hardware.dumpstate@1.0", + generated_sources: ["android.hardware.dumpstate@1.0_genc++"], + generated_headers: ["android.hardware.dumpstate@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.dumpstate@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/dumpstate/1.0/IDumpstateDevice.hal b/dumpstate/1.0/IDumpstateDevice.hal new file mode 100644 index 0000000..fec3eb4 --- /dev/null +++ b/dumpstate/1.0/IDumpstateDevice.hal
@@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016 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.dumpstate@1.0; + +interface IDumpstateDevice { + /* + * Dumps device-specific state into the given file descriptor. + */ + dumpstateBoard(handle h); +};
diff --git a/dumpstate/1.0/default/Android.mk b/dumpstate/1.0/default/Android.mk new file mode 100644 index 0000000..0b07f49 --- /dev/null +++ b/dumpstate/1.0/default/Android.mk
@@ -0,0 +1,22 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.dumpstate@1.0-service +LOCAL_INIT_RC := android.hardware.dumpstate@1.0-service.rc +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_SRC_FILES := \ + DumpstateDevice.cpp \ + service.cpp + +LOCAL_SHARED_LIBRARIES := \ + android.hardware.dumpstate@1.0 \ + libbase \ + libcutils \ + libdumpstateutil \ + libhidlbase \ + libhidltransport \ + liblog \ + libutils + +include $(BUILD_EXECUTABLE)
diff --git a/dumpstate/1.0/default/DumpstateDevice.cpp b/dumpstate/1.0/default/DumpstateDevice.cpp new file mode 100644 index 0000000..8000d85 --- /dev/null +++ b/dumpstate/1.0/default/DumpstateDevice.cpp
@@ -0,0 +1,65 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "dumpstate" + +#include "DumpstateDevice.h" + +#include <log/log.h> + +#include "DumpstateUtil.h" + +using android::os::dumpstate::DumpFileToFd; +using android::os::dumpstate::RunCommandToFd; + +namespace android { +namespace hardware { +namespace dumpstate { +namespace V1_0 { +namespace implementation { + +// Methods from ::android::hardware::dumpstate::V1_0::IDumpstateDevice follow. +Return<void> DumpstateDevice::dumpstateBoard(const hidl_handle& handle) { + // NOTE: this is just an example on how to use the DumpstateUtil.h functions to implement + // this interface - since HIDL_FETCH_IDumpstateDevice() is not defined, this function will never + // be called by dumpstate. + + if (handle->numFds < 1) { + ALOGE("no FDs\n"); + return Void(); + } + + int fd = handle->data[0]; + if (fd < 0) { + ALOGE("invalid FD: %d\n", handle->data[0]); + return Void(); + } + ALOGD("DumpstateDevice::dumpstateBoard() FD: %d\n", fd); + ALOGI("Dumpstate HIDL not provided by device\n"); + dprintf(fd, "Dumpstate HIDL not provided by device; providing bogus data.\n"); + + // Shows some examples on how to use the libdumpstateutil API. + RunCommandToFd(fd, "DATE", {"/system/bin/date"}); + DumpFileToFd(fd, "HOSTS", "/system/etc/hosts"); + + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace dumpstate +} // namespace hardware +} // namespace android
diff --git a/dumpstate/1.0/default/DumpstateDevice.h b/dumpstate/1.0/default/DumpstateDevice.h new file mode 100644 index 0000000..f8585f5 --- /dev/null +++ b/dumpstate/1.0/default/DumpstateDevice.h
@@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_DUMPSTATE_V1_0_DUMPSTATEDEVICE_H +#define ANDROID_HARDWARE_DUMPSTATE_V1_0_DUMPSTATEDEVICE_H + +#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace dumpstate { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::dumpstate::V1_0::IDumpstateDevice; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +struct DumpstateDevice : public IDumpstateDevice { + // Methods from ::android::hardware::dumpstate::V1_0::IDumpstateDevice follow. + Return<void> dumpstateBoard(const hidl_handle& h) override; + +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace dumpstate +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_DUMPSTATE_V1_0_DUMPSTATEDEVICE_H
diff --git a/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc b/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc new file mode 100644 index 0000000..0f27248 --- /dev/null +++ b/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
@@ -0,0 +1,4 @@ +service dumpstate-1-0 /vendor/bin/hw/android.hardware.dumpstate@1.0-service + class hal + user system + group system
diff --git a/dumpstate/1.0/default/service.cpp b/dumpstate/1.0/default/service.cpp new file mode 100644 index 0000000..85bea12 --- /dev/null +++ b/dumpstate/1.0/default/service.cpp
@@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.dumpstate@1.0-service" + +#include <hidl/HidlSupport.h> +#include <hidl/HidlTransportSupport.h> + +#include "DumpstateDevice.h" + +using ::android::hardware::configureRpcThreadpool; +using ::android::hardware::dumpstate::V1_0::IDumpstateDevice; +using ::android::hardware::dumpstate::V1_0::implementation::DumpstateDevice; +using ::android::hardware::joinRpcThreadpool; +using ::android::sp; + +int main (int /* argc */, char * /* argv */ []) { + sp<IDumpstateDevice> dumpstate = new DumpstateDevice; + configureRpcThreadpool(1, true); + dumpstate->registerAsService(); + joinRpcThreadpool(); +}
diff --git a/dumpstate/Android.bp b/dumpstate/Android.bp new file mode 100644 index 0000000..bbb3e4b --- /dev/null +++ b/dumpstate/Android.bp
@@ -0,0 +1,4 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", +]
diff --git a/gatekeeper/1.0/Android.bp b/gatekeeper/1.0/Android.bp new file mode 100644 index 0000000..2697e4c --- /dev/null +++ b/gatekeeper/1.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.gatekeeper@1.0_hal", + srcs: [ + "types.hal", + "IGatekeeper.hal", + ], +} + +genrule { + name: "android.hardware.gatekeeper@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.gatekeeper@1.0", + srcs: [ + ":android.hardware.gatekeeper@1.0_hal", + ], + out: [ + "android/hardware/gatekeeper/1.0/types.cpp", + "android/hardware/gatekeeper/1.0/GatekeeperAll.cpp", + ], +} + +genrule { + name: "android.hardware.gatekeeper@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.gatekeeper@1.0", + srcs: [ + ":android.hardware.gatekeeper@1.0_hal", + ], + out: [ + "android/hardware/gatekeeper/1.0/types.h", + "android/hardware/gatekeeper/1.0/IGatekeeper.h", + "android/hardware/gatekeeper/1.0/IHwGatekeeper.h", + "android/hardware/gatekeeper/1.0/BnHwGatekeeper.h", + "android/hardware/gatekeeper/1.0/BpHwGatekeeper.h", + "android/hardware/gatekeeper/1.0/BsGatekeeper.h", + ], +} + +cc_library_shared { + name: "android.hardware.gatekeeper@1.0", + generated_sources: ["android.hardware.gatekeeper@1.0_genc++"], + generated_headers: ["android.hardware.gatekeeper@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.gatekeeper@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/gatekeeper/1.0/Android.mk b/gatekeeper/1.0/Android.mk new file mode 100644 index 0000000..70206ff --- /dev/null +++ b/gatekeeper/1.0/Android.mk
@@ -0,0 +1,156 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.gatekeeper@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (GatekeeperResponse) +# +GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/GatekeeperResponse.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gatekeeper@1.0::types.GatekeeperResponse + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (GatekeeperStatusCode) +# +GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/GatekeeperStatusCode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gatekeeper@1.0::types.GatekeeperStatusCode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGatekeeper.hal +# +GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/IGatekeeper.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGatekeeper.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gatekeeper@1.0::IGatekeeper + +$(GEN): $(LOCAL_PATH)/IGatekeeper.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.gatekeeper@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (GatekeeperResponse) +# +GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/GatekeeperResponse.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gatekeeper@1.0::types.GatekeeperResponse + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (GatekeeperStatusCode) +# +GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/GatekeeperStatusCode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gatekeeper@1.0::types.GatekeeperStatusCode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGatekeeper.hal +# +GEN := $(intermediates)/android/hardware/gatekeeper/V1_0/IGatekeeper.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGatekeeper.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gatekeeper@1.0::IGatekeeper + +$(GEN): $(LOCAL_PATH)/IGatekeeper.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/gatekeeper/1.0/IGatekeeper.hal b/gatekeeper/1.0/IGatekeeper.hal new file mode 100644 index 0000000..c193477 --- /dev/null +++ b/gatekeeper/1.0/IGatekeeper.hal
@@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016 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.gatekeeper@1.0; + +interface IGatekeeper { + +/** + * Enrolls desiredPassword, which may be derived from a user selected pin + * or password, with the private key used only for enrolling authentication + * factor data. + * + * If there was already a password enrolled, current password handle must be + * passed in currentPasswordHandle, and current password must be passed in + * currentPassword. Valid currentPassword must verify() against + * currentPasswordHandle. + * + * @param uid The Android user identifier + * + * @param currentPasswordHandle The currently enrolled password handle the user + * wants to replace. May be empty only if there's no currently enrolled + * password. Otherwise must be non-empty. + * + * @param currentPassword The user's current password in plain text. + * it MUST verify against current_password_handle if the latter is not-empty + * + * @param desiredPassword The new password the user wishes to enroll in + * plaintext. + * + * @return response + * On success, data buffer must contain the new password handle referencing + * the password provided in desiredPassword. + * This buffer can be used on subsequent calls to enroll or + * verify. On error, this buffer must be empty. + * response.code must always contain operation completion status. + * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on + * failure. It must return STATUS_OK on success. + * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero. + */ +enroll(uint32_t uid, + vec<uint8_t> currentPasswordHandle, + vec<uint8_t> currentPassword, + vec<uint8_t> desiredPassword) + generates (GatekeeperResponse response); + +/** + * Verifies that providedPassword matches enrolledPasswordHandle. + * + * Implementations of this module may retain the result of this call + * to attest to the recency of authentication. + * + * On success, returns verification token in response.data, which shall be + * usable to attest password verification to other trusted services. + * + * @param uid The Android user identifier + * + * @param challenge An optional challenge to authenticate against, or 0. + * Used when a separate authenticator requests password verification, + * or for transactional password authentication. + * + * @param enrolledPasswordHandle The currently enrolled password handle that + * user wishes to verify against. Must be non-empty. + * + * @param providedPassword The plaintext password to be verified against the + * enrolledPasswordHandle + * + * @return response + * On success, a non-empty data buffer containing the + * authentication token resulting from this verification is returned. + * On error, data buffer must be empty. + * response.code must always contain operation completion status. + * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on + * failure. It must return STATUS_OK on success. + * If password re-enrollment is necessary, it must return STATUS_REENROLL. + * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero. + */ +verify(uint32_t uid, uint64_t challenge, + vec<uint8_t> enrolledPasswordHandle, + vec<uint8_t> providedPassword) + generates (GatekeeperResponse response); + +/* + * Deletes the enrolledPasswordHandle associated with the uid. Once deleted + * the user cannot be verified anymore. + * This is an optional method. + * + * @param uid The Android user identifier + * + * @return response + * response.code must always contain operation completion status. + * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on + * failure. It must return STATUS_OK on success. + * If not implemented, it must return ERROR_NOT_IMPLEMENTED. + * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero. + */ +deleteUser(uint32_t uid) generates (GatekeeperResponse response); + +/* + * Deletes all the enrolled_password_handles for all uid's. Once called, + * no users must be enrolled on the device. + * This is an optional method. + * + * @return response + * response.code must always contain operation completion status. + * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on + * failure. It must return STATUS_OK on success. + * If not implemented, it must return ERROR_NOT_IMPLEMENTED. + * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero. + */ +deleteAllUsers() generates (GatekeeperResponse response); +};
diff --git a/gatekeeper/1.0/default/Android.mk b/gatekeeper/1.0/default/Android.mk new file mode 100644 index 0000000..d084535 --- /dev/null +++ b/gatekeeper/1.0/default/Android.mk
@@ -0,0 +1,40 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.gatekeeper@1.0-impl + +LOCAL_SRC_FILES := \ + Gatekeeper.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + android.hardware.gatekeeper@1.0 \ + libhardware \ + libhidlbase \ + libhidltransport \ + libutils \ + liblog \ + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.gatekeeper@1.0-service +LOCAL_INIT_RC := android.hardware.gatekeeper@1.0-service.rc + +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + android.hardware.gatekeeper@1.0 \ + libhardware \ + libhidlbase \ + libhidltransport \ + libutils \ + liblog \ + +include $(BUILD_EXECUTABLE)
diff --git a/gatekeeper/1.0/default/Gatekeeper.cpp b/gatekeeper/1.0/default/Gatekeeper.cpp new file mode 100644 index 0000000..dce06e6 --- /dev/null +++ b/gatekeeper/1.0/default/Gatekeeper.cpp
@@ -0,0 +1,165 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.gatekeeper@1.0-service" + +#include <dlfcn.h> + +#include <log/log.h> + +#include "Gatekeeper.h" + +namespace android { +namespace hardware { +namespace gatekeeper { +namespace V1_0 { +namespace implementation { + +Gatekeeper::Gatekeeper() +{ + int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module); + device = NULL; + + if (!ret) { + ret = gatekeeper_open(module, &device); + } + if (ret < 0) { + LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL"); + } +} + +Gatekeeper::~Gatekeeper() +{ + if (device != nullptr) { + int ret = gatekeeper_close(device); + if (ret < 0) { + ALOGE("Unable to close GateKeeper HAL"); + } + } + dlclose(module->dso); +} + +// Methods from ::android::hardware::gatekeeper::V1_0::IGatekeeper follow. +Return<void> Gatekeeper::enroll(uint32_t uid, + const hidl_vec<uint8_t>& currentPasswordHandle, + const hidl_vec<uint8_t>& currentPassword, + const hidl_vec<uint8_t>& desiredPassword, + enroll_cb cb) +{ + GatekeeperResponse rsp; + uint8_t *enrolled_password_handle = nullptr; + uint32_t enrolled_password_handle_length = 0; + + int ret = device->enroll(device, uid, + currentPasswordHandle.data(), currentPasswordHandle.size(), + currentPassword.data(), currentPassword.size(), + desiredPassword.data(), desiredPassword.size(), + &enrolled_password_handle, &enrolled_password_handle_length); + if (!ret) { + rsp.data.setToExternal(enrolled_password_handle, + enrolled_password_handle_length, + true); + rsp.code = GatekeeperStatusCode::STATUS_OK; + } else if (ret > 0) { + rsp.timeout = ret; + rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT; + } else { + rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE; + } + cb(rsp); + return Void(); +} + +Return<void> Gatekeeper::verify(uint32_t uid, + uint64_t challenge, + const hidl_vec<uint8_t>& enrolledPasswordHandle, + const hidl_vec<uint8_t>& providedPassword, + verify_cb cb) +{ + GatekeeperResponse rsp; + uint8_t *auth_token = nullptr; + uint32_t auth_token_length = 0; + bool request_reenroll = false; + + int ret = device->verify(device, uid, challenge, + enrolledPasswordHandle.data(), enrolledPasswordHandle.size(), + providedPassword.data(), providedPassword.size(), + &auth_token, &auth_token_length, + &request_reenroll); + if (!ret) { + rsp.data.setToExternal(auth_token, auth_token_length, true); + if (request_reenroll) { + rsp.code = GatekeeperStatusCode::STATUS_REENROLL; + } else { + rsp.code = GatekeeperStatusCode::STATUS_OK; + } + } else if (ret > 0) { + rsp.timeout = ret; + rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT; + } else { + rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE; + } + cb(rsp); + return Void(); +} + +Return<void> Gatekeeper::deleteUser(uint32_t uid, deleteUser_cb cb) { + GatekeeperResponse rsp; + + if (device->delete_user != nullptr) { + int ret = device->delete_user(device, uid); + if (!ret) { + rsp.code = GatekeeperStatusCode::STATUS_OK; + } else if (ret > 0) { + rsp.timeout = ret; + rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT; + } else { + rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE; + } + } else { + rsp.code = GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED; + } + cb(rsp); + return Void(); +} + +Return<void> Gatekeeper::deleteAllUsers(deleteAllUsers_cb cb) { + GatekeeperResponse rsp; + if (device->delete_all_users != nullptr) { + int ret = device->delete_all_users(device); + if (!ret) { + rsp.code = GatekeeperStatusCode::STATUS_OK; + } else if (ret > 0) { + rsp.timeout = ret; + rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT; + } else { + rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE; + } + } else { + rsp.code = GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED; + } + cb(rsp); + return Void(); +} + +IGatekeeper* HIDL_FETCH_IGatekeeper(const char* /* name */) { + return new Gatekeeper(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gatekeeper +} // namespace hardware +} // namespace android
diff --git a/gatekeeper/1.0/default/Gatekeeper.h b/gatekeeper/1.0/default/Gatekeeper.h new file mode 100644 index 0000000..4cc01f6 --- /dev/null +++ b/gatekeeper/1.0/default/Gatekeeper.h
@@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_GATEKEEPER_V1_0_GATEKEEPER_H +#define ANDROID_HARDWARE_GATEKEEPER_V1_0_GATEKEEPER_H + +#include <android/hardware/gatekeeper/1.0/IGatekeeper.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> + +#include <hardware/hardware.h> +#include <hardware/gatekeeper.h> + +namespace android { +namespace hardware { +namespace gatekeeper { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gatekeeper::V1_0::GatekeeperResponse; +using ::android::hardware::gatekeeper::V1_0::IGatekeeper; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +class Gatekeeper : public IGatekeeper { +public: + Gatekeeper(); + ~Gatekeeper(); + + // Methods from ::android::hardware::gatekeeper::V1_0::IGatekeeper follow. + Return<void> enroll(uint32_t uid, + const hidl_vec<uint8_t>& currentPasswordHandle, + const hidl_vec<uint8_t>& currentPassword, + const hidl_vec<uint8_t>& desiredPassword, + enroll_cb _hidl_cb) override; + Return<void> verify(uint32_t uid, + uint64_t challenge, + const hidl_vec<uint8_t>& enrolledPasswordHandle, + const hidl_vec<uint8_t>& providedPassword, + verify_cb _hidl_cb) override; + Return<void> deleteUser(uint32_t uid, deleteUser_cb _hidl_cb) override; + Return<void> deleteAllUsers(deleteAllUsers_cb _hidl_cb) override; +private: + gatekeeper_device_t *device; + const hw_module_t *module; +}; + +extern "C" IGatekeeper* HIDL_FETCH_IGatekeeper(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace gatekeeper +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GATEKEEPER_V1_0_GATEKEEPER_H
diff --git a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc new file mode 100644 index 0000000..d3f5e9d --- /dev/null +++ b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
@@ -0,0 +1,4 @@ +service gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service + class hal + user system + group system
diff --git a/gatekeeper/1.0/default/service.cpp b/gatekeeper/1.0/default/service.cpp new file mode 100644 index 0000000..5cbdafb --- /dev/null +++ b/gatekeeper/1.0/default/service.cpp
@@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.gatekeeper@1.0-service" + +#include <android/hardware/gatekeeper/1.0/IGatekeeper.h> + +#include <hidl/LegacySupport.h> + +// Generated HIDL files +using android::hardware::gatekeeper::V1_0::IGatekeeper; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IGatekeeper>(); +}
diff --git a/gatekeeper/1.0/types.hal b/gatekeeper/1.0/types.hal new file mode 100644 index 0000000..8c184ee --- /dev/null +++ b/gatekeeper/1.0/types.hal
@@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 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.gatekeeper@1.0; + +/** + * Gatekeeper response codes; success >= 0; error < 0 + */ +enum GatekeeperStatusCode : int32_t { + STATUS_REENROLL = 1, // success, but upper layers should re-enroll + // the verified password due to a version change + STATUS_OK = 0, // operation is successful + ERROR_GENERAL_FAILURE = -1, // operation failed + ERROR_RETRY_TIMEOUT = -2, // operation should be retried after timeout + ERROR_NOT_IMPLEMENTED = -3, // operation is not implemented +}; + +/** + * Gatekeeper response to any/all requests has this structure as mandatory part + */ +struct GatekeeperResponse { + /* request completion status */ + GatekeeperStatusCode code; + /* retry timeout in ms, if code == ERROR_RETRY_TIMEOUT + * otherwise unused (0) + */ + uint32_t timeout; + /* optional crypto blob */ + vec<uint8_t> data; +};
diff --git a/gatekeeper/1.0/vts/functional/Android.bp b/gatekeeper/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..70cb615 --- /dev/null +++ b/gatekeeper/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalGatekeeperV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalGatekeeperV1_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.gatekeeper@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ] +}
diff --git a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp new file mode 100644 index 0000000..391dea0 --- /dev/null +++ b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
@@ -0,0 +1,438 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "gatekeeper_hidl_hal_test" + +#include <algorithm> +#include <cmath> +#include <string> +#include <vector> + +#include <inttypes.h> +#include <unistd.h> + +#include <hardware/hw_auth_token.h> + +#include <android/log.h> +#include <android/hardware/gatekeeper/1.0/IGatekeeper.h> +#include <android/hardware/gatekeeper/1.0/types.h> + +#include <VtsHalHidlTargetTestBase.h> + +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::gatekeeper::V1_0::IGatekeeper; +using ::android::hardware::gatekeeper::V1_0::GatekeeperResponse; +using ::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +struct GatekeeperRequest { + uint32_t uid; + uint64_t challenge; + hidl_vec<uint8_t> curPwdHandle; + hidl_vec<uint8_t> curPwd; + hidl_vec<uint8_t> newPwd; + GatekeeperRequest() : uid(0), challenge(0) {} +}; + +// ASSERT_* macros generate return "void" internally +// we have to use EXPECT_* if we return anything but "void" +static const hw_auth_token_t *toAuthToken(GatekeeperResponse &rsp) { + const hw_auth_token_t *auth_token = + reinterpret_cast<hw_auth_token_t *>(rsp.data.data()); + const size_t auth_token_size = rsp.data.size(); + + EXPECT_NE(nullptr, auth_token); + EXPECT_EQ(sizeof(hw_auth_token_t), auth_token_size); + + if (auth_token != nullptr && auth_token_size >= sizeof(*auth_token)) { + // these are in network order: translate to host + uint32_t auth_type = ntohl(auth_token->authenticator_type); + uint64_t auth_tstamp = ntohq(auth_token->timestamp); + + EXPECT_EQ(HW_AUTH_PASSWORD, auth_type); + EXPECT_NE(UINT64_C(~0), auth_tstamp); + EXPECT_EQ(HW_AUTH_TOKEN_VERSION, auth_token->version); + // EXPECT_NE(UINT64_C(0), auth_token->authenticator_id); + ALOGI("Authenticator ID: %016" PRIX64, auth_token->authenticator_id); + EXPECT_NE(UINT32_C(0), auth_token->user_id); + } + return auth_token; +} + +// The main test class for Gatekeeper HIDL HAL. +class GatekeeperHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + void setUid(uint32_t uid) { uid_ = uid; } + + void doEnroll(GatekeeperRequest &req, GatekeeperResponse &rsp) { + while (true) { + auto ret = gatekeeper_->enroll( + uid_, req.curPwdHandle, req.curPwd, req.newPwd, + [&rsp](const GatekeeperResponse &cbRsp) { rsp = cbRsp; }); + ASSERT_TRUE(ret.isOk()); + if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break; + ALOGI("%s: got retry code; retrying in 1 sec", __func__); + sleep(1); + } + } + + void doVerify(GatekeeperRequest &req, GatekeeperResponse &rsp) { + while (true) { + auto ret = gatekeeper_->verify( + uid_, req.challenge, req.curPwdHandle, req.newPwd, + [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; }); + ASSERT_TRUE(ret.isOk()); + if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break; + ALOGI("%s: got retry code; retrying in 1 sec", __func__); + sleep(1); + } + } + + void doDeleteUser(GatekeeperResponse &rsp) { + while (true) { + auto ret = gatekeeper_->deleteUser( + uid_, [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; }); + ASSERT_TRUE(ret.isOk()); + if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break; + ALOGI("%s: got retry code; retrying in 1 sec", __func__); + sleep(1); + } + } + + void doDeleteAllUsers(GatekeeperResponse &rsp) { + while (true) { + auto ret = gatekeeper_->deleteAllUsers( + [&rsp](const GatekeeperResponse &cb_rsp) { rsp = cb_rsp; }); + ASSERT_TRUE(ret.isOk()); + if (rsp.code != GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) break; + ALOGI("%s: got retry code; retrying in 1 sec", __func__); + sleep(1); + } + } + + void generatePassword(hidl_vec<uint8_t> &password, uint8_t seed) { + password.resize(16); + memset(password.data(), seed, password.size()); + } + + void checkEnroll(GatekeeperResponse &rsp, bool expectSuccess) { + if (expectSuccess) { + EXPECT_EQ(GatekeeperStatusCode::STATUS_OK, rsp.code); + EXPECT_NE(nullptr, rsp.data.data()); + EXPECT_GT(rsp.data.size(), UINT32_C(0)); + } else { + EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, rsp.code); + EXPECT_EQ(UINT32_C(0), rsp.data.size()); + } + } + + void checkVerify(GatekeeperResponse &rsp, uint64_t challenge, + bool expectSuccess) { + if (expectSuccess) { + EXPECT_GE(rsp.code, GatekeeperStatusCode::STATUS_OK); + EXPECT_LE(rsp.code, GatekeeperStatusCode::STATUS_REENROLL); + + const hw_auth_token_t *auth_token = toAuthToken(rsp); + ASSERT_NE(nullptr, auth_token); + EXPECT_EQ(challenge, auth_token->challenge); + } else { + EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, rsp.code); + EXPECT_EQ(UINT32_C(0), rsp.data.size()); + } + } + + void enrollNewPassword(hidl_vec<uint8_t> &password, GatekeeperResponse &rsp, + bool expectSuccess) { + GatekeeperRequest req; + req.newPwd.setToExternal(password.data(), password.size()); + doEnroll(req, rsp); + checkEnroll(rsp, expectSuccess); + } + + void verifyPassword(hidl_vec<uint8_t> &password, + hidl_vec<uint8_t> &passwordHandle, uint64_t challenge, + GatekeeperResponse &verifyRsp, bool expectSuccess) { + GatekeeperRequest verifyReq; + + // build verify request for the same password (we want it to succeed) + verifyReq.newPwd = password; + // use enrolled password handle we've got + verifyReq.curPwdHandle = passwordHandle; + verifyReq.challenge = challenge; + doVerify(verifyReq, verifyRsp); + checkVerify(verifyRsp, challenge, expectSuccess); + } + + protected: + sp<IGatekeeper> gatekeeper_; + uint32_t uid_; + + public: + GatekeeperHidlTest() : uid_(0) {} + virtual void SetUp() override { + GatekeeperResponse rsp; + gatekeeper_ = ::testing::VtsHalHidlTargetTestBase::getService<IGatekeeper>(); + ASSERT_NE(nullptr, gatekeeper_.get()); + doDeleteAllUsers(rsp); + } + + virtual void TearDown() override { + GatekeeperResponse rsp; + doDeleteAllUsers(rsp); + } +}; + +/** + * Ensure we can enroll new password + */ +TEST_F(GatekeeperHidlTest, EnrollSuccess) { + hidl_vec<uint8_t> password; + GatekeeperResponse rsp; + ALOGI("Testing Enroll (expected success)"); + generatePassword(password, 0); + enrollNewPassword(password, rsp, true); + ALOGI("Testing Enroll done"); +} + +/** + * Ensure we can not enroll empty password + */ +TEST_F(GatekeeperHidlTest, EnrollNoPassword) { + hidl_vec<uint8_t> password; + GatekeeperResponse rsp; + ALOGI("Testing Enroll (expected failure)"); + enrollNewPassword(password, rsp, false); + ALOGI("Testing Enroll done"); +} + +/** + * Ensure we can successfully verify previously enrolled password + */ +TEST_F(GatekeeperHidlTest, VerifySuccess) { + GatekeeperResponse enrollRsp; + GatekeeperResponse verifyRsp; + hidl_vec<uint8_t> password; + + ALOGI("Testing Enroll+Verify (expected success)"); + generatePassword(password, 0); + enrollNewPassword(password, enrollRsp, true); + verifyPassword(password, enrollRsp.data, 1, verifyRsp, true); + ALOGI("Testing Enroll+Verify done"); +} + +/** + * Ensure we can securely update password (keep the same + * secure user_id) if we prove we know old password + */ +TEST_F(GatekeeperHidlTest, TrustedReenroll) { + GatekeeperResponse enrollRsp; + GatekeeperRequest reenrollReq; + GatekeeperResponse reenrollRsp; + GatekeeperResponse verifyRsp; + GatekeeperResponse reenrollVerifyRsp; + hidl_vec<uint8_t> password; + hidl_vec<uint8_t> newPassword; + + generatePassword(password, 0); + + ALOGI("Testing Trusted Reenroll (expected success)"); + enrollNewPassword(password, enrollRsp, true); + verifyPassword(password, enrollRsp.data, 0, verifyRsp, true); + ALOGI("Primary Enroll+Verify done"); + + generatePassword(newPassword, 1); + reenrollReq.newPwd.setToExternal(newPassword.data(), newPassword.size()); + reenrollReq.curPwd.setToExternal(password.data(), password.size()); + reenrollReq.curPwdHandle.setToExternal(enrollRsp.data.data(), + enrollRsp.data.size()); + + doEnroll(reenrollReq, reenrollRsp); + checkEnroll(reenrollRsp, true); + verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true); + ALOGI("Trusted ReEnroll+Verify done"); + + const hw_auth_token_t *first = toAuthToken(verifyRsp); + const hw_auth_token_t *second = toAuthToken(reenrollVerifyRsp); + if (first != nullptr && second != nullptr) { + EXPECT_EQ(first->user_id, second->user_id); + } + ALOGI("Testing Trusted Reenroll done"); +} + +/** + * Ensure we can update password (and get new + * secure user_id) if we don't know old password + */ +TEST_F(GatekeeperHidlTest, UntrustedReenroll) { + GatekeeperResponse enrollRsp; + GatekeeperResponse reenrollRsp; + GatekeeperResponse verifyRsp; + GatekeeperResponse reenrollVerifyRsp; + hidl_vec<uint8_t> password; + hidl_vec<uint8_t> newPassword; + + ALOGI("Testing Untrusted Reenroll (expected success)"); + generatePassword(password, 0); + enrollNewPassword(password, enrollRsp, true); + verifyPassword(password, enrollRsp.data, 0, verifyRsp, true); + ALOGI("Primary Enroll+Verify done"); + + generatePassword(newPassword, 1); + enrollNewPassword(newPassword, reenrollRsp, true); + verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true); + ALOGI("Untrusted ReEnroll+Verify done"); + + const hw_auth_token_t *first = toAuthToken(verifyRsp); + const hw_auth_token_t *second = toAuthToken(reenrollVerifyRsp); + if (first != nullptr && second != nullptr) { + EXPECT_NE(first->user_id, second->user_id); + } + ALOGI("Testing Untrusted Reenroll done"); +} + +/** + * Ensure we dont get successful verify with invalid data + */ +TEST_F(GatekeeperHidlTest, VerifyNoData) { + hidl_vec<uint8_t> password; + hidl_vec<uint8_t> passwordHandle; + GatekeeperResponse verifyRsp; + + ALOGI("Testing Verify (expected failure)"); + verifyPassword(password, passwordHandle, 0, verifyRsp, false); + EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, verifyRsp.code); + ALOGI("Testing Verify done"); +} + +/** + * Ensure we can not verify password after we enrolled it and then deleted user + */ +TEST_F(GatekeeperHidlTest, DeleteUserTest) { + hidl_vec<uint8_t> password; + GatekeeperResponse enrollRsp; + GatekeeperResponse verifyRsp; + GatekeeperResponse delRsp; + ALOGI("Testing deleteUser (expected success)"); + setUid(10001); + generatePassword(password, 0); + enrollNewPassword(password, enrollRsp, true); + verifyPassword(password, enrollRsp.data, 0, verifyRsp, true); + ALOGI("Enroll+Verify done"); + doDeleteUser(delRsp); + EXPECT_EQ(UINT32_C(0), delRsp.data.size()); + EXPECT_TRUE(delRsp.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED || + delRsp.code == GatekeeperStatusCode::STATUS_OK); + ALOGI("DeleteUser done"); + if (delRsp.code == GatekeeperStatusCode::STATUS_OK) { + verifyPassword(password, enrollRsp.data, 0, verifyRsp, false); + EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, verifyRsp.code); + ALOGI("Verify after Delete done (must fail)"); + } + ALOGI("Testing deleteUser done: rsp=%" PRIi32, delRsp.code); +} + +/** + * Ensure we can not delete a user that does not exist + */ +TEST_F(GatekeeperHidlTest, DeleteInvalidUserTest) { + hidl_vec<uint8_t> password; + GatekeeperResponse enrollRsp; + GatekeeperResponse verifyRsp; + GatekeeperResponse delRsp1; + GatekeeperResponse delRsp2; + ALOGI("Testing deleteUser (expected failure)"); + setUid(10002); + generatePassword(password, 0); + enrollNewPassword(password, enrollRsp, true); + verifyPassword(password, enrollRsp.data, 0, verifyRsp, true); + ALOGI("Enroll+Verify done"); + + // Delete the user + doDeleteUser(delRsp1); + EXPECT_EQ(UINT32_C(0), delRsp1.data.size()); + EXPECT_TRUE(delRsp1.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED || + delRsp1.code == GatekeeperStatusCode::STATUS_OK); + + // Delete the user again + doDeleteUser(delRsp2); + EXPECT_EQ(UINT32_C(0), delRsp2.data.size()); + EXPECT_TRUE(delRsp2.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED || + delRsp2.code == GatekeeperStatusCode::ERROR_GENERAL_FAILURE); + ALOGI("DeleteUser done"); + ALOGI("Testing deleteUser done: rsp=%" PRIi32, delRsp2.code); +} + +/** + * Ensure we can not verify passwords after we enrolled them and then deleted + * all users + */ +TEST_F(GatekeeperHidlTest, DeleteAllUsersTest) { + struct UserData { + uint32_t userId; + hidl_vec<uint8_t> password; + GatekeeperResponse enrollRsp; + GatekeeperResponse verifyRsp; + UserData(int id) { userId = id; } + } users[3]{10001, 10002, 10003}; + GatekeeperResponse delAllRsp; + ALOGI("Testing deleteAllUsers (expected success)"); + + // enroll multiple users + for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) { + setUid(users[i].userId); + generatePassword(users[i].password, (i % 255) + 1); + enrollNewPassword(users[i].password, users[i].enrollRsp, true); + } + ALOGI("Multiple users enrolled"); + + // verify multiple users + for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) { + setUid(users[i].userId); + verifyPassword(users[i].password, users[i].enrollRsp.data, 0, + users[i].verifyRsp, true); + } + ALOGI("Multiple users verified"); + + doDeleteAllUsers(delAllRsp); + EXPECT_EQ(UINT32_C(0), delAllRsp.data.size()); + EXPECT_TRUE(delAllRsp.code == GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED || + delAllRsp.code == GatekeeperStatusCode::STATUS_OK); + ALOGI("All users deleted"); + + if (delAllRsp.code == GatekeeperStatusCode::STATUS_OK) { + // verify multiple users after they are deleted; all must fail + for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) { + setUid(users[i].userId); + verifyPassword(users[i].password, users[i].enrollRsp.data, 0, + users[i].verifyRsp, false); + EXPECT_EQ(GatekeeperStatusCode::ERROR_GENERAL_FAILURE, + users[i].verifyRsp.code); + } + ALOGI("Multiple users verified after delete (all must fail)"); + } + + ALOGI("Testing deleteAllUsers done: rsp=%" PRIi32, delAllRsp.code); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +}
diff --git a/gatekeeper/Android.bp b/gatekeeper/Android.bp new file mode 100644 index 0000000..33f70eb --- /dev/null +++ b/gatekeeper/Android.bp
@@ -0,0 +1,5 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/vts/functional", +]
diff --git a/gnss/1.0/Android.bp b/gnss/1.0/Android.bp new file mode 100644 index 0000000..16895b6 --- /dev/null +++ b/gnss/1.0/Android.bp
@@ -0,0 +1,195 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.gnss@1.0_hal", + srcs: [ + "types.hal", + "IAGnss.hal", + "IAGnssCallback.hal", + "IAGnssRil.hal", + "IAGnssRilCallback.hal", + "IGnss.hal", + "IGnssBatching.hal", + "IGnssBatchingCallback.hal", + "IGnssCallback.hal", + "IGnssConfiguration.hal", + "IGnssDebug.hal", + "IGnssGeofenceCallback.hal", + "IGnssGeofencing.hal", + "IGnssMeasurement.hal", + "IGnssMeasurementCallback.hal", + "IGnssNavigationMessage.hal", + "IGnssNavigationMessageCallback.hal", + "IGnssNi.hal", + "IGnssNiCallback.hal", + "IGnssXtra.hal", + "IGnssXtraCallback.hal", + ], +} + +genrule { + name: "android.hardware.gnss@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.gnss@1.0", + srcs: [ + ":android.hardware.gnss@1.0_hal", + ], + out: [ + "android/hardware/gnss/1.0/types.cpp", + "android/hardware/gnss/1.0/AGnssAll.cpp", + "android/hardware/gnss/1.0/AGnssCallbackAll.cpp", + "android/hardware/gnss/1.0/AGnssRilAll.cpp", + "android/hardware/gnss/1.0/AGnssRilCallbackAll.cpp", + "android/hardware/gnss/1.0/GnssAll.cpp", + "android/hardware/gnss/1.0/GnssBatchingAll.cpp", + "android/hardware/gnss/1.0/GnssBatchingCallbackAll.cpp", + "android/hardware/gnss/1.0/GnssCallbackAll.cpp", + "android/hardware/gnss/1.0/GnssConfigurationAll.cpp", + "android/hardware/gnss/1.0/GnssDebugAll.cpp", + "android/hardware/gnss/1.0/GnssGeofenceCallbackAll.cpp", + "android/hardware/gnss/1.0/GnssGeofencingAll.cpp", + "android/hardware/gnss/1.0/GnssMeasurementAll.cpp", + "android/hardware/gnss/1.0/GnssMeasurementCallbackAll.cpp", + "android/hardware/gnss/1.0/GnssNavigationMessageAll.cpp", + "android/hardware/gnss/1.0/GnssNavigationMessageCallbackAll.cpp", + "android/hardware/gnss/1.0/GnssNiAll.cpp", + "android/hardware/gnss/1.0/GnssNiCallbackAll.cpp", + "android/hardware/gnss/1.0/GnssXtraAll.cpp", + "android/hardware/gnss/1.0/GnssXtraCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.gnss@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.gnss@1.0", + srcs: [ + ":android.hardware.gnss@1.0_hal", + ], + out: [ + "android/hardware/gnss/1.0/types.h", + "android/hardware/gnss/1.0/IAGnss.h", + "android/hardware/gnss/1.0/IHwAGnss.h", + "android/hardware/gnss/1.0/BnHwAGnss.h", + "android/hardware/gnss/1.0/BpHwAGnss.h", + "android/hardware/gnss/1.0/BsAGnss.h", + "android/hardware/gnss/1.0/IAGnssCallback.h", + "android/hardware/gnss/1.0/IHwAGnssCallback.h", + "android/hardware/gnss/1.0/BnHwAGnssCallback.h", + "android/hardware/gnss/1.0/BpHwAGnssCallback.h", + "android/hardware/gnss/1.0/BsAGnssCallback.h", + "android/hardware/gnss/1.0/IAGnssRil.h", + "android/hardware/gnss/1.0/IHwAGnssRil.h", + "android/hardware/gnss/1.0/BnHwAGnssRil.h", + "android/hardware/gnss/1.0/BpHwAGnssRil.h", + "android/hardware/gnss/1.0/BsAGnssRil.h", + "android/hardware/gnss/1.0/IAGnssRilCallback.h", + "android/hardware/gnss/1.0/IHwAGnssRilCallback.h", + "android/hardware/gnss/1.0/BnHwAGnssRilCallback.h", + "android/hardware/gnss/1.0/BpHwAGnssRilCallback.h", + "android/hardware/gnss/1.0/BsAGnssRilCallback.h", + "android/hardware/gnss/1.0/IGnss.h", + "android/hardware/gnss/1.0/IHwGnss.h", + "android/hardware/gnss/1.0/BnHwGnss.h", + "android/hardware/gnss/1.0/BpHwGnss.h", + "android/hardware/gnss/1.0/BsGnss.h", + "android/hardware/gnss/1.0/IGnssBatching.h", + "android/hardware/gnss/1.0/IHwGnssBatching.h", + "android/hardware/gnss/1.0/BnHwGnssBatching.h", + "android/hardware/gnss/1.0/BpHwGnssBatching.h", + "android/hardware/gnss/1.0/BsGnssBatching.h", + "android/hardware/gnss/1.0/IGnssBatchingCallback.h", + "android/hardware/gnss/1.0/IHwGnssBatchingCallback.h", + "android/hardware/gnss/1.0/BnHwGnssBatchingCallback.h", + "android/hardware/gnss/1.0/BpHwGnssBatchingCallback.h", + "android/hardware/gnss/1.0/BsGnssBatchingCallback.h", + "android/hardware/gnss/1.0/IGnssCallback.h", + "android/hardware/gnss/1.0/IHwGnssCallback.h", + "android/hardware/gnss/1.0/BnHwGnssCallback.h", + "android/hardware/gnss/1.0/BpHwGnssCallback.h", + "android/hardware/gnss/1.0/BsGnssCallback.h", + "android/hardware/gnss/1.0/IGnssConfiguration.h", + "android/hardware/gnss/1.0/IHwGnssConfiguration.h", + "android/hardware/gnss/1.0/BnHwGnssConfiguration.h", + "android/hardware/gnss/1.0/BpHwGnssConfiguration.h", + "android/hardware/gnss/1.0/BsGnssConfiguration.h", + "android/hardware/gnss/1.0/IGnssDebug.h", + "android/hardware/gnss/1.0/IHwGnssDebug.h", + "android/hardware/gnss/1.0/BnHwGnssDebug.h", + "android/hardware/gnss/1.0/BpHwGnssDebug.h", + "android/hardware/gnss/1.0/BsGnssDebug.h", + "android/hardware/gnss/1.0/IGnssGeofenceCallback.h", + "android/hardware/gnss/1.0/IHwGnssGeofenceCallback.h", + "android/hardware/gnss/1.0/BnHwGnssGeofenceCallback.h", + "android/hardware/gnss/1.0/BpHwGnssGeofenceCallback.h", + "android/hardware/gnss/1.0/BsGnssGeofenceCallback.h", + "android/hardware/gnss/1.0/IGnssGeofencing.h", + "android/hardware/gnss/1.0/IHwGnssGeofencing.h", + "android/hardware/gnss/1.0/BnHwGnssGeofencing.h", + "android/hardware/gnss/1.0/BpHwGnssGeofencing.h", + "android/hardware/gnss/1.0/BsGnssGeofencing.h", + "android/hardware/gnss/1.0/IGnssMeasurement.h", + "android/hardware/gnss/1.0/IHwGnssMeasurement.h", + "android/hardware/gnss/1.0/BnHwGnssMeasurement.h", + "android/hardware/gnss/1.0/BpHwGnssMeasurement.h", + "android/hardware/gnss/1.0/BsGnssMeasurement.h", + "android/hardware/gnss/1.0/IGnssMeasurementCallback.h", + "android/hardware/gnss/1.0/IHwGnssMeasurementCallback.h", + "android/hardware/gnss/1.0/BnHwGnssMeasurementCallback.h", + "android/hardware/gnss/1.0/BpHwGnssMeasurementCallback.h", + "android/hardware/gnss/1.0/BsGnssMeasurementCallback.h", + "android/hardware/gnss/1.0/IGnssNavigationMessage.h", + "android/hardware/gnss/1.0/IHwGnssNavigationMessage.h", + "android/hardware/gnss/1.0/BnHwGnssNavigationMessage.h", + "android/hardware/gnss/1.0/BpHwGnssNavigationMessage.h", + "android/hardware/gnss/1.0/BsGnssNavigationMessage.h", + "android/hardware/gnss/1.0/IGnssNavigationMessageCallback.h", + "android/hardware/gnss/1.0/IHwGnssNavigationMessageCallback.h", + "android/hardware/gnss/1.0/BnHwGnssNavigationMessageCallback.h", + "android/hardware/gnss/1.0/BpHwGnssNavigationMessageCallback.h", + "android/hardware/gnss/1.0/BsGnssNavigationMessageCallback.h", + "android/hardware/gnss/1.0/IGnssNi.h", + "android/hardware/gnss/1.0/IHwGnssNi.h", + "android/hardware/gnss/1.0/BnHwGnssNi.h", + "android/hardware/gnss/1.0/BpHwGnssNi.h", + "android/hardware/gnss/1.0/BsGnssNi.h", + "android/hardware/gnss/1.0/IGnssNiCallback.h", + "android/hardware/gnss/1.0/IHwGnssNiCallback.h", + "android/hardware/gnss/1.0/BnHwGnssNiCallback.h", + "android/hardware/gnss/1.0/BpHwGnssNiCallback.h", + "android/hardware/gnss/1.0/BsGnssNiCallback.h", + "android/hardware/gnss/1.0/IGnssXtra.h", + "android/hardware/gnss/1.0/IHwGnssXtra.h", + "android/hardware/gnss/1.0/BnHwGnssXtra.h", + "android/hardware/gnss/1.0/BpHwGnssXtra.h", + "android/hardware/gnss/1.0/BsGnssXtra.h", + "android/hardware/gnss/1.0/IGnssXtraCallback.h", + "android/hardware/gnss/1.0/IHwGnssXtraCallback.h", + "android/hardware/gnss/1.0/BnHwGnssXtraCallback.h", + "android/hardware/gnss/1.0/BpHwGnssXtraCallback.h", + "android/hardware/gnss/1.0/BsGnssXtraCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.gnss@1.0", + generated_sources: ["android.hardware.gnss@1.0_genc++"], + generated_headers: ["android.hardware.gnss@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.gnss@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/gnss/1.0/Android.mk b/gnss/1.0/Android.mk new file mode 100644 index 0000000..5985c87 --- /dev/null +++ b/gnss/1.0/Android.mk
@@ -0,0 +1,1103 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.gnss@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (GnssConstellationType) +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssConstellationType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::types.GnssConstellationType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (GnssLocation) +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssLocation.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::types.GnssLocation + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (GnssLocationFlags) +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssLocationFlags.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::types.GnssLocationFlags + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (GnssMax) +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssMax.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::types.GnssMax + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IAGnss.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnss.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnss.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssCallback.hal +$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IAGnss + +$(GEN): $(LOCAL_PATH)/IAGnss.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IAGnssCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IAGnssCallback + +$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IAGnssRil.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssRil.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssRil.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssRilCallback.hal +$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IAGnssRil + +$(GEN): $(LOCAL_PATH)/IAGnssRil.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IAGnssRilCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssRilCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssRilCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IAGnssRilCallback + +$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnss.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnss.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnss.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnss.hal +$(GEN): $(LOCAL_PATH)/IAGnss.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssRil.hal +$(GEN): $(LOCAL_PATH)/IAGnssRil.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssBatching.hal +$(GEN): $(LOCAL_PATH)/IGnssBatching.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssConfiguration.hal +$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssDebug.hal +$(GEN): $(LOCAL_PATH)/IGnssDebug.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssGeofencing.hal +$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssMeasurement.hal +$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNavigationMessage.hal +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNi.hal +$(GEN): $(LOCAL_PATH)/IGnssNi.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssXtra.hal +$(GEN): $(LOCAL_PATH)/IGnssXtra.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnss + +$(GEN): $(LOCAL_PATH)/IGnss.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssBatching.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssBatching.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssBatching.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssBatchingCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssBatching + +$(GEN): $(LOCAL_PATH)/IGnssBatching.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssBatchingCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssBatchingCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssBatchingCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssBatchingCallback + +$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssCallback + +$(GEN): $(LOCAL_PATH)/IGnssCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssConfiguration.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssConfiguration.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssConfiguration.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssConfiguration + +$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssDebug.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssDebug.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssDebug.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssDebug + +$(GEN): $(LOCAL_PATH)/IGnssDebug.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssGeofenceCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssGeofenceCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssGeofenceCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssGeofenceCallback + +$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssGeofencing.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssGeofencing.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssGeofencing.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssGeofenceCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssGeofencing + +$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssMeasurement.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssMeasurement.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssMeasurement.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssMeasurementCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssMeasurement + +$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssMeasurementCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssMeasurementCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssMeasurementCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssMeasurementCallback + +$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssNavigationMessage.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNavigationMessage.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNavigationMessage.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssNavigationMessage + +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssNavigationMessageCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNavigationMessageCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssNavigationMessageCallback + +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssNi.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNi.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNi.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNiCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssNi + +$(GEN): $(LOCAL_PATH)/IGnssNi.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssNiCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNiCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNiCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssNiCallback + +$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssXtra.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssXtra.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssXtra.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssXtraCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssXtra + +$(GEN): $(LOCAL_PATH)/IGnssXtra.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssXtraCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssXtraCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssXtraCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssXtraCallback + +$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.gnss@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (GnssConstellationType) +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssConstellationType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::types.GnssConstellationType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (GnssLocation) +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssLocation.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::types.GnssLocation + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (GnssLocationFlags) +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssLocationFlags.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::types.GnssLocationFlags + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (GnssMax) +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/GnssMax.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::types.GnssMax + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IAGnss.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnss.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnss.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssCallback.hal +$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IAGnss + +$(GEN): $(LOCAL_PATH)/IAGnss.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IAGnssCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IAGnssCallback + +$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IAGnssRil.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssRil.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssRil.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssRilCallback.hal +$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IAGnssRil + +$(GEN): $(LOCAL_PATH)/IAGnssRil.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IAGnssRilCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IAGnssRilCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IAGnssRilCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IAGnssRilCallback + +$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnss.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnss.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnss.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnss.hal +$(GEN): $(LOCAL_PATH)/IAGnss.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IAGnssRil.hal +$(GEN): $(LOCAL_PATH)/IAGnssRil.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssBatching.hal +$(GEN): $(LOCAL_PATH)/IGnssBatching.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssConfiguration.hal +$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssDebug.hal +$(GEN): $(LOCAL_PATH)/IGnssDebug.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssGeofencing.hal +$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssMeasurement.hal +$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNavigationMessage.hal +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNi.hal +$(GEN): $(LOCAL_PATH)/IGnssNi.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssXtra.hal +$(GEN): $(LOCAL_PATH)/IGnssXtra.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnss + +$(GEN): $(LOCAL_PATH)/IGnss.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssBatching.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssBatching.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssBatching.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssBatchingCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssBatching + +$(GEN): $(LOCAL_PATH)/IGnssBatching.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssBatchingCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssBatchingCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssBatchingCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssBatchingCallback + +$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssCallback + +$(GEN): $(LOCAL_PATH)/IGnssCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssConfiguration.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssConfiguration.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssConfiguration.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssConfiguration + +$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssDebug.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssDebug.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssDebug.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssDebug + +$(GEN): $(LOCAL_PATH)/IGnssDebug.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssGeofenceCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssGeofenceCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssGeofenceCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssGeofenceCallback + +$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssGeofencing.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssGeofencing.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssGeofencing.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssGeofenceCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssGeofencing + +$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssMeasurement.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssMeasurement.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssMeasurement.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssMeasurementCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssMeasurement + +$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssMeasurementCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssMeasurementCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssMeasurementCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssMeasurementCallback + +$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssNavigationMessage.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNavigationMessage.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNavigationMessage.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssNavigationMessage + +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssNavigationMessageCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNavigationMessageCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssNavigationMessageCallback + +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssNi.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNi.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNi.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssNiCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssNi + +$(GEN): $(LOCAL_PATH)/IGnssNi.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssNiCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssNiCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssNiCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssNiCallback + +$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssXtra.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssXtra.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssXtra.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IGnssXtraCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssXtra + +$(GEN): $(LOCAL_PATH)/IGnssXtra.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IGnssXtraCallback.hal +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/IGnssXtraCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IGnssXtraCallback.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0::IGnssXtraCallback + +$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.gnss@1.0-java-constants +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +# +GEN := $(intermediates)/android/hardware/gnss/V1_0/Constants.java +$(GEN): $(HIDL) +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/IAGnss.hal +$(GEN): $(LOCAL_PATH)/IAGnssCallback.hal +$(GEN): $(LOCAL_PATH)/IAGnssRil.hal +$(GEN): $(LOCAL_PATH)/IAGnssRilCallback.hal +$(GEN): $(LOCAL_PATH)/IGnss.hal +$(GEN): $(LOCAL_PATH)/IGnssBatching.hal +$(GEN): $(LOCAL_PATH)/IGnssBatchingCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssConfiguration.hal +$(GEN): $(LOCAL_PATH)/IGnssDebug.hal +$(GEN): $(LOCAL_PATH)/IGnssGeofenceCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssGeofencing.hal +$(GEN): $(LOCAL_PATH)/IGnssMeasurement.hal +$(GEN): $(LOCAL_PATH)/IGnssMeasurementCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessage.hal +$(GEN): $(LOCAL_PATH)/IGnssNavigationMessageCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssNi.hal +$(GEN): $(LOCAL_PATH)/IGnssNiCallback.hal +$(GEN): $(LOCAL_PATH)/IGnssXtra.hal +$(GEN): $(LOCAL_PATH)/IGnssXtraCallback.hal + +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava-constants \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.gnss@1.0 + +$(GEN): + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +# Avoid dependency cycle of framework.jar -> this-library -> framework.jar +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj + +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/gnss/1.0/IAGnss.hal b/gnss/1.0/IAGnss.hal new file mode 100644 index 0000000..b8f5746 --- /dev/null +++ b/gnss/1.0/IAGnss.hal
@@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +import IAGnssCallback; + +/* + * Extended interface for AGNSS support. + */ +interface IAGnss { + @export(name="", value_prefix="APN_IP_") + enum ApnIpType : uint8_t { + INVALID = 0, + IPV4 = 1, + IPV6 = 2, + IPV4V6 = 3 + }; + + /* + * Opens the AGNSS interface and provides the callback routines to the + * implementation of this interface. + * + * @param callback Handle to the AGNSS status callback interface. + */ + setCallback(IAGnssCallback callback); + + /* + * Notifies that the AGNSS data connection has been closed. + * + * @return success True if the operation is successful. + */ + dataConnClosed() generates (bool success); + + /* + * Notifies that a data connection is not available for AGNSS. + * + * @return success True if the operation is successful. + */ + dataConnFailed() generates (bool success); + + /* + * Sets the hostname and port for the AGNSS server. + * + * @param type Specifies if SUPL or C2K. + * @param hostname Hostname of the AGNSS server. + * @param port Port number associated with the server. + * + * @return success True if the operation is successful. + */ + setServer(AGnssType type, string hostname, int32_t port) + generates (bool success); + + /* + * Notifies that a data connection is available and sets the name of the + * APN, and its IP type, to be used for SUPL connections. + * + * @param apn Access Point Name(follows regular APN naming convention). + * @param apnIpType Specifies if SUPL or C2K. + * + * @return success True if the operation is successful. + */ + dataConnOpen(string apn, ApnIpType apnIpType) + generates (bool success); +};
diff --git a/gnss/1.0/IAGnssCallback.hal b/gnss/1.0/IAGnssCallback.hal new file mode 100644 index 0000000..fe2e101 --- /dev/null +++ b/gnss/1.0/IAGnssCallback.hal
@@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +/** Callback structure for the AGNSS interface. */ +interface IAGnssCallback { + /** AGNSS type **/ + @export(name="", value_prefix="AGPS_") + enum AGnssType : uint8_t { + TYPE_SUPL = 1, + TYPE_C2K = 2 + }; + + @export(name="", value_prefix="GNSS_") + enum AGnssStatusValue : uint8_t { + /** GNSS requests data connection for AGNSS. */ + REQUEST_AGNSS_DATA_CONN = 1, + /** GNSS releases the AGNSS data connection. */ + RELEASE_AGNSS_DATA_CONN = 2, + /** AGNSS data connection initiated */ + AGNSS_DATA_CONNECTED = 3, + /** AGNSS data connection completed */ + AGNSS_DATA_CONN_DONE = 4, + /** AGNSS data connection failed */ + AGNSS_DATA_CONN_FAILED = 5 + }; + + /* + * Represents the status of AGNSS augmented to support IPv4. + */ + @export(name="", value_prefix="GPS_") + struct AGnssStatusIpV4 { + AGnssType type; + AGnssStatusValue status; + /* + * 32-bit IPv4 address. + */ + uint32_t ipV4Addr; + }; + + /* + * Represents the status of AGNSS augmented to support IPv6. + */ + struct AGnssStatusIpV6 { + AGnssType type; + AGnssStatusValue status; + /* + * 128-bit IPv6 address. + */ + uint8_t[16] ipV6Addr; + }; + + /* + * Callback with AGNSS(IpV4) status information. + * + * @param status Will be of type AGnssStatusIpV4. + */ + agnssStatusIpV4Cb(AGnssStatusIpV4 status); + + /* + * Callback with AGNSS(IpV6) status information. + * + * @param status Will be of type AGnssStatusIpV6. + */ + agnssStatusIpV6Cb(AGnssStatusIpV6 status); + +};
diff --git a/gnss/1.0/IAGnssRil.hal b/gnss/1.0/IAGnssRil.hal new file mode 100644 index 0000000..6292273 --- /dev/null +++ b/gnss/1.0/IAGnssRil.hal
@@ -0,0 +1,144 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +import IAGnssRilCallback; + +/* + * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface + * Layer interface allows the GNSS chipset to request radio interface layer + * information from Android platform. Examples of such information are reference + * location, unique subscriber ID, phone number string and network availability changes. + */ +interface IAGnssRil { + @export(name="", value_prefix="AGPS_SETID_TYPE_") + enum SetIDType : uint8_t { + NONE = 0, + IMSI = 1, + MSISDM = 2 + }; + + @export(name="", value_prefix="AGPS_RIL_NETWORK_TYPE_") + enum NetworkType : uint8_t { + MOBILE = 0, + WIFI = 1, + MMS = 2, + SUPL = 3, + DUN = 4, + HIPRI = 5, + WIMAX = 6, + }; + + @export(name="", value_prefix="AGPS_REF_LOCATION_TYPE_") + enum AGnssRefLocationType : uint8_t { + GSM_CELLID = 1, + UMTS_CELLID = 2, + LTE_CELLID = 4, + }; + + /* CellID for 2G, 3G and LTE, used in AGNSS. */ + struct AGnssRefLocationCellID { + AGnssRefLocationType type; + + /* Mobile Country Code. */ + uint16_t mcc; + + /* Mobile Network Code .*/ + uint16_t mnc; + + /* + * Location Area Code in 2G, 3G and LTE. In 3G lac is discarded. In LTE, + * lac is populated with tac, to ensure that we don't break old clients that + * might rely in the old (wrong) behavior. + */ + uint16_t lac; + + /* Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE. */ + uint32_t cid; + + /* Tracking Area Code in LTE. */ + uint16_t tac; + + /* Physical Cell id in LTE (not used in 2G and 3G) */ + uint16_t pcid; + }; + + /* Represents ref locations */ + struct AGnssRefLocation { + AGnssRefLocationType type; + + AGnssRefLocationCellID cellID; + }; + + /* + * Opens the AGNSS interface and provides the callback routines + * to the implementation of this interface. + * + * @param callback Interface for AGnssRil callbacks. + */ + setCallback(IAGnssRilCallback callback); + + /* + * Sets the reference location. + * + * @param agnssReflocation AGNSS reference location CellID. + */ + setRefLocation(AGnssRefLocation agnssReflocation); + + /* + * Sets the SET ID. + * + * @param type Must be populated with either IMSI or MSISDN or NONE. + * @param setid If type is IMSI then setid is populated with + * a string representing the unique Subscriber ID, for example, the IMSI for + * a GMS phone. If type is MSISDN, then setid must contain + * the phone number string for line 1. For example, the MSISDN for a GSM phone. + * If the type is NONE, then the string must be empty. + * + * @return success True if all parameters were valid and operation was + * successful. + */ + setSetId(SetIDType type, string setid) generates (bool success); + + /* + * Notify GNSS of network status changes. + * + * @param connected Indicates whether network connectivity exists and + * it is possible to establish connections and pass data. + * @param type Indicates the kind of network, for eg. mobile, wifi etc. + * @param roaming Indicates whether the device is currently roaming on + * this network. + * + * @return success True is all parameters were valid and operation was + * successful. + */ + updateNetworkState(bool connected, NetworkType type, bool roaming) + generates (bool success); + + /* + * Notify GNSS of network status changes. + * + * @param available Indicates whether network connectivity is available. + * @param apn String containing the Access Point Name. + * + * @return success True if all parameters were valid and the operation was + * successful. + * TODO(b/32022567): Add VTS test to validate the format of APN. + */ + updateNetworkAvailability(bool available, string apn) generates (bool success); + +};
diff --git a/gnss/1.0/IAGnssRilCallback.hal b/gnss/1.0/IAGnssRilCallback.hal new file mode 100644 index 0000000..2d64e54 --- /dev/null +++ b/gnss/1.0/IAGnssRilCallback.hal
@@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +/* + * Callback for IAGnssRil interface. Used to request SET ID and + * Reference Location. + */ +interface IAGnssRilCallback { + /* Kinds of SET ID that can be requested */ + @export(name="", value_prefix="AGPS_RIL_REQUEST_SETID_") + enum ID : uint32_t { + IMSI = 1 << 0L, + MSISDN = 1 << 1L, + }; + + /* + * The Hal uses this API to request a SET ID. + * + * @param setIdflag Specifies the kind of SET ID that is required by the HAL. + */ + requestSetIdCb(bitfield<ID> setIdflag); + + /* + * The Hal uses this API to request a reference location. + * + */ + requestRefLocCb(); + +};
diff --git a/gnss/1.0/IGnss.hal b/gnss/1.0/IGnss.hal new file mode 100644 index 0000000..5cde79e --- /dev/null +++ b/gnss/1.0/IGnss.hal
@@ -0,0 +1,237 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +import IAGnss; +import IAGnssRil; +import IGnssBatching; +import IGnssCallback; +import IGnssConfiguration; +import IGnssDebug; +import IGnssMeasurement; +import IGnssNavigationMessage; +import IGnssGeofencing; +import IGnssNi; +import IGnssXtra; + +/* Represents the standard GNSS (Global Navigation Satellite System) interface. */ +interface IGnss { + /* Requested operational mode for GNSS operation. */ + @export(name="", value_prefix="GPS_POSITION_MODE_") + enum GnssPositionMode : uint8_t { + /** Mode for running GNSS standalone (no assistance). */ + STANDALONE = 0, + /** AGNSS MS-Based mode. */ + MS_BASED = 1, + /* + * AGNSS MS-Assisted mode. This mode is not maintained by the platform anymore. + * It is strongly recommended to use MS_BASED instead. + */ + MS_ASSISTED = 2, + }; + + /* Requested recurrence mode for GNSS operation. */ + @export(name="", value_prefix="GPS_POSITION_") + enum GnssPositionRecurrence : uint32_t { + /** Receive GNSS fixes on a recurring basis at a specified period. */ + RECURRENCE_PERIODIC = 0, + /** Request a single shot GNSS fix. */ + RECURRENCE_SINGLE = 1 + }; + + /* + * Flags used to specify which aiding data to delete when calling + * deleteAidingData(). + */ + @export(name="", value_prefix="GPS_") + enum GnssAidingData : uint16_t { + DELETE_EPHEMERIS = 0x0001, + DELETE_ALMANAC = 0x0002, + DELETE_POSITION = 0x0004, + DELETE_TIME = 0x0008, + DELETE_IONO = 0x0010, + DELETE_UTC = 0x0020, + DELETE_HEALTH = 0x0040, + DELETE_SVDIR = 0x0080, + DELETE_SVSTEER = 0x0100, + DELETE_SADATA = 0x0200, + DELETE_RTI = 0x0400, + DELETE_CELLDB_INFO = 0x8000, + DELETE_ALL = 0xFFFF + }; + + /* + * Opens the interface and provides the callback routines + * to the implementation of this interface. + * + * @param callback Callback interface for IGnss. + * + * @return success Returns true on success. + */ + setCallback(IGnssCallback callback) generates (bool success); + + /* + * Starts a location output stream using the IGnssCallback + * gnssLocationCb(), following the settings from the most recent call to + * setPositionMode(). + * + * This output must operate independently of any GNSS location batching + * operations, see the IGnssBatching.hal for details. + * + * @return success Returns true on success. + */ + start() generates (bool success); + + /* + * Stops the location output stream. + * + * @return success Returns true on success. + */ + stop() generates (bool success); + + /* + * Closes the interface. + */ + cleanup(); + + /* + * Injects the current time. + * + * @param timeMs This is the UTC time received from the NTP server, its value + * is given in milliseconds since January 1, 1970. + * @param timeReferenceMs The corresponding value of + * SystemClock.elapsedRealtime() from the device when the NTP response was + * received in milliseconds. + * @param uncertaintyMs Uncertainty associated with the value represented by + * time. Represented in milliseconds. + * + * @return success Returns true if the operation is successful. + */ + injectTime(GnssUtcTime timeMs, int64_t timeReferenceMs, int32_t uncertaintyMs) + generates (bool success); + + /* + * Injects current location from another location provider (typically cell + * ID). + * + * @param latitudeDegrees Measured in Degrees. + * @param longitudeDegrees Measured in Degrees. + * @param accuracyMeters Measured in meters. + * + * @return success Returns true if successful. + */ + injectLocation(double latitudeDegrees, double longitudeDegrees, float accuracyMeters) + generates (bool success); + + /* + * Specifies that the next call to start will not use the + * information defined in the flags. GnssAidingData value of DELETE_ALL is + * passed for a cold start. + * + * @param aidingDataFlags Flags specifying the aiding data to be deleted. + */ + deleteAidingData(GnssAidingData aidingDataFlags); + + /* + * Sets the GnssPositionMode parameter,its associated recurrence value, + * the time between fixes,requested fix accuracy and time to first fix. + * + * @param mode Parameter must be one of MS_BASED or STANDALONE. + * It is allowed by the platform (and it is recommended) to fallback to + * MS_BASED if MS_ASSISTED is passed in, and MS_BASED is supported. + * @recurrence GNSS postion recurrence value, either periodic or single. + * @param minIntervalMs Represents the time between fixes in milliseconds. + * @param preferredAccuracyMeters Represents the requested fix accuracy in meters. + * @param preferredTimeMs Represents the requested time to first fix in milliseconds. + + * @return success Returns true if successful. + */ + setPositionMode(GnssPositionMode mode, GnssPositionRecurrence recurrence, + uint32_t minIntervalMs, uint32_t preferredAccuracyMeters, + uint32_t preferredTimeMs) + generates (bool success); + + /* + * This method returns the IAGnssRil Interface. + * + * @return aGnssRilIface Handle to the IAGnssRil interface. + */ + getExtensionAGnssRil() generates (IAGnssRil aGnssRilIface); + + /* + * This method returns the IGnssGeofencing Interface. + * + * @return gnssGeofencingIface Handle to the IGnssGeofencing interface. + */ + getExtensionGnssGeofencing() generates(IGnssGeofencing gnssGeofencingIface); + + /* + * This method returns the IAGnss Interface. + * + * @return aGnssIface Handle to the IAGnss interface. + */ + getExtensionAGnss() generates (IAGnss aGnssIface); + + /* + * This method returns the IGnssNi interface. + * + * @return gnssNiIface Handle to the IGnssNi interface. + */ + getExtensionGnssNi() generates (IGnssNi gnssNiIface); + + /* + * This method returns the IGnssMeasurement interface. + * + * @return gnssMeasurementIface Handle to the IGnssMeasurement interface. + */ + getExtensionGnssMeasurement() generates (IGnssMeasurement gnssMeasurementIface); + + /* + * This method returns the IGnssNavigationMessage interface. + * + * @return gnssNavigationIface gnssNavigationIface to the IGnssNavigationMessage interface. + */ + getExtensionGnssNavigationMessage() generates (IGnssNavigationMessage gnssNavigationIface); + + /* + * This method returns the IGnssXtra interface. + * + * @return xtraIface Handle to the IGnssXtra interface. + */ + getExtensionXtra() generates (IGnssXtra xtraIface); + + /* + * This method returns the IGnssConfiguration interface. + * + * @return gnssConfigIface Handle to the IGnssConfiguration interface. + */ + getExtensionGnssConfiguration() generates (IGnssConfiguration gnssConfigIface); + + /* + * This method returns the IGnssDebug interface. + * + * @return debugIface Handle to the IGnssDebug interface. + */ + getExtensionGnssDebug() generates (IGnssDebug debugIface); + + /* + * This method returns the IGnssBatching interface. + * + * @return batchingIface Handle to the IGnssBatching interface. + */ + getExtensionGnssBatching() generates (IGnssBatching batchingIface); +};
diff --git a/gnss/1.0/IGnssBatching.hal b/gnss/1.0/IGnssBatching.hal new file mode 100644 index 0000000..6f2dde6 --- /dev/null +++ b/gnss/1.0/IGnssBatching.hal
@@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +import IGnssBatchingCallback; + +/* + * Extended interface for GNSS Batching support. + * + * If this interface is supported, this batching request must be able to run in + * parallel with, or without, non-batched location requested by the + * IGnss start() & stop() - i.e. both requests must be handled independently, + * and not interfere with each other. + * + * For example, if a 1Hz continuous output is underway on the IGnssCallback, + * due to an IGnss start() operation, + * and then a IGnssBatching start() is called for a location every 10 + * seconds, the newly added batching request must not disrupt the 1Hz + * continuous location output on the IGnssCallback. + * + * As with GNSS Location outputs, source of location must be GNSS satellite + * measurements, optionally using interial and baro sensors to improve + * relative motion filtering. No additional absolute positioning information, + * such as WiFi derived location, may be mixed with the GNSS information. + */ + +interface IGnssBatching { + /* + * Enum which holds the bit masks for batching control. + */ + @export(name="", value_prefix="FLP_BATCH_") + enum Flag : uint8_t { + /* + * If this flag is set, the hardware implementation + * must wake up the application processor when the FIFO is full, and + * call IGnssBatchingCallback to return the locations. + * + * If the flag is not set, the hardware implementation must drop + * the oldest data when the FIFO is full. + */ + WAKEUP_ON_FIFO_FULL = 0x01 + }; + + struct Options { + /* + * Time interval between samples in the location batch, in nano + * seconds. + */ + int64_t periodNanos; + + /* + * Flags controlling how batching should behave. + */ + bitfield<Flag> flags; + }; + + /* + * Opens the interface and provides the callback routines + * to the implementation of this interface. + * + * @param callback Callback interface for IGnssBatching. + * + * @return success Returns true on success. + */ + init(IGnssBatchingCallback callback) generates (bool success); + + /* + * Return the batch size (in number of GnssLocation objects) + * available in this hardware implementation. + * + * If the available size is variable, for example, based on other operations + * consuming memory, this is the minimum size guaranteed to be available + * for batching operations. + * + * This may, for example, be used by the upper layer, to decide on the + * batching interval and whether the AP should be woken up or not. + * + * @return batchSize number of location objects supported per batch + */ + getBatchSize() generates (uint16_t batchSize); + + /* + * Start batching locations. This API is primarily used when the AP is + * asleep and the device can batch locations in the hardware. + * + * IGnssBatchingCallback is used to return the locations. + * + * When the buffer is full and WAKEUP_ON_FIFO_FULL is used, + * IGnssBatchingCallback must be called to return the locations. + * + * When the buffer is full and WAKEUP_ON_FIFO_FULL is not set, + * the oldest location object is dropped. In this case the AP must not be + * woken up. The AP would then generally be responsible for using + * flushBatchedLocation to explicitly ask for the location as needed, + * to avoid it being dropped. + * + * @param options See struct Options definition. + * + * @return success Returns true on success. + */ + start(Options options) generates (bool success); + + /** + * Retrieve all batched locations currently stored. + * + * IGnssBatchingCallback is used to return the location. + * + * IGnssBatchingCallback must be called in response, even if there are + * no locations to flush (in which case the Location vector must be empty). + * + * Subsequent calls to flushBatchedLocation + * must not return any of the locations returned in this call. + */ + flush(); + + /** + * Stop batching. + * + * @return success Returns true on success. + */ + stop() generates (bool success); + + /** + * Closes the interface. If any batch operations are in progress, + * they must be stopped. If any locations are in the hardware batch, they + * must be deleted (and not sent via callback.) + * + * init() may be called again, after this, if the interface is to be restored + */ + cleanup(); + +};
diff --git a/gnss/1.0/IGnssBatchingCallback.hal b/gnss/1.0/IGnssBatchingCallback.hal new file mode 100644 index 0000000..a8f4b88 --- /dev/null +++ b/gnss/1.0/IGnssBatchingCallback.hal
@@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +/* The callback interface to report measurements from the HAL. */ +interface IGnssBatchingCallback { + /* + * Called when a batch of locations is output, by various means, including + * a flush request, as well as the buffer becoming full (if appropriate option + * is set.) + * + * All locations returned by this callback must be cleared from the hardware + * buffer, such the sequential calls of this callback do not return any + * redundant locations. (Same lat/lon, at a new time, is acceptable.) + * + * @param locations GNSS Location information from HAL. + */ + gnssLocationBatchCb(vec<GnssLocation> locations); +};
diff --git a/gnss/1.0/IGnssCallback.hal b/gnss/1.0/IGnssCallback.hal new file mode 100644 index 0000000..0c3b9f0 --- /dev/null +++ b/gnss/1.0/IGnssCallback.hal
@@ -0,0 +1,244 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +/* + * The interface is required for the HAL to communicate certain information + * like status and location info back to the platform, the platform implements + * the interfaces and passes a handle to the HAL. + */ +interface IGnssCallback { + /* Flags for the gnssSetCapabilities callback. */ + @export(name="", value_prefix="GPS_CAPABILITY_") + enum Capabilities : uint32_t { + /* + * GNSS HAL schedules fixes for RECURRENCE_PERIODIC mode. + * If this is not set, then the framework will use 1000ms for + * minInterval and will call start() and stop() to schedule the GNSS. + */ + SCHEDULING = 1 << 0, + /** GNSS supports MS-Based AGNSS mode */ + MSB = 1 << 1, + /** GNSS supports MS-Assisted AGNSS mode */ + MSA = 1 << 2, + /** GNSS supports single-shot fixes */ + SINGLE_SHOT = 1 << 3, + /** GNSS supports on demand time injection */ + ON_DEMAND_TIME = 1 << 4, + /** GNSS supports Geofencing */ + GEOFENCING = 1 << 5, + /** GNSS supports Measurements for at least GPS. */ + MEASUREMENTS = 1 << 6, + /** GNSS supports Navigation Messages */ + NAV_MESSAGES = 1 << 7 + }; + + /* GNSS status event values. */ + @export(name="", value_prefix="GPS_STATUS_") + enum GnssStatusValue : uint8_t { + /** GNSS status unknown. */ + NONE = 0, + /** GNSS has begun navigating. */ + SESSION_BEGIN = 1, + /** GNSS has stopped navigating. */ + SESSION_END = 2, + /** GNSS has powered on but is not navigating. */ + ENGINE_ON = 3, + /** GNSS is powered off. */ + ENGINE_OFF = 4 + }; + + /* + * Flags that indicate information about the satellite + */ + @export(name="", value_prefix="GNSS_SV_FLAGS_") + enum GnssSvFlags : uint8_t { + NONE = 0, + HAS_EPHEMERIS_DATA = 1 << 0, + HAS_ALMANAC_DATA = 1 << 1, + USED_IN_FIX = 1 << 2, + HAS_CARRIER_FREQUENCY = 1 << 3 + }; + + struct GnssSvInfo { + /* + * Pseudo-random number for the SV, or FCN/OSN number for Glonass. The + * distinction is made by looking at constellation field. Values must be + * in the range of: + * + * - GNSS: 1-32 + * - SBAS: 120-151, 183-192 + * - GLONASS: 1-24, the orbital slot number (OSN), if known. Or, if not: + * 93-106, the frequency channel number (FCN) (-7 to +6) offset by + * + 100 + * i.e. report an FCN of -7 as 93, FCN of 0 as 100, and FCN of +6 + * as 106. + * - QZSS: 193-200 + * - Galileo: 1-36 + * - Beidou: 1-37 + */ + int16_t svid; + + /* + * Defines the constellation of the given SV. + */ + GnssConstellationType constellation; + + /* + * Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. + * It contains the measured C/N0 value for the signal at the antenna port. + * + * This is a mandatory value. + */ + float cN0Dbhz; + + /** Elevation of SV in degrees. */ + float elevationDegrees; + + /** Azimuth of SV in degrees. */ + float azimuthDegrees; + + /* + * Carrier frequency of the signal tracked, for example it can be the + * GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, L5 = + * 1176.45 MHz, varying GLO channels, etc. If the field is not set, it + * is the primary common use central frequency, e.g. L1 = 1575.45 MHz + * for GPS. + * + * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same + * time, two GnssSvInfo structs must be reported for this same + * satellite, in one of the structs, all the values related + * to L1 must be filled, and in the other all of the values related to + * L5 must be filled. + * + * If the data is available, gnssClockFlags must contain + * HAS_CARRIER_FREQUENCY. + */ + float carrierFrequencyHz; + + /* + * Contains additional data about the given SV. + */ + bitfield<GnssSvFlags> svFlag; + }; + + /* + * Represents SV status. + */ + struct GnssSvStatus { + /* + * Number of GNSS SVs currently visible, refers to the SVs stored in sv_list + */ + uint32_t numSvs; + + /* + * Pointer to an array of SVs information for all GNSS constellations, + * except GNSS, which is reported using svList + */ + GnssSvInfo[GnssMax:SVS_COUNT] gnssSvList; + + }; + + /* + * Called when a GNSS location is available. + * + * @param location Location information from HAL. + */ + gnssLocationCb(GnssLocation location); + + /* + * Called to communicate the status of the GNSS engine. + * + * @param status Status information from HAL. + */ + gnssStatusCb(GnssStatusValue status); + + /* + * @param svInfo SV status information from HAL. + */ + gnssSvStatusCb(GnssSvStatus svInfo); + + /* + * Called when NMEA data is available. + * Callback for reporting NMEA sentences. + * + * @param timestamp Marks the instance of reporting. + * @param nmea Follows standard NMEA 0183. Each sentence begins with a '$' + * and ends with a carriage return/line feed sequence and can be no longer + * than 80 characters of visible text (plus the line terminators). The data + * is contained within this single line with data items separated by commas. + * The data itself is just ascii text and may extend over multiple sentences + * in certain specialized instances but is normally fully contained in one + * variable length sentence. The data may vary in the amount of precision + * contained in the message. For example time might be indicated to decimal + * parts of a second or location may be shown with 3 or even 4 digits after + * the decimal point. Programs that read the data must only use the commas + * to determine the field boundaries and not depend on column positions. + * There is a provision for a checksum at the end of each sentence which may + * or may not be checked by the unit that reads the data. The checksum field + * consists of a '*' and two hex digits representing an 8 bit exclusive OR + * of all characters between, but not including, the '$' and '*'. + */ + gnssNmeaCb(GnssUtcTime timestamp, string nmea); + + /* + * Callback to inform framework of the GNSS engine's capabilities. + * + * @param capabilities Capability parameter is a bit field of + * the Capabilities enum. + */ + gnssSetCapabilitesCb(bitfield<Capabilities> capabilities); + + /* + * Callback utility for acquiring the GNSS wakelock. This can be used to prevent + * the CPU from suspending while handling GNSS events. + */ + gnssAcquireWakelockCb(); + + /** Callback utility for releasing the GNSS wakelock. */ + gnssReleaseWakelockCb(); + + /** Callback for requesting NTP time */ + gnssRequestTimeCb(); + + /* + * Provides information about how new the underlying GPS/GNSS hardware and + * software is. + * + * This information will be available for Android Test Applications. If a GNSS + * HAL does not provide this information, it will be considered "2015 or + * earlier". + * + * If a GNSS HAL does provide this information, then newer years will need to + * meet newer CTS standards. E.g. if the date are 2016 or above, then N+ level + * GnssMeasurement support will be verified. + */ + struct GnssSystemInfo{ + /* + * year in which the last update was made to the underlying hardware/firmware + * used to capture GNSS signals, e.g. 2016 + */ + uint16_t yearOfHw; + }; + + /* + * Callback to inform framework of the engine's hardware version information. + * + * @param info GnssSystemInfo about the GPS/GNSS hardware. + */ + gnssSetSystemInfoCb(GnssSystemInfo info); +};
diff --git a/gnss/1.0/IGnssConfiguration.hal b/gnss/1.0/IGnssConfiguration.hal new file mode 100644 index 0000000..2fb6e4e --- /dev/null +++ b/gnss/1.0/IGnssConfiguration.hal
@@ -0,0 +1,149 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +/* + * Interface for passing GNSS configuration info from platform to HAL. + */ +interface IGnssConfiguration { + /* + * Enum which holds the bit masks for SUPL_MODE configuration parameter. + */ + enum SuplMode : uint8_t { + /* Mobile Station Based */ + MSB = 0x01, + + /* Mobile Station Assisted */ + MSA = 0x02 + }; + + /* + * Enum which holds the bit masks for GPS_LOCK configuration parameter. + */ + enum GpsLock : uint8_t { + /* Lock Mobile Originated GPS functionalitues. */ + MO = 0x01, + + /* Lock Network initiated GPS functionalities. */ + NI = 0x02 + }; + + /* + * Enum that hold the bit masks for various LTE Positioning Profile settings (LPP_PROFILE + * configuration parameter). If none of the bits in the enum are set, the default setting is + * Radio Resource Location Protocol(RRLP). + */ + enum LppProfile : uint8_t { + /* Enable LTE Positioning Protocol user plane */ + USER_PLANE = 0x01, + + /* Enable LTE Positioning Protocol Control plane */ + CONTROL_PLANE = 0x02 + }; + + /* + * Enum which holds the bit masks for A_GLONASS_POS_PROTOCOL_SELECT + * configuration parameter. + */ + enum GlonassPosProtocol : uint8_t { + /* Radio Resource Control(RRC) control-plane. */ + RRC_CPLANE = 0x01, + + /* Radio Resource Location user-plane. */ + RRLP_CPLANE = 0x02, + + /* LTE Positioning Protocol User plane */ + LPP_UPLANE = 0x04 + }; + + /* + * IMPORTANT: GNSS HAL must expect the below methods to be called multiple + * times. They can be called even when GnssLocationProvider is already + * constructed and enabled. GNSS HAL must maintain the existing requests + * for various callbacks regardless the change in configuration data. + */ + + /* + * This method enables or disables emergency SUPL. + * + * @param enabled True if emergency SUPL is to be enabled. + * + * @return success True if operation was successful. + */ + setSuplEs(bool enabled) generates (bool success); + + /* + * This method sets the SUPL version requested by Carrier. The GNSS HAL + * must use this version of the SUPL protocol if supported. + * + * @param version SUPL version requested by carrier. This is a bit mask + * with bits 0:7 representing a service indicator field, bits 8:15 + * representing the minor version and bits 16:23 representing the + * major version. + * + * @return success True if operation was successful. + */ + setSuplVersion(uint32_t version) generates (bool success); + + /* + * This method sets the SUPL mode. + * + * @param mode Bit mask that specifies the SUPL mode which is set with the SuplMode enum. + * + * @return success True if operation was successful. + */ + setSuplMode(bitfield<SuplMode> mode) generates (bool success); + + /* + * This setting configures how GPS functionalities should be locked when + * user turns off GPS On setting. + * + * @param lock Bitmask that specifies the GPS functionalities to be be + * locked as per the GpsLock enum. + * + * @return success True if operation was successful. + */ + setGpsLock(bitfield<GpsLock> lock) generates (bool success); + + /* + * This method sets the LTE Positioning Profile configuration. + * + * @param lppProfile Bitmask that specifies the LTE Positioning Profile + * configuration to be set as per the LppProfile enum. + * + * @return success True if operation was successful. + */ + setLppProfile(bitfield<LppProfile> lppProfile) generates (bool success); + + /* + * This method selects positioning protocol on A-Glonass system. + * + * @param protocol Bitmask that specifies the positioning protocol to be + * set as per GlonassPosProtocol enum. + * + * @return success True if operation was successful. + */ + setGlonassPositioningProtocol(bitfield<GlonassPosProtocol> protocol) generates (bool success); + + /* + * This method configures which PDN to use. + * + * @param enable Use emergency PDN if true and regular PDN if false. + * @return success True if operation was successful. + */ + setEmergencySuplPdn(bool enable) generates (bool success); +};
diff --git a/gnss/1.0/IGnssDebug.hal b/gnss/1.0/IGnssDebug.hal new file mode 100644 index 0000000..8784d1a --- /dev/null +++ b/gnss/1.0/IGnssDebug.hal
@@ -0,0 +1,139 @@ +package android.hardware.gnss@1.0; + +/* Extended interface for DEBUG support. */ +interface IGnssDebug { + enum SatelliteEphemerisType : uint8_t { + /* no information is known to the gnss hardware, about this satellite */ + UNKNOWN, + /* this satellite is known to exist */ + KNOWN, + /* this satellite is not known to exist */ + NONEXISTENT, + /* Only Almanac (approximate) location known for this satellite */ + ALMANAC_ONLY, + /* Ephemeris is known from demodulating the signal on device */ + DEMODULATED, + /* Ephemeris has been provided by SUPL */ + SUPL_PROVIDED, + /* Ephemeris has been provided by another server */ + OTHER_SERVER_PROVIDED, + /* + * Predicted ephemeris has been provided by a server + * (e.g. Xtra, Extended Ephemeris, etc...) + */ + SERVER_PREDICTED, + /* + * Predicted ephemeris in use, generated locally on the device (e.g. from prior + * ephemeris) + */ + LOCALLY_PREDICTED + }; + + /* + * Provides the current best known position from any + * source (GNSS or injected assistance). + */ + struct PositionDebug { + /* + * Validity of the data in this struct. False only if no + * latitude/longitude information is known. + */ + bool valid; + /* Latitude expressed in degrees */ + double latitudeDegrees; + /* Longitude expressed in degrees */ + double longitudeDegrees; + /* Altitude above ellipsoid expressed in meters */ + float altitudeMeters; + /* Represents speed in meters per second. */ + float speedMetersPerSec; + /* Represents heading in degrees. */ + float bearingDegrees; + /* + * estimated horizontal accuracy of position expressed in meters, radial, + * 68% confidence. + */ + double horizontalAccuracyMeters; + /* + * estimated vertical accuracy of position expressed in meters, with + * 68% confidence. + */ + double verticalAccuracyMeters; + /* + * estimated speed accuracy in meters per second with 68% confidence. + */ + double speedAccuracyMetersPerSecond; + /* + * estimated bearing accuracy degrees with 68% confidence. + */ + double bearingAccuracyDegrees; + /* + * Time duration before this report that this position information was + * valid. + */ + float ageSeconds; + }; + + /* + * Provides the current best known UTC time estimate. + */ + struct TimeDebug { + /* + * Validity of the data in the struct. + * False if current time is unknown. + */ + bool valid; + /* + * UTC time estimate. + */ + GnssUtcTime timeEstimate; + /* 68% error estimate in time. */ + float timeUncertaintyNs; + }; + + /* + * Provides a single satellite info that has decoded navigation data. + */ + struct SatelliteData { + /* Satellite vehicle ID number */ + int16_t svid; + /* Defines the constellation type of the given SV. */ + GnssConstellationType constellation; + /* Defines the ephemeris type of the satellite. */ + SatelliteEphemerisType ephemerisType; + /* + * Time duration before this report, that the ephemeris source was last + * updated, e.g. latest demodulation, or latest server download. + * Set to 0 when ephemerisType is UNKNOWN. + */ + float ephemerisAgeSeconds; + }; + + /* + * Provides a set of debug information that is filled by the GNSS chipset + * when the method getDebugData() is invoked. + */ + struct DebugData { + /* Current best known position. */ + PositionDebug position; + /* Current best know time estimate */ + TimeDebug time; + /* + * Provides a list of the decoded satellite ephemeris. + * Must provide a complete list for all constellations device can track, + * including GnssConstellationType UNKNOWN. + */ + vec<SatelliteData> satelliteDataArray; + + }; + + /* + * This methods requests position, time and satellite ephemeris debug information + * from the HAL. + * + * @return ret debugData information from GNSS Hal that contains the current best + * known position, best known time estimate and a complete list of + * constellations that the device can track. + */ + getDebugData() generates (DebugData debugData); +};
diff --git a/gnss/1.0/IGnssGeofenceCallback.hal b/gnss/1.0/IGnssGeofenceCallback.hal new file mode 100644 index 0000000..722317e --- /dev/null +++ b/gnss/1.0/IGnssGeofenceCallback.hal
@@ -0,0 +1,191 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +/* + * GNSS Geofence. + * There are 3 states associated with a Geofence: Inside, Outside, Unknown. + * There are 3 transitions: ENTERED, EXITED, UNCERTAIN. + * + * An example state diagram with confidence level: 95% and Unknown time limit + * set as 30 secs is shown below. (confidence level and Unknown time limit are + * explained latter). + * ____________________________ + * | Unknown (30 secs) | + * """""""""""""""""""""""""""" + * ^ | | ^ + * UNCERTAIN| |ENTERED EXITED| |UNCERTAIN + * | v v | + * ________ EXITED _________ + * | Inside | -----------> | Outside | + * | | <----------- | | + * """""""" ENTERED """"""""" + * + * Inside state: We are 95% confident that the user is inside the geofence. + * Outside state: We are 95% confident that the user is outside the geofence + * Unknown state: Rest of the time. + * + * The Unknown state is better explained with an example: + * + * __________ + * | c| + * | ___ | _______ + * | |a| | | b | + * | """ | """"""" + * | | + * """""""""" + * In the diagram above, "a" and "b" are 2 geofences and "c" is the accuracy + * circle reported by the GNSS subsystem. Now with regard to "b", the system is + * confident that the user is outside. But with regard to "a" is not confident + * whether it is inside or outside the geofence. If the accuracy remains the + * same for a sufficient period of time, the UNCERTAIN transition must be + * triggered with the state set to Unknown. If the accuracy improves later, an + * appropriate transition must be triggered. This "sufficient period of time" + * is defined by the parameter in the addGeofenceArea API. + * In other words, Unknown state can be interpreted as a state in which the + * GNSS subsystem isn't confident enough that the user is either inside or + * outside the Geofence. It moves to Unknown state only after the expiry of the + * timeout. + * + * The geofence callback needs to be triggered for the ENTERED and EXITED + * transitions, when the GNSS system is confident that the user has entered + * (Inside state) or exited (Outside state) the Geofence. An implementation + * which uses a value of 95% as the confidence is recommended. The callback + * must be triggered only for the transitions requested by the + * addGeofenceArea method. + * + * Even though the diagram and explanation talks about states and transitions, + * the callee is only interested in the transitions. The states are mentioned + * here for illustrative purposes. + * + * Startup Scenario: When the device boots up, if an application adds geofences, + * and then we get an accurate GNSS location fix, it needs to trigger the + * appropriate (ENTERED or EXITED) transition for every Geofence it knows about. + * By default, all the Geofences will be in the Unknown state. + * + * When the GNSS system is unavailable, gnssGeofenceStatusCb must be + * called to inform the upper layers of the same. Similarly, when it becomes + * available the callback must be called. This is a global state while the + * UNKNOWN transition described above is per geofence. + * + * An important aspect to note is that users of this API (framework), will use + * other subsystems like wifi, sensors, cell to handle Unknown case and + * hopefully provide a definitive state transition to the third party + * application. GNSS Geofence will just be a signal indicating what the GNSS + * subsystem knows about the Geofence. + * + */ + +interface IGnssGeofenceCallback { + @export(name="", value_prefix="GPS_GEOFENCE_") + enum GeofenceTransition : int32_t { + ENTERED = (1 << 0L), + EXITED = (1 << 1L), + UNCERTAIN = (1 << 2L), + }; + + @export(name="", value_prefix="GPS_GEOFENCE_") + enum GeofenceAvailability : int32_t { + UNAVAILABLE = (1 << 0L), + AVAILABLE = (1 << 1L), + }; + + @export(name="", value_prefix="GPS_GEOFENCE_") + enum GeofenceStatus : int32_t { + OPERATION_SUCCESS = 0, + ERROR_TOO_MANY_GEOFENCES = -100, + ERROR_ID_EXISTS = -101, + ERROR_ID_UNKNOWN = -102, + ERROR_INVALID_TRANSITION = -103, + ERROR_GENERIC = -149 + }; + + /* + * The callback associated with the geofence transition. + * The callback must only be called when the caller is interested in that + * particular transition. For instance, if the caller is interested only in + * ENTERED transition, then the callback must not be called with the EXITED + * transition. + * + * IMPORTANT: If a transition is triggered resulting in this callback, the + * GNSS subsystem will wake up the application processor, if its in suspend + * state. + * + * @param geofenceId The id associated with the addGeofenceArea. + * @param location The current GNSS location. + * @param transition Can be one of ENTERED, EXITED or UNCERTAIN. + * @param timestamp Timestamp when the transition was detected. + * + */ + gnssGeofenceTransitionCb(int32_t geofenceId, GnssLocation location, + GeofenceTransition transition, GnssUtcTime timestamp); + + /* + * The callback associated with the availability of the GNSS system for + * geofencing monitoring. If the GNSS system determines that it cannot monitor + * geofences because of lack of reliability or unavailability of the GNSS + * signals, it will call this callback with UNAVAILABLE parameter. + * + * @param status - UNAVAILABLE or AVAILABLE. + * @param lastLocation - Last known location. + */ + gnssGeofenceStatusCb(GeofenceAvailability status, GnssLocation lastLocation); + + /* + * The callback associated with the addGeofence call. + * + * @param geofenceId Id of the geofence. + * @param status Will be OPERATION_SUCCESS if the geofence + * add was successful. Will be ERROR_TOO_MANY_GEOFENCES if the + * geofence limit has been reached. + * Will be ERROR_ID_EXISTS if geofence with id already exists. + * Will be ERROR_INVALID_TRANSITION if the monitorTransition contains an + * invalid transition. + * Will be ERROR_GENERIC for other errors. + */ + gnssGeofenceAddCb(int32_t geofenceId, GeofenceStatus status); + + /* + * The callback associated with the removeGeofence call. + * + * @param geofenceId Id of the geofence. + * @param status Will return OPERATION_SUCCESS if successful. + * Will be ERROR_ID_UNKNOWN for invalid id and + * ERROR_GENERIC for others. + */ + gnssGeofenceRemoveCb(int32_t geofenceId, GeofenceStatus status); + + /* + * The callback associated with the pauseGeofence call. + * + * @param geofenceId Id of the geofence. + * @param status Will be OPERATION_SUCCESS if success. + * Will be ERROR_ID_UNKNOWN for invalid id. Will be + * ERROR_INVALID_TRANSITION when monitorTransitions is invalid. + * Will be ERROR_GENERIC for other err errors. + */ + gnssGeofencePauseCb(int32_t geofenceId, GeofenceStatus status); + + /* + * The callback associated with the resumeGeofence call. + * + * @param geofenceId - Id of the geofence. + * @param status Will be OPERATION_SUCCESS if successful. + * Will be ERROR_ID_UNKNOWN for invalid id and ERROR_GENERIC for others. + */ + gnssGeofenceResumeCb(int32_t geofenceId, GeofenceStatus status); +};
diff --git a/gnss/1.0/IGnssGeofencing.hal b/gnss/1.0/IGnssGeofencing.hal new file mode 100644 index 0000000..b8348b3 --- /dev/null +++ b/gnss/1.0/IGnssGeofencing.hal
@@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +import IGnssGeofenceCallback; + +/* Extended interface for GNSS Geofencing support */ +interface IGnssGeofencing { + /* + * Opens the geofence interface and provides the callback routines + * to the HAL. + * + * @param callback Handle to the IGnssGeofenceCallback interface. + */ + setCallback(IGnssGeofenceCallback callback); + + /* + * Add a geofence area. This api currently supports circular geofences. + * + * @param geofenceId The id for the geofence. If a geofence with this id + * already exists, an error value (ERROR_ID_EXISTS) must be returned. + * @param latitudeDegrees The latitude(in degrees) for the geofence lastTransition. + * @param longtitudeDegrees The longitude(in degrees) for the geofence lastTransition. + * @param radiusMeters The radius(in meters) for the geofence lastTransition. + * @param lastTransition The current state of the geofence. For example, if + * the system already knows that the user is inside the geofence, this will + * be set to ENTERED. In most cases, it will be UNCERTAIN. + * @param monitorTransitions - Which transitions to monitor. Bitwise OR of + * ENTERED, EXITED and UNCERTAIN. + * @param notificationResponsivenessMs - Defines the best-effort description + * of how soon must the callback be called when the transition associated + * with the Geofence is triggered. For instance, if set to 1000 millseconds + * with ENTERED, the callback must be called 1000 milliseconds within entering + * the geofence. This parameter is defined in milliseconds. + * NOTE: This is not to be confused with the rate that the GNSS is polled at. + * It is acceptable to dynamically vary the rate of sampling the GNSS for + * power-saving reasons; thus the rate of sampling may be faster or slower + * than this. + * @param unknownTimerMs - The time limit after which the UNCERTAIN transition + * must be triggered. This parameter is defined in milliseconds. + */ + addGeofence(int32_t geofenceId, double latitudeDegrees, double longitudeDegrees, + double radiusMeters, GeofenceTransition lastTransition, + bitfield<IGnssGeofenceCallback.GeofenceTransition> monitorTransitions, + uint32_t notificationResponsivenessMs, + uint32_t unknownTimerMs); + + /* + * Pause monitoring a particular geofence. + * + * @param geofenceId The id for the geofence. + */ + pauseGeofence(int32_t geofenceId); + + /* + * Resume monitoring a particular geofence. + * + * @param geofenceId - The id for the geofence. + * @param monitorTransitions Specifies which transitions to monitor. + * It can be a bitwise OR of ENTERED, EXITED and + * UNCERTAIN. This supersedes the value associated + * provided in the addGeofenceArea call. + */ + resumeGeofence(int32_t geofenceId, + bitfield<IGnssGeofenceCallback.GeofenceTransition> monitorTransitions); + + /* + * Remove a geofence area. After the function returns, no notifications + * must be sent. + * + * @param geofenceId The id of the geofence. + */ + removeGeofence(int32_t geofenceId); +};
diff --git a/gnss/1.0/IGnssMeasurement.hal b/gnss/1.0/IGnssMeasurement.hal new file mode 100644 index 0000000..8329442 --- /dev/null +++ b/gnss/1.0/IGnssMeasurement.hal
@@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +import IGnssMeasurementCallback; + +/* + * Extended interface for GNSS Measurements support. + */ +interface IGnssMeasurement { + @export(name="", value_prefix="GPS_MEASUREMENT_") + enum GnssMeasurementStatus : int32_t { + SUCCESS = 0, + ERROR_ALREADY_INIT = -100, + ERROR_GENERIC = -101 + }; + + /* + * Initializes the interface and registers the callback routines with the HAL. + * After a successful call to 'setCallback' the HAL must begin to provide updates at + * an average output rate of 1Hz (occasional + * intra-measurement time offsets in the range from 0-2000msec can be + * tolerated.) + * + * @param callback Handle to GnssMeasurement callback interface. + * + * @return initRet Returns SUCCESS if successful. + * Returns ERROR_ALREADY_INIT if a callback has already been + * registered without a corresponding call to 'close'. + * Returns ERROR_GENERIC for any other error. The HAL must + * not generate any other updates upon returning this error code. + */ + setCallback(IGnssMeasurementCallback callback) generates (GnssMeasurementStatus initRet); + + /* + * Stops updates from the HAL, and unregisters the callback routines. + * After a call to close(), the previously registered callbacks must be + * considered invalid by the HAL. + * If close() is invoked without a previous setCallback, this function must perform + * no work. + */ + close(); + +};
diff --git a/gnss/1.0/IGnssMeasurementCallback.hal b/gnss/1.0/IGnssMeasurementCallback.hal new file mode 100644 index 0000000..5789621 --- /dev/null +++ b/gnss/1.0/IGnssMeasurementCallback.hal
@@ -0,0 +1,609 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +/* The callback interface to report measurements from the HAL. */ +interface IGnssMeasurementCallback { + /* + * Flags to indicate what fields in GnssClock are valid. + */ + @export(name="", value_prefix="GNSS_CLOCK_") + enum GnssClockFlags : uint16_t { + /** A valid 'leap second' is stored in the data structure. */ + HAS_LEAP_SECOND = 1 << 0, + /** A valid 'time uncertainty' is stored in the data structure. */ + HAS_TIME_UNCERTAINTY = 1 << 1, + /** A valid 'full bias' is stored in the data structure. */ + HAS_FULL_BIAS = 1 << 2, + /** A valid 'bias' is stored in the data structure. */ + HAS_BIAS = 1 << 3, + /** A valid 'bias uncertainty' is stored in the data structure. */ + HAS_BIAS_UNCERTAINTY = 1 << 4, + /** A valid 'drift' is stored in the data structure. */ + HAS_DRIFT = 1 << 5, + /** A valid 'drift uncertainty' is stored in the data structure. */ + HAS_DRIFT_UNCERTAINTY = 1 << 6 + }; + + /* + * Flags to indicate what fields in GnssMeasurement are valid. + */ + @export(name="", value_prefix="GNSS_MEASUREMENT_") + enum GnssMeasurementFlags : uint32_t { + /** A valid 'snr' is stored in the data structure. */ + HAS_SNR = 1 << 0, + /** A valid 'carrier frequency' is stored in the data structure. */ + HAS_CARRIER_FREQUENCY = 1 << 9, + /** A valid 'carrier cycles' is stored in the data structure. */ + HAS_CARRIER_CYCLES = 1 << 10, + /** A valid 'carrier phase' is stored in the data structure. */ + HAS_CARRIER_PHASE = 1 << 11, + /** A valid 'carrier phase uncertainty' is stored in the data structure. */ + HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12, + /** A valid automatic gain control is stored in the data structure. */ + HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13 + }; + + /* + * Enumeration of available values for the GNSS Measurement's multipath + * indicator. + */ + @export(name="", value_prefix="GNSS_MULTIPATH_") + enum GnssMultipathIndicator : uint8_t { + /** The indicator is not available or unknown. */ + INDICATOR_UNKNOWN = 0, + /** The measurement is indicated to be affected by multipath. */ + INDICATOR_PRESENT = 1, + /** The measurement is indicated to be not affected by multipath. */ + INDICATIOR_NOT_PRESENT = 2 + }; + + /* + * Flags indicating the GNSS measurement state. + * + * The expected behavior here is for GNSS HAL to set all the flags that applies. + * For example, if the state for a satellite is only C/A code locked and bit + * synchronized, and there is still millisecond ambiguity, the state must be + * set as: + * + * STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_MSEC_AMBIGUOUS + * + * If GNSS is still searching for a satellite, the corresponding state must be + * set to STATE_UNKNOWN(0). + */ + @export(name="", value_prefix="GNSS_MEASUREMENT_") + enum GnssMeasurementState : uint32_t { + STATE_UNKNOWN = 0, + STATE_CODE_LOCK = 1 << 0, + STATE_BIT_SYNC = 1 << 1, + STATE_SUBFRAME_SYNC = 1 << 2, + STATE_TOW_DECODED = 1 << 3, + STATE_MSEC_AMBIGUOUS = 1 << 4, + STATE_SYMBOL_SYNC = 1 << 5, + STATE_GLO_STRING_SYNC = 1 << 6, + STATE_GLO_TOD_DECODED = 1 << 7, + STATE_BDS_D2_BIT_SYNC = 1 << 8, + STATE_BDS_D2_SUBFRAME_SYNC = 1 << 9, + STATE_GAL_E1BC_CODE_LOCK = 1 << 10, + STATE_GAL_E1C_2ND_CODE_LOCK = 1 << 11, + STATE_GAL_E1B_PAGE_SYNC = 1 << 12, + STATE_SBAS_SYNC = 1 << 13, + STATE_TOW_KNOWN = 1 << 14, + STATE_GLO_TOD_KNOWN = 1 << 15, + }; + + /* + * Flags indicating the Accumulated Delta Range's states. + */ + @export(name="", value_prefix="GNSS_") + enum GnssAccumulatedDeltaRangeState : uint16_t { + ADR_STATE_UNKNOWN = 0, + ADR_STATE_VALID = 1 << 0, + ADR_STATE_RESET = 1 << 1, + ADR_STATE_CYCLE_SLIP = 1 << 2, + }; + + /* + * Represents an estimate of the GNSS clock time. + */ + struct GnssClock { + /* + * A set of flags indicating the validity of the fields in this data + * structure. + */ + bitfield<GnssClockFlags> gnssClockFlags; + + /* + * Leap second data. + * The sign of the value is defined by the following equation: + * utcTimeNs = timeNs - (fullBiasNs + biasNs) - leapSecond * + * 1,000,000,000 + * + * If this data is available, gnssClockFlags must contain + * HAS_LEAP_SECOND. + */ + int16_t leapSecond; + + /* + * The GNSS receiver internal clock value. This is the local hardware clock + * value. + * + * For local hardware clock, this value is expected to be monotonically + * increasing while the hardware clock remains powered on. (For the case of a + * HW clock that is not continuously on, see the + * hwClockDiscontinuityCount field). The receiver's estimate of GNSS time + * can be derived by subtracting the sum of fullBiasNs and biasNs (when + * available) from this value. + * + * This GNSS time must be the best estimate of current GNSS time + * that GNSS receiver can achieve. + * + * Sub-nanosecond accuracy can be provided by means of the 'biasNs' field. + * The value contains the timeUncertaintyNs in it. + * + * This field is mandatory. + */ + int64_t timeNs; + + /* + * 1-Sigma uncertainty associated with the clock's time in nanoseconds. + * The uncertainty is represented as an absolute (single sided) value. + * + * If the data is available, gnssClockFlags must contain + * HAS_TIME_UNCERTAINTY. Ths value is ideally zero, as the time + * 'latched' by timeNs is defined as the reference clock vs. which all + * other times (and corresponding uncertainties) are measured. + */ + double timeUncertaintyNs; + + /* + * The difference between hardware clock ('time' field) inside GNSS receiver + * and the true GNSS time since 0000Z, January 6, 1980, in nanoseconds. + * + * The sign of the value is defined by the following equation: + * local estimate of GNSS time = timeNs - (fullBiasNs + biasNs) + * + * This value is mandatory if the receiver has estimated GNSS time. If the + * computed time is for a non-GNSS constellation, the time offset of that + * constellation to GNSS has to be applied to fill this value. The error + * estimate for the sum of this and the biasNs is the biasUncertaintyNs, + * and the caller is responsible for using this uncertainty (it can be very + * large before the GNSS time has been solved for.) If the data is available + * gnssClockFlags must contain HAS_FULL_BIAS. + */ + int64_t fullBiasNs; + + /* + * Sub-nanosecond bias. + * The error estimate for the sum of this and the fullBiasNs is the + * biasUncertaintyNs. + * + * If the data is available gnssClockFlags must contain HAS_BIAS. If GNSS + * has computed a position fix. This value is mandatory if the receiver has + * estimated GNSS time. + */ + double biasNs; + + /* + * 1-Sigma uncertainty associated with the local estimate of GNSS time (clock + * bias) in nanoseconds. The uncertainty is represented as an absolute + * (single sided) value. + * + * If the data is available gnssClockFlags must contain + * HAS_BIAS_UNCERTAINTY. This value is mandatory if the receiver + * has estimated GNSS time. + */ + double biasUncertaintyNs; + + /* + * The clock's drift in nanoseconds (per second). + * + * A positive value means that the frequency is higher than the nominal + * frequency, and that the (fullBiasNs + biasNs) is growing more positive + * over time. + * + * The value contains the 'drift uncertainty' in it. + * If the data is available gnssClockFlags must contain HAS_DRIFT. + * + * This value is mandatory if the receiver has estimated GNSS time. + */ + double driftNsps; + + /* + * 1-Sigma uncertainty associated with the clock's drift in nanoseconds (per + * second). + * The uncertainty is represented as an absolute (single sided) value. + * + * If the data is available gnssClockFlags must contain + * HAS_DRIFT_UNCERTAINTY. If GNSS has computed a position fix this + * field is mandatory and must be populated. + */ + double driftUncertaintyNsps; + + /* + * When there are any discontinuities in the HW clock, this field is + * mandatory. + * + * A "discontinuity" is meant to cover the case of a switch from one source + * of clock to another. A single free-running crystal oscillator (XO) + * will generally not have any discontinuities, and this can be set and + * left at 0. + * + * If, however, the timeNs value (HW clock) is derived from a composite of + * sources, that is not as smooth as a typical XO, or is otherwise stopped & + * restarted, then this value shall be incremented each time a discontinuity + * occurs. (E.g. this value can start at zero at device boot-up and + * increment each time there is a change in clock continuity. In the + * unlikely event that this value reaches full scale, rollover (not + * clamping) is required, such that this value continues to change, during + * subsequent discontinuity events.) + * + * While this number stays the same, between GnssClock reports, it can be + * safely assumed that the timeNs value has been running continuously, e.g. + * derived from a single, high quality clock (XO like, or better, that is + * typically used during continuous GNSS signal sampling.) + * + * It is expected, esp. during periods where there are few GNSS signals + * available, that the HW clock be discontinuity-free as long as possible, + * as this avoids the need to use (waste) a GNSS measurement to fully + * re-solve for the GNSS clock bias and drift, when using the accompanying + * measurements, from consecutive GnssData reports. + */ + uint32_t hwClockDiscontinuityCount; + + }; + + /* + * Represents a GNSS Measurement, it contains raw and computed information. + * + * All signal measurement information (e.g. svTime, + * pseudorangeRate, multipathIndicator) reported in this struct must be + * based on GNSS signal measurements only. You must not synthesize measurements + * by calculating or reporting expected measurements based on known or estimated + * position, velocity, or time. + */ + struct GnssMeasurement{ + /* + * A set of flags indicating the validity of the fields in this data + * structure. + */ + bitfield<GnssMeasurementFlags> flags; + + /* + * Satellite vehicle ID number, as defined in GnssSvInfo::svid + * This is a mandatory value. + */ + int16_t svid; + + /* + * Defines the constellation of the given SV. + */ + GnssConstellationType constellation; + + /* + * Time offset at which the measurement was taken in nanoseconds. + * The reference receiver's time is specified by GnssData::clock::timeNs. + * + * The sign of timeOffsetNs is given by the following equation: + * measurement time = GnssClock::timeNs + timeOffsetNs + * + * It provides an individual time-stamp for the measurement, and allows + * sub-nanosecond accuracy. + * This is a mandatory value. + */ + double timeOffsetNs; + + /* + * Per satellite sync state. It represents the current sync state for the + * associated satellite. + * Based on the sync state, the 'received GNSS tow' field must be interpreted + * accordingly. + * + * This is a mandatory value. + */ + bitfield<GnssMeasurementState> state; + + /* + * The received GNSS Time-of-Week at the measurement time, in nanoseconds. + * For GNSS & QZSS, this is the received GNSS Time-of-Week at the + * measurement time, in nanoseconds. The value is relative to the + * beginning of the current GNSS week. + * + * Given the highest sync state that can be achieved, per each satellite, + * valid range for this field can be: + * Searching : [ 0 ] : STATE_UNKNOWN + * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK set + * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC set + * Subframe sync : [ 0 6s ] : STATE_SUBFRAME_SYNC set + * TOW decoded : [ 0 1week ] : STATE_TOW_DECODED set + * TOW Known : [ 0 1week ] : STATE_TOW_KNOWN set + * + * Note: TOW Known refers to the case where TOW is possibly not decoded + * over the air but has been determined from other sources. If TOW + * decoded is set then TOW Known must also be set. + * + * Note: If there is any ambiguity in integer millisecond, + * GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS must be set accordingly, in the + * 'state' field. + * + * This value must be populated if 'state' != STATE_UNKNOWN. + * + * For Glonass, this is the received Glonass time of day, at the + * measurement time in nanoseconds. + * + * Given the highest sync state that can be achieved, per each satellite, + * valid range for this field can be: + * Searching : [ 0 ] : STATE_UNKNOWN set + * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK set + * Symbol sync : [ 0 10ms ] : STATE_SYMBOL_SYNC set + * Bit sync : [ 0 20ms ] : STATE_BIT_SYNC set + * String sync : [ 0 2s ] : STATE_GLO_STRING_SYNC set + * Time of day decoded : [ 0 1day ] : STATE_GLO_TOD_DECODED set + * Time of day known : [ 0 1day ] : STATE_GLO_TOD_KNOWN set + * + * Note: Time of day known refers to the case where it is possibly not + * decoded over the air but has been determined from other sources. If + * Time of day decoded is set then Time of day known must also be set. + * + * For Beidou, this is the received Beidou time of week, + * at the measurement time in nanoseconds. + * + * Given the highest sync state that can be achieved, per each satellite, + * valid range for this field can be: + * Searching : [ 0 ] : STATE_UNKNOWN set. + * C/A code lock : [ 0 1ms ] : STATE_CODE_LOCK set. + * Bit sync (D2) : [ 0 2ms ] : STATE_BDS_D2_BIT_SYNC set. + * Bit sync (D1) : [ 0 20ms ] : STATE_BIT_SYNC set. + * Subframe (D2) : [ 0 0.6s ] : STATE_BDS_D2_SUBFRAME_SYNC set. + * Subframe (D1) : [ 0 6s ] : STATE_SUBFRAME_SYNC set. + * Time of week decoded : [ 0 1week ] : STATE_TOW_DECODED set. + * Time of week known : [ 0 1week ] : STATE_TOW_KNOWN set + * + * Note: TOW Known refers to the case where TOW is possibly not decoded + * over the air but has been determined from other sources. If TOW + * decoded is set then TOW Known must also be set. + * + * For Galileo, this is the received Galileo time of week, + * at the measurement time in nanoseconds. + * + * E1BC code lock : [ 0 4ms ] : STATE_GAL_E1BC_CODE_LOCK set. + * E1C 2nd code lock : [ 0 100ms] : STATE_GAL_E1C_2ND_CODE_LOCK set. + * E1B page : [ 0 2s ] : STATE_GAL_E1B_PAGE_SYNC set. + * Time of week decoded : [ 0 1week] : STATE_TOW_DECODED is set. + * Time of week known : [ 0 1week] : STATE_TOW_KNOWN set + * + * Note: TOW Known refers to the case where TOW is possibly not decoded + * over the air but has been determined from other sources. If TOW + * decoded is set then TOW Known must also be set. + * + * For SBAS, this is received SBAS time, at the measurement time in + * nanoseconds. + * + * Given the highest sync state that can be achieved, per each satellite, + * valid range for this field can be: + * Searching : [ 0 ] : STATE_UNKNOWN + * C/A code lock: [ 0 1ms ] : STATE_CODE_LOCK is set + * Symbol sync : [ 0 2ms ] : STATE_SYMBOL_SYNC is set + * Message : [ 0 1s ] : STATE_SBAS_SYNC is set + */ + int64_t receivedSvTimeInNs; + + /* + * 1-Sigma uncertainty of the Received GNSS Time-of-Week in nanoseconds. + * + * This value must be populated if 'state' != STATE_UNKNOWN. + */ + int64_t receivedSvTimeUncertaintyInNs; + + /* + * Carrier-to-noise density in dB-Hz, typically in the range [0, 63]. + * It contains the measured C/N0 value for the signal at the antenna port. + * + * This is a mandatory value. + */ + double cN0DbHz; + + /* + * Pseudorange rate at the timestamp in m/s. The correction of a given + * Pseudorange Rate value includes corrections for receiver and satellite + * clock frequency errors. Ensure that this field is independent (see + * comment at top of GnssMeasurement struct.) + * + * It is mandatory to provide the 'uncorrected' 'pseudorange rate', and + * provide GnssClock's 'drift' field as well. When providing the + * uncorrected pseudorange rate, do not apply the corrections described above.) + * + * The value includes the 'pseudorange rate uncertainty' in it. + * A positive 'uncorrected' value indicates that the SV is moving away from + * the receiver. + * + * The sign of the 'uncorrected' 'pseudorange rate' and its relation to the + * sign of 'doppler shift' is given by the equation: + * pseudorange rate = -k * doppler shift (where k is a constant) + * + * This must be the most accurate pseudorange rate available, based on + * fresh signal measurements from this channel. + * + * It is mandatory that this value be provided at typical carrier phase PRR + * quality (few cm/sec per second of uncertainty, or better) - when signals + * are sufficiently strong & stable, e.g. signals from a GNSS simulator at >= + * 35 dB-Hz. + */ + double pseudorangeRateMps; + + /* + * 1-Sigma uncertainty of the pseudorangeRateMps. + * The uncertainty is represented as an absolute (single sided) value. + * + * This is a mandatory value. + */ + double pseudorangeRateUncertaintyMps; + + /* + * Accumulated delta range's state. It indicates whether ADR is reset or + * there is a cycle slip(indicating loss of lock). + * + * This is a mandatory value. + */ + bitfield<GnssAccumulatedDeltaRangeState> accumulatedDeltaRangeState; + + /* + * Accumulated delta range since the last channel reset in meters. + * A positive value indicates that the SV is moving away from the receiver. + * + * The sign of the 'accumulated delta range' and its relation to the sign of + * 'carrier phase' is given by the equation: + * accumulated delta range = -k * carrier phase (where k is a constant) + * + * This value must be populated if 'accumulated delta range state' != + * ADR_STATE_UNKNOWN. + * However, it is expected that the data is only accurate when: + * 'accumulated delta range state' == ADR_STATE_VALID. + */ + double accumulatedDeltaRangeM; + + /* + * 1-Sigma uncertainty of the accumulated delta range in meters. + * This value must be populated if 'accumulated delta range state' != + * ADR_STATE_UNKNOWN. + */ + double accumulatedDeltaRangeUncertaintyM; + + /* + * Carrier frequency of the signal tracked, for example it can be the + * GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz, L5 = + * 1176.45 MHz, varying GLO channels, etc. If the field is not set, it + * is the primary common use central frequency, e.g. L1 = 1575.45 MHz + * for GPS. + * + * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same + * time, two raw measurement structs must be reported for this same + * satellite, in one of the measurement structs, all the values related + * to L1 must be filled, and in the other all of the values related to + * L5 must be filled. + * + * If the data is available, gnssClockFlags must contain + * HAS_CARRIER_FREQUENCY. + */ + float carrierFrequencyHz; + + /* + * The number of full carrier cycles between the satellite and the + * receiver. The reference frequency is given by the field + * 'carrierFrequencyHz'. Indications of possible cycle slips and + * resets in the accumulation of this value can be inferred from the + * accumulatedDeltaRangeState flags. + * + * If the data is available, gnssClockFlags must contain + * HAS_CARRIER_CYCLES. + */ + int64_t carrierCycles; + + /* + * The RF phase detected by the receiver, in the range [0.0, 1.0]. + * This is usually the fractional part of the complete carrier phase + * measurement. + * + * The reference frequency is given by the field 'carrierFrequencyHz'. + * The value contains the 'carrier-phase uncertainty' in it. + * + * If the data is available, gnssClockFlags must contain + * HAS_CARRIER_PHASE. + */ + double carrierPhase; + + /* + * 1-Sigma uncertainty of the carrier-phase. + * If the data is available, gnssClockFlags must contain + * HAS_CARRIER_PHASE_UNCERTAINTY. + */ + double carrierPhaseUncertainty; + + /* + * An enumeration that indicates the 'multipath' state of the event. + * + * The multipath Indicator is intended to report the presence of overlapping + * signals that manifest as distorted correlation peaks. + * + * - if there is a distorted correlation peak shape, report that multipath + * is MULTIPATH_INDICATOR_PRESENT. + * - if there is no distorted correlation peak shape, report + * MULTIPATH_INDICATOR_NOT_PRESENT + * - if signals are too weak to discern this information, report + * MULTIPATH_INDICATOR_UNKNOWN + * + * Example: when doing the standardized overlapping Multipath Performance + * test (3GPP TS 34.171) the Multipath indicator must report + * MULTIPATH_INDICATOR_PRESENT for those signals that are tracked, and + * contain multipath, and MULTIPATH_INDICATOR_NOT_PRESENT for those + * signals that are tracked and do not contain multipath. + */ + GnssMultipathIndicator multipathIndicator; + + /* + * Signal-to-noise ratio at correlator output in dB. + * If the data is available, gnssClockFlags must contain MEASUREMENT_HAS_SNR. + * This is the power ratio of the "correlation peak height above the + * observed noise floor" to "the noise RMS". + */ + double snrDb; + + /* + * Automatic gain control (AGC) level. AGC acts as a variable gain + * amplifier adjusting the power of the incoming signal. The AGC level + * may be used to indicate potential interference. When AGC is at a + * nominal level, this value must be set as 0. Higher gain (and/or lower + * input power) must be output as a positive number. Hence in cases of + * strong jamming, in the band of this signal, this value must go more + * negative. + * + * Note: Different hardware designs (e.g. antenna, pre-amplification, or + * other RF HW components) may also affect the typical output of of this + * value on any given hardware design in an open sky test - the + * important aspect of this output is that changes in this value are + * indicative of changes on input signal power in the frequency band for + * this measurement. + */ + double agcLevelDb; + }; + + /* + * Represents a reading of GNSS measurements. For devices where GnssSystemInfo's + * yearOfHw is set to 2016+, it is mandatory that these be provided, on + * request, when the GNSS receiver is searching/tracking signals. + * + * - Reporting of GNSS constellation measurements is mandatory. + * - Reporting of all tracked constellations are encouraged. + */ + struct GnssData { + /* Number of GnssMeasurement elements. */ + uint32_t measurementCount; + + /* The array of measurements. */ + GnssMeasurement[GnssMax:SVS_COUNT] measurements; + + /** The GNSS clock time reading. */ + GnssClock clock; + }; + + /* + * Callback for the hal to pass a GnssData structure back to the client. + * + * @param data Contains a reading of GNSS measurements. + */ + GnssMeasurementCb(GnssData data); +};
diff --git a/gnss/1.0/IGnssNavigationMessage.hal b/gnss/1.0/IGnssNavigationMessage.hal new file mode 100644 index 0000000..ddd9169 --- /dev/null +++ b/gnss/1.0/IGnssNavigationMessage.hal
@@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +import IGnssNavigationMessageCallback; + +/* + * Extended interface for GNSS navigation message reporting support. + */ +interface IGnssNavigationMessage { + @export(name="", value_prefix="GPS_NAVIGATION_MESSAGE_") + enum GnssNavigationMessageStatus : int32_t { + SUCCESS = 0, + ERROR_ALREADY_INIT = -100, + ERROR_GENERIC = -101 + }; + + /* + * Initializes the interface and registers the callback routines with the HAL. + * After a successful call to 'setCallback' the HAL must begin to provide updates as + * they become available. + * @param callback handle to IGnssNavigationMessageCallack interface. + * + * @return initRet Returns SUCCESS if the operation + * is successful. + * Returns ERROR_ALREADY_INIT if a callback has + * already been registered without a corresponding call to close(). + * Returns ERROR_GENERIC if any other error occurred. It is + * expected that the HAL will not generate any updates upon returning + * this error code. + */ + setCallback(IGnssNavigationMessageCallback callback) generates (GnssNavigationMessageStatus initRet); + + /* + * Stops updates from the HAL, and unregisters the callback routines. + * After a call to close(), the previously registered callbacks must be + * considered invalid by the HAL. + * If close() is invoked without a previous setCallback, this function must perform + * no work. + */ + close(); +};
diff --git a/gnss/1.0/IGnssNavigationMessageCallback.hal b/gnss/1.0/IGnssNavigationMessageCallback.hal new file mode 100644 index 0000000..2e6b853 --- /dev/null +++ b/gnss/1.0/IGnssNavigationMessageCallback.hal
@@ -0,0 +1,168 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +/** Represents a GNSS navigation message (or a fragment of it). */ +interface IGnssNavigationMessageCallback { + /* + * Enumeration of available values to indicate the GNSS Navigation message + * types. + * + * For convenience, first byte is the GnssConstellationType on which that signal + * is typically transmitted. + */ + @export(name="", value_prefix="GNSS_NAVIGATION_MESSAGE_TYPE_") + enum GnssNavigationMessageType : int16_t { + UNKNOWN = 0, + /** GNSS L1 C/A message contained in the structure. */ + GNSS_L1CA = 0x0101, + /** GNSS L2-CNAV message contained in the structure. */ + GNSS_L2CNAV = 0x0102, + /** GNSS L5-CNAV message contained in the structure. */ + GNSS_L5CNAV = 0x0103, + /** GNSS CNAV-2 message contained in the structure. */ + GNSS_CNAV2 = 0x0104, + /** Glonass L1 CA message contained in the structure. */ + GLO_L1CA = 0x0301, + /** Beidou D1 message contained in the structure. */ + BDS_D1 = 0x0501, + /** Beidou D2 message contained in the structure. */ + BDS_D2 = 0x0502, + /** Galileo I/NAV message contained in the structure. */ + GAL_I = 0x0601, + /** Galileo F/NAV message contained in the structure. */ + GAL_F = 0x0602 + }; + + /* + * Status of Navigation Message + * When a message is received properly without any parity error in its + * navigation words, the status must be set to PARITY_PASSED. But if a message is + * received with words that failed parity check, but GNSS is able to correct + * those words, the status must be set to PARITY_REBUILT. + * No need to send any navigation message that contains words with parity error + * and cannot be corrected. + */ + @export(name="navigation_message_status", value_prefix="NAV_MESSAGE_STATUS_") + enum NavigationMessageStatus : uint16_t { + PARITY_PASSED = (1 << 0), + PARITY_REBUILT = (1 << 1), + UNKNOWN = 0 + }; + + struct GnssNavigationMessage { + /* + * Satellite vehicle ID number, as defined in GnssSvInfo::svid + * This is a mandatory value. + */ + int16_t svid; + + /* + * The type of message contained in the structure. + * This is a mandatory value. + */ + GnssNavigationMessageType type; + + /* + * The status of the received navigation message. + * No need to send any navigation message that contains words with parity + * error and cannot be corrected. + */ + bitfield<NavigationMessageStatus> status; + + /* + * Message identifier. It provides an index so the complete Navigation + * Message can be assembled. + * + * - For GNSS L1 C/A subframe 4 and 5, this value corresponds to the 'frame + * id' of the navigation message, in the range of 1-25 (Subframe 1, 2, 3 + * does not contain a 'frame id' and this value can be set to -1.) + * + * - For Glonass L1 C/A, this refers to the frame ID, in the range of 1-5. + * + * - For BeiDou D1, this refers to the frame number in the range of 1-24 + * + * - For Beidou D2, this refers to the frame number, in the range of 1-120 + * + * - For Galileo F/NAV nominal frame structure, this refers to the subframe + * number, in the range of 1-12 + * + * - For Galileo I/NAV nominal frame structure, this refers to the subframe + * number in the range of 1-24 + */ + int16_t messageId; + + /* + * Sub-message identifier. If required by the message 'type', this value + * contains a sub-index within the current message (or frame) that is being + * transmitted. + * + * - For GNSS L1 C/A, BeiDou D1 & BeiDou D2, the submessage id corresponds to + * the subframe number of the navigation message, in the range of 1-5. + * + * - For Glonass L1 C/A, this refers to the String number, in the range from + * 1-15 + * + * - For Galileo F/NAV, this refers to the page type in the range 1-6 + * + * - For Galileo I/NAV, this refers to the word type in the range 1-10+ + */ + int16_t submessageId; + + /* + * The data of the reported GNSS message. The bytes (or words) are specified + * using big endian format (MSB first). The data is stored and decoded + * in a server for research purposes. + * + * - For GNSS L1 C/A, Beidou D1 & Beidou D2, each subframe contains 10 30-bit + * words. Each word (30 bits) must fit into the last 30 bits in a + * 4-byte word (skip B31 and B32), with MSB first, for a total of 40 + * bytes, covering a time period of 6, 6, and 0.6 seconds, respectively. + * The standard followed is 1995 SPS Signal specification. + * + * - For Glonass L1 C/A, each string contains 85 data bits, including the + * checksum. These bits must fit into 11 bytes, with MSB first (skip + * B86-B88), covering a time period of 2 seconds. + * The standard followed is Glonass Interface Control Document Edition 5.1. + * + * - For Galileo F/NAV, each word consists of 238-bit (sync & tail symbols + * excluded). Each word must fit into 30-bytes, with MSB first (skip + * B239, B240), covering a time period of 10 seconds. The standard + * followed is European GNSS(Galileo) Signal in Space Interface + * Control Document Issue 1.2. + * + * - For Galileo I/NAV, each page contains 2 page parts, even and odd, with + * a total of 2x114 = 228 bits, (sync & tail excluded) that must fit + * into 29 bytes, with MSB first (skip B229-B232). The standard followed + * is same as above. + * + * TODO(b/32022567): Describe this relationship with data to the VTS + * via custom annotations and plug in a VTS test to verify that the data + * correctly follows the standard. + * + */ + vec<uint8_t> data; + }; + + /* + * The callback to report an available fragment of a GNSS navigation messages + * from the HAL. + * + * @param message - The GNSS navigation submessage/subframe representation. + */ + gnssNavigationMessageCb(GnssNavigationMessage message); +};
diff --git a/gnss/1.0/IGnssNi.hal b/gnss/1.0/IGnssNi.hal new file mode 100644 index 0000000..c823bf0 --- /dev/null +++ b/gnss/1.0/IGnssNi.hal
@@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; +import IGnssNiCallback; + +/* + * Extended interface for Network-initiated (NI) support. This interface is used + * to respond to NI notifications originating from the HAL. + */ +interface IGnssNi { + /* + * Registers the callbacks for HAL to use. + * + * @param callback handle to IGnssNiCallback interface. + */ + setCallback(IGnssNiCallback callback); + + /* + * Sends a response to HAL. + * + * @param notifId An ID generated by HAL to associate NI notifications and + * framework responses. + * @param userResponse A GNSS Ni response indicating if the notification was + * accepted, denied or not responded to. + */ + respond(int32_t notifId, GnssUserResponseType userResponse); +};
diff --git a/gnss/1.0/IGnssNiCallback.hal b/gnss/1.0/IGnssNiCallback.hal new file mode 100644 index 0000000..c5fb223 --- /dev/null +++ b/gnss/1.0/IGnssNiCallback.hal
@@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +/* GNSS Network Initiated callback interface. */ +interface IGnssNiCallback { + /* + * GnssNiType constants + */ + @export(name="", value_prefix="GPS_NI_TYPE_") + enum GnssNiType : uint8_t { + VOICE = 1, + UMTS_SUPL = 2, + UMTS_CTRL_PLANE = 3 + }; + + /* + * GnssNiNotifyFlags constants + */ + @export(name="", value_prefix="GPS_NI_") + enum GnssNiNotifyFlags : uint32_t { + /** NI requires notification */ + NEED_NOTIFY = 0x0001, + /** NI requires verification */ + NEED_VERIFY = 0x0002, + /** NI requires privacy override, no notification/minimal trace */ + PRIVACY_OVERRIDE = 0x0004, + }; + + /* + * GNSS NI responses, used to define the response in + * NI structures + */ + @export(name="", value_prefix="GPS_NI_") + enum GnssUserResponseType : uint8_t { + RESPONSE_ACCEPT = 1, + RESPONSE_DENY = 2, + RESPONSE_NORESP = 3, + }; + + /* + * NI data encoding scheme + */ + @export(name="", value_prefix="GPS_") + enum GnssNiEncodingType : int32_t { + ENC_NONE = 0, + ENC_SUPL_GSM_DEFAULT = 1, + ENC_SUPL_UTF8 = 2, + ENC_SUPL_UCS2 = 3, + ENC_UNKNOWN = -1, + }; + + /** Represents an NI request */ + struct GnssNiNotification{ + /* + * An ID generated by HAL to associate NI notifications and UI + * responses. + */ + int32_t notificationId; + + /* + * A type used to distinguish different categories of NI + * events, such as VOICE, UMTS_SUPL etc. + */ + GnssNiType niType; + + /* + * Notification/verification options, combinations of GnssNiNotifyFlags + * constants. + */ + bitfield<GnssNiNotifyFlags> notifyFlags; + + /* + * Timeout period to wait for user response. + * Set to 0 for no timeout limit. Specified in seconds. + */ + uint32_t timeoutSec; + + /* + * Default response when timeout. + */ + GnssUserResponseType defaultResponse; + + /* + * String representing the requester of the network inititated location + * request. + */ + string requestorId; + + /* + * Notification message. String representing the service(for eg. SUPL-service) + * who sent the network initiated location request. + */ + string notificationMessage; + + /* + * requestorId decoding scheme. + */ + GnssNiEncodingType requestorIdEncoding; + + /* + * notificationId decoding scheme + */ + GnssNiEncodingType notificationIdEncoding; + }; + + /* + * Callback with a network initiated request. + * + * @param notification network initiated request. + */ + niNotifyCb(GnssNiNotification notification); +};
diff --git a/gnss/1.0/IGnssXtra.hal b/gnss/1.0/IGnssXtra.hal new file mode 100644 index 0000000..5222fde --- /dev/null +++ b/gnss/1.0/IGnssXtra.hal
@@ -0,0 +1,27 @@ +package android.hardware.gnss@1.0; +import IGnssXtraCallback; + +/* + * This interface is used by the GNSS HAL to request the framework + * to download XTRA data. + */ +interface IGnssXtra { + /* + * Opens the XTRA interface and provides the callback routines + * to the implementation of this interface. + * + * @param callback Handle to the IGnssXtraCallback interface. + * + * @return success True if the operation is successful. + */ + setCallback(IGnssXtraCallback callback) generates (bool success); + + /* + * Inject the downloaded XTRA data into the GNSS receiver. + * + * @param xtraData GNSS XTRA data. + * + * @return success True if the operation is successful. + */ + injectXtraData(string xtraData) generates (bool success); +};
diff --git a/gnss/1.0/IGnssXtraCallback.hal b/gnss/1.0/IGnssXtraCallback.hal new file mode 100644 index 0000000..42df082 --- /dev/null +++ b/gnss/1.0/IGnssXtraCallback.hal
@@ -0,0 +1,12 @@ +package android.hardware.gnss@1.0; + +/* + * This interface is used by the GNSS HAL to request download of XTRA data. + */ +interface IGnssXtraCallback { + /* + * Callback to request the client to download XTRA data. The client should + * download XTRA data and inject it by calling injectXtraData(). + */ + downloadRequestCb(); +};
diff --git a/gnss/1.0/default/AGnss.cpp b/gnss/1.0/default/AGnss.cpp new file mode 100644 index 0000000..29c6ddd --- /dev/null +++ b/gnss/1.0/default/AGnss.cpp
@@ -0,0 +1,198 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_AGnssInterface" + +#include "AGnss.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +std::vector<std::unique_ptr<ThreadFuncArgs>> AGnss::sThreadFuncArgsList; +sp<IAGnssCallback> AGnss::sAGnssCbIface = nullptr; +bool AGnss::sInterfaceExists = false; + +AGpsCallbacks AGnss::sAGnssCb = { + .status_cb = statusCb, + .create_thread_cb = createThreadCb +}; + +AGnss::AGnss(const AGpsInterface* aGpsIface) : mAGnssIface(aGpsIface) { + /* Error out if an instance of the interface already exists. */ + LOG_ALWAYS_FATAL_IF(sInterfaceExists); + sInterfaceExists = true; +} + +AGnss::~AGnss() { + sThreadFuncArgsList.clear(); + sInterfaceExists = false; +} + +void AGnss::statusCb(AGpsStatus* status) { + if (sAGnssCbIface == nullptr) { + ALOGE("%s: AGNSS Callback Interface configured incorrectly", __func__); + return; + } + + if (status == nullptr) { + ALOGE("AGNSS status is invalid"); + return; + } + + /* + * Logic based on AGnssStatus processing by GnssLocationProvider. Size of + * AGpsStatus is checked for backward compatibility since some devices may + * be sending out an older version of AGpsStatus that only supports IPv4. + */ + size_t statusSize = status->size; + if (status->size == sizeof(AGpsStatus)) { + switch (status->addr.ss_family) + { + case AF_INET: + { + /* + * ss_family indicates IPv4. + */ + struct sockaddr_in* in = reinterpret_cast<struct sockaddr_in*>(&(status->addr)); + IAGnssCallback::AGnssStatusIpV4 aGnssStatusIpV4 = { + .type = static_cast<IAGnssCallback::AGnssType>(status->type), + .status = static_cast<IAGnssCallback::AGnssStatusValue>(status->status), + .ipV4Addr = in->sin_addr.s_addr, + }; + + /* + * Callback to client with agnssStatusIpV4Cb. + */ + auto ret = sAGnssCbIface->agnssStatusIpV4Cb(aGnssStatusIpV4); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + break; + } + case AF_INET6: + { + /* + * ss_family indicates IPv6. Callback to client with agnssStatusIpV6Cb. + */ + IAGnssCallback::AGnssStatusIpV6 aGnssStatusIpV6; + + aGnssStatusIpV6.type = static_cast<IAGnssCallback::AGnssType>(status->type); + aGnssStatusIpV6.status = static_cast<IAGnssCallback::AGnssStatusValue>( + status->status); + + struct sockaddr_in6* in6 = reinterpret_cast<struct sockaddr_in6 *>( + &(status->addr)); + memcpy(&(aGnssStatusIpV6.ipV6Addr[0]), in6->sin6_addr.s6_addr, + aGnssStatusIpV6.ipV6Addr.size()); + auto ret = sAGnssCbIface->agnssStatusIpV6Cb(aGnssStatusIpV6); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + break; + } + default: + ALOGE("Invalid ss_family found: %d", status->addr.ss_family); + } + } else if (statusSize >= sizeof(AGpsStatus_v2)) { + AGpsStatus_v2* statusV2 = reinterpret_cast<AGpsStatus_v2*>(status); + uint32_t ipV4Addr = statusV2->ipaddr; + IAGnssCallback::AGnssStatusIpV4 aGnssStatusIpV4 = { + .type = static_cast<IAGnssCallback::AGnssType>(AF_INET), + .status = static_cast<IAGnssCallback::AGnssStatusValue>(status->status), + /* + * For older versions of AGpsStatus, change IP addr to net order. This + * was earlier being done in GnssLocationProvider. + */ + .ipV4Addr = htonl(ipV4Addr) + }; + /* + * Callback to client with agnssStatusIpV4Cb. + */ + auto ret = sAGnssCbIface->agnssStatusIpV4Cb(aGnssStatusIpV4); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + } else { + ALOGE("%s: Invalid size for AGPS Status", __func__); + } +} + +pthread_t AGnss::createThreadCb(const char* name, void (*start)(void*), void* arg) { + return createPthread(name, start, arg, &sThreadFuncArgsList); +} + +/* + * Implementation of methods from ::android::hardware::gnss::V1_0::IAGnss follow. + */ +Return<void> AGnss::setCallback(const sp<IAGnssCallback>& callback) { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return Void(); + } + + sAGnssCbIface = callback; + + mAGnssIface->init(&sAGnssCb); + return Void(); +} + +Return<bool> AGnss::dataConnClosed() { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return false; + } + + return (mAGnssIface->data_conn_closed() == 0); +} + +Return<bool> AGnss::dataConnFailed() { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return false; + } + + return (mAGnssIface->data_conn_failed() == 0); +} + +Return<bool> AGnss::setServer(IAGnssCallback::AGnssType type, + const hidl_string& hostname, + int32_t port) { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return false; + } + + return (mAGnssIface->set_server(static_cast<AGpsType>(type), hostname.c_str(), port) == 0); +} + +Return<bool> AGnss::dataConnOpen(const hidl_string& apn, IAGnss::ApnIpType apnIpType) { + if (mAGnssIface == nullptr) { + ALOGE("%s: AGnss interface is unavailable", __func__); + return false; + } + + return (mAGnssIface->data_conn_open_with_apn_ip_type(apn.c_str(), + static_cast<uint16_t>(apnIpType)) == 0); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/AGnss.h b/gnss/1.0/default/AGnss.h new file mode 100644 index 0000000..2a8eed0 --- /dev/null +++ b/gnss/1.0/default/AGnss.h
@@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_gnss_V1_0_AGnss_H_ +#define android_hardware_gnss_V1_0_AGnss_H_ + +#include <ThreadCreationWrapper.h> +#include <android/hardware/gnss/1.0/IAGnss.h> +#include <hardware/gps_internal.h> +#include <hidl/Status.h> +#include <netinet/in.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IAGnss; +using ::android::hardware::gnss::V1_0::IAGnssCallback; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* + * Extended interface for AGNSS support. Also contains wrapper methods to allow + * methods from IAGnssCallback interface to be passed into the conventional + * implementation of the GNSS HAL. + */ +struct AGnss : public IAGnss { + AGnss(const AGpsInterface* agpsIface); + ~AGnss(); + /* + * Methods from ::android::hardware::gnss::V1_0::IAGnss interface follow. + * These declarations were generated from IAGnss.hal. + */ + Return<void> setCallback(const sp<IAGnssCallback>& callback) override; + Return<bool> dataConnClosed() override; + Return<bool> dataConnFailed() override; + Return<bool> setServer(IAGnssCallback::AGnssType type, + const hidl_string& hostname, int32_t port) override; + Return<bool> dataConnOpen(const hidl_string& apn, + IAGnss::ApnIpType apnIpType) override; + + /* + * Callback methods to be passed into the conventional GNSS HAL by the default + * implementation. These methods are not part of the IAGnss base class. + */ + static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg); + static void statusCb(AGpsStatus* status); + + /* + * Holds function pointers to the callback methods. + */ + static AGpsCallbacks sAGnssCb; + + private: + const AGpsInterface* mAGnssIface = nullptr; + static sp<IAGnssCallback> sAGnssCbIface; + static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList; + static bool sInterfaceExists; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_AGnss_H_
diff --git a/gnss/1.0/default/AGnssRil.cpp b/gnss/1.0/default/AGnssRil.cpp new file mode 100644 index 0000000..1458327 --- /dev/null +++ b/gnss/1.0/default/AGnssRil.cpp
@@ -0,0 +1,152 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_AGnssRilInterface" + +#include "AGnssRil.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +std::vector<std::unique_ptr<ThreadFuncArgs>> AGnssRil::sThreadFuncArgsList; +sp<IAGnssRilCallback> AGnssRil::sAGnssRilCbIface = nullptr; +bool AGnssRil::sInterfaceExists = false; + +AGpsRilCallbacks AGnssRil::sAGnssRilCb = { + .request_setid = AGnssRil::requestSetId, + .request_refloc = AGnssRil::requestRefLoc, + .create_thread_cb = AGnssRil::createThreadCb +}; + +AGnssRil::AGnssRil(const AGpsRilInterface* aGpsRilIface) : mAGnssRilIface(aGpsRilIface) { + /* Error out if an instance of the interface already exists. */ + LOG_ALWAYS_FATAL_IF(sInterfaceExists); + sInterfaceExists = true; +} + +AGnssRil::~AGnssRil() { + sThreadFuncArgsList.clear(); + sInterfaceExists = false; +} + +void AGnssRil::requestSetId(uint32_t flags) { + if (sAGnssRilCbIface == nullptr) { + ALOGE("%s: AGNSSRil Callback Interface configured incorrectly", __func__); + return; + } + + auto ret = sAGnssRilCbIface->requestSetIdCb(flags); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void AGnssRil::requestRefLoc(uint32_t /*flags*/) { + if (sAGnssRilCbIface == nullptr) { + ALOGE("%s: AGNSSRil Callback Interface configured incorrectly", __func__); + return; + } + + auto ret = sAGnssRilCbIface->requestRefLocCb(); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +pthread_t AGnssRil::createThreadCb(const char* name, void (*start)(void*), void* arg) { + return createPthread(name, start, arg, &sThreadFuncArgsList); +} + +// Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow. +Return<void> AGnssRil::setCallback(const sp<IAGnssRilCallback>& callback) { + if (mAGnssRilIface == nullptr) { + ALOGE("%s: AGnssRil interface is unavailable", __func__); + return Void(); + } + + sAGnssRilCbIface = callback; + + mAGnssRilIface->init(&sAGnssRilCb); + return Void(); +} + +Return<void> AGnssRil::setRefLocation(const IAGnssRil::AGnssRefLocation& aGnssRefLocation) { + if (mAGnssRilIface == nullptr) { + ALOGE("%s: AGnssRil interface is unavailable", __func__); + return Void(); + } + + AGpsRefLocation aGnssRefloc; + aGnssRefloc.type = static_cast<uint16_t>(aGnssRefLocation.type); + + auto& cellID = aGnssRefLocation.cellID; + aGnssRefloc.u.cellID = { + .type = static_cast<uint16_t>(cellID.type), + .mcc = cellID.mcc, + .mnc = cellID.mnc, + .lac = cellID.lac, + .cid = cellID.cid, + .tac = cellID.tac, + .pcid = cellID.pcid + }; + + mAGnssRilIface->set_ref_location(&aGnssRefloc, sizeof(aGnssRefloc)); + return Void(); +} + +Return<bool> AGnssRil::setSetId(IAGnssRil::SetIDType type, const hidl_string& setid) { + if (mAGnssRilIface == nullptr) { + ALOGE("%s: AGnssRil interface is unavailable", __func__); + return false; + } + + mAGnssRilIface->set_set_id(static_cast<uint16_t>(type), setid.c_str()); + return true; +} + +Return<bool> AGnssRil::updateNetworkState(bool connected, + IAGnssRil::NetworkType type, + bool roaming) { + if (mAGnssRilIface == nullptr) { + ALOGE("%s: AGnssRil interface is unavailable", __func__); + return false; + } + + mAGnssRilIface->update_network_state(connected, + static_cast<int>(type), + roaming, + nullptr /* extra_info */); + return true; +} + +Return<bool> AGnssRil::updateNetworkAvailability(bool available, const hidl_string& apn) { + if (mAGnssRilIface == nullptr) { + ALOGE("%s: AGnssRil interface is unavailable", __func__); + return false; + } + + mAGnssRilIface->update_network_availability(available, apn.c_str()); + return true; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/AGnssRil.h b/gnss/1.0/default/AGnssRil.h new file mode 100644 index 0000000..6215a9e --- /dev/null +++ b/gnss/1.0/default/AGnssRil.h
@@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_gnss_V1_0_AGnssRil_H_ +#define android_hardware_gnss_V1_0_AGnssRil_H_ + +#include <ThreadCreationWrapper.h> +#include <android/hardware/gnss/1.0/IAGnssRil.h> +#include <hardware/gps.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IAGnssRil; +using ::android::hardware::gnss::V1_0::IAGnssRilCallback; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* + * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface Layer interface + * allows the GNSS chipset to request radio interface layer information from Android platform. + * Examples of such information are reference location, unique subscriber ID, phone number string + * and network availability changes. Also contains wrapper methods to allow methods from + * IAGnssiRilCallback interface to be passed into the conventional implementation of the GNSS HAL. + */ +struct AGnssRil : public IAGnssRil { + AGnssRil(const AGpsRilInterface* aGpsRilIface); + ~AGnssRil(); + + /* + * Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow. + * These declarations were generated from IAGnssRil.hal. + */ + Return<void> setCallback(const sp<IAGnssRilCallback>& callback) override; + Return<void> setRefLocation(const IAGnssRil::AGnssRefLocation& agnssReflocation) override; + Return<bool> setSetId(IAGnssRil::SetIDType type, const hidl_string& setid) override; + Return<bool> updateNetworkState(bool connected, + IAGnssRil::NetworkType type, + bool roaming) override; + Return<bool> updateNetworkAvailability(bool available, const hidl_string& apn) override; + static void requestSetId(uint32_t flags); + static void requestRefLoc(uint32_t flags); + + /* + * Callback method to be passed into the conventional GNSS HAL by the default + * implementation. This method is not part of the IAGnssRil base class. + */ + static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg); + + /* + * Holds function pointers to the callback methods. + */ + static AGpsRilCallbacks sAGnssRilCb; + + private: + const AGpsRilInterface* mAGnssRilIface = nullptr; + static sp<IAGnssRilCallback> sAGnssRilCbIface; + static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList; + static bool sInterfaceExists; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_AGnssRil_H_
diff --git a/gnss/1.0/default/Android.mk b/gnss/1.0/default/Android.mk new file mode 100644 index 0000000..5ad5e50 --- /dev/null +++ b/gnss/1.0/default/Android.mk
@@ -0,0 +1,56 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.gnss@1.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + ThreadCreationWrapper.cpp \ + AGnss.cpp \ + AGnssRil.cpp \ + Gnss.cpp \ + GnssBatching.cpp \ + GnssDebug.cpp \ + GnssGeofencing.cpp \ + GnssMeasurement.cpp \ + GnssNavigationMessage.cpp \ + GnssNi.cpp \ + GnssXtra.cpp \ + GnssConfiguration.cpp \ + GnssUtils.cpp + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libhidlbase \ + libhidltransport \ + libutils \ + android.hardware.gnss@1.0 \ + libhardware + +LOCAL_CFLAGS += -Werror + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.gnss@1.0-service +LOCAL_INIT_RC := android.hardware.gnss@1.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + +LOCAL_SHARED_LIBRARIES += \ + libhidlbase \ + libhidltransport \ + android.hardware.gnss@1.0 \ + +include $(BUILD_EXECUTABLE)
diff --git a/gnss/1.0/default/Gnss.cpp b/gnss/1.0/default/Gnss.cpp new file mode 100644 index 0000000..9493737 --- /dev/null +++ b/gnss/1.0/default/Gnss.cpp
@@ -0,0 +1,702 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_GnssInterface" + +#include "Gnss.h" +#include <GnssUtils.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +std::vector<std::unique_ptr<ThreadFuncArgs>> Gnss::sThreadFuncArgsList; +sp<IGnssCallback> Gnss::sGnssCbIface = nullptr; +bool Gnss::sInterfaceExists = false; +bool Gnss::sWakelockHeldGnss = false; +bool Gnss::sWakelockHeldFused = false; + +GpsCallbacks Gnss::sGnssCb = { + .size = sizeof(GpsCallbacks), + .location_cb = locationCb, + .status_cb = statusCb, + .sv_status_cb = gpsSvStatusCb, + .nmea_cb = nmeaCb, + .set_capabilities_cb = setCapabilitiesCb, + .acquire_wakelock_cb = acquireWakelockCb, + .release_wakelock_cb = releaseWakelockCb, + .create_thread_cb = createThreadCb, + .request_utc_time_cb = requestUtcTimeCb, + .set_system_info_cb = setSystemInfoCb, + .gnss_sv_status_cb = gnssSvStatusCb, +}; + +Gnss::Gnss(gps_device_t* gnssDevice) { + /* Error out if an instance of the interface already exists. */ + LOG_ALWAYS_FATAL_IF(sInterfaceExists); + sInterfaceExists = true; + + if (gnssDevice == nullptr) { + ALOGE("%s: Invalid device_t handle", __func__); + return; + } + + mGnssIface = gnssDevice->get_gps_interface(gnssDevice); +} + +Gnss::~Gnss() { + sInterfaceExists = false; + sThreadFuncArgsList.clear(); +} + +void Gnss::locationCb(GpsLocation* location) { + if (sGnssCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + if (location == nullptr) { + ALOGE("%s: Invalid location from GNSS HAL", __func__); + return; + } + + android::hardware::gnss::V1_0::GnssLocation gnssLocation = convertToGnssLocation(location); + auto ret = sGnssCbIface->gnssLocationCb(gnssLocation); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void Gnss::statusCb(GpsStatus* gnssStatus) { + if (sGnssCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + if (gnssStatus == nullptr) { + ALOGE("%s: Invalid GpsStatus from GNSS HAL", __func__); + return; + } + + IGnssCallback::GnssStatusValue status = + static_cast<IGnssCallback::GnssStatusValue>(gnssStatus->status); + + auto ret = sGnssCbIface->gnssStatusCb(status); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void Gnss::gnssSvStatusCb(GnssSvStatus* status) { + if (sGnssCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + if (status == nullptr) { + ALOGE("Invalid status from GNSS HAL %s", __func__); + return; + } + + IGnssCallback::GnssSvStatus svStatus; + svStatus.numSvs = status->num_svs; + + if (svStatus.numSvs > static_cast<uint32_t>(GnssMax::SVS_COUNT)) { + ALOGW("Too many satellites %zd. Clamps to %d.", svStatus.numSvs, GnssMax::SVS_COUNT); + svStatus.numSvs = static_cast<uint32_t>(GnssMax::SVS_COUNT); + } + + for (size_t i = 0; i < svStatus.numSvs; i++) { + auto svInfo = status->gnss_sv_list[i]; + IGnssCallback::GnssSvInfo gnssSvInfo = { + .svid = svInfo.svid, + .constellation = static_cast<android::hardware::gnss::V1_0::GnssConstellationType>( + svInfo.constellation), + .cN0Dbhz = svInfo.c_n0_dbhz, + .elevationDegrees = svInfo.elevation, + .azimuthDegrees = svInfo.azimuth, + .svFlag = svInfo.flags, + // Older chipsets do not provide carrier frequency, hence HAS_CARRIER_FREQUENCY flag + // is not set and the carrierFrequencyHz field is set to zero + .carrierFrequencyHz = 0 + }; + svStatus.gnssSvList[i] = gnssSvInfo; + } + + auto ret = sGnssCbIface->gnssSvStatusCb(svStatus); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +/* + * This enum is used by gpsSvStatusCb() method below to convert GpsSvStatus + * to GnssSvStatus for backward compatibility. It is only used by the default + * implementation and is not part of the GNSS interface. + */ +enum SvidValues : uint16_t { + GLONASS_SVID_OFFSET = 64, + GLONASS_SVID_COUNT = 24, + BEIDOU_SVID_OFFSET = 200, + BEIDOU_SVID_COUNT = 35, + SBAS_SVID_MIN = 33, + SBAS_SVID_MAX = 64, + SBAS_SVID_ADD = 87, + QZSS_SVID_MIN = 193, + QZSS_SVID_MAX = 200 +}; + +/* + * The following code that converts GpsSvStatus to GnssSvStatus is moved here from + * GnssLocationProvider. GnssLocationProvider does not require it anymore since GpsSvStatus is + * being deprecated and is no longer part of the GNSS interface. + */ +void Gnss::gpsSvStatusCb(GpsSvStatus* svInfo) { + if (sGnssCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + if (svInfo == nullptr) { + ALOGE("Invalid status from GNSS HAL %s", __func__); + return; + } + + IGnssCallback::GnssSvStatus svStatus; + svStatus.numSvs = svInfo->num_svs; + /* + * Clamp the list size since GnssSvStatus can support a maximum of + * GnssMax::SVS_COUNT entries. + */ + if (svStatus.numSvs > static_cast<uint32_t>(GnssMax::SVS_COUNT)) { + ALOGW("Too many satellites %zd. Clamps to %d.", svStatus.numSvs, GnssMax::SVS_COUNT); + svStatus.numSvs = static_cast<uint32_t>(GnssMax::SVS_COUNT); + } + + uint32_t ephemerisMask = svInfo->ephemeris_mask; + uint32_t almanacMask = svInfo->almanac_mask; + uint32_t usedInFixMask = svInfo->used_in_fix_mask; + /* + * Conversion from GpsSvInfo to IGnssCallback::GnssSvInfo happens below. + */ + for (size_t i = 0; i < svStatus.numSvs; i++) { + IGnssCallback::GnssSvInfo& info = svStatus.gnssSvList[i]; + info.svid = svInfo->sv_list[i].prn; + if (info.svid >= 1 && info.svid <= 32) { + info.constellation = GnssConstellationType::GPS; + } else if (info.svid > GLONASS_SVID_OFFSET && + info.svid <= GLONASS_SVID_OFFSET + GLONASS_SVID_COUNT) { + info.constellation = GnssConstellationType::GLONASS; + info.svid -= GLONASS_SVID_OFFSET; + } else if (info.svid > BEIDOU_SVID_OFFSET && + info.svid <= BEIDOU_SVID_OFFSET + BEIDOU_SVID_COUNT) { + info.constellation = GnssConstellationType::BEIDOU; + info.svid -= BEIDOU_SVID_OFFSET; + } else if (info.svid >= SBAS_SVID_MIN && info.svid <= SBAS_SVID_MAX) { + info.constellation = GnssConstellationType::SBAS; + info.svid += SBAS_SVID_ADD; + } else if (info.svid >= QZSS_SVID_MIN && info.svid <= QZSS_SVID_MAX) { + info.constellation = GnssConstellationType::QZSS; + } else { + ALOGD("Unknown constellation type with Svid = %d.", info.svid); + info.constellation = GnssConstellationType::UNKNOWN; + } + + info.cN0Dbhz = svInfo->sv_list[i].snr; + info.elevationDegrees = svInfo->sv_list[i].elevation; + info.azimuthDegrees = svInfo->sv_list[i].azimuth; + // TODO: b/31702236 + info.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE); + + /* + * Only GPS info is valid for these fields, as these masks are just 32 + * bits, by GPS prn. + */ + if (info.constellation == GnssConstellationType::GPS) { + int32_t svidMask = (1 << (info.svid - 1)); + if ((ephemerisMask & svidMask) != 0) { + info.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA; + } + if ((almanacMask & svidMask) != 0) { + info.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA; + } + if ((usedInFixMask & svidMask) != 0) { + info.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX; + } + } + } + + auto ret = sGnssCbIface->gnssSvStatusCb(svStatus); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void Gnss::nmeaCb(GpsUtcTime timestamp, const char* nmea, int length) { + if (sGnssCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + android::hardware::hidl_string nmeaString; + nmeaString.setToExternal(nmea, length); + auto ret = sGnssCbIface->gnssNmeaCb(timestamp, nmeaString); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void Gnss::setCapabilitiesCb(uint32_t capabilities) { + if (sGnssCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + auto ret = sGnssCbIface->gnssSetCapabilitesCb(capabilities); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void Gnss::acquireWakelockCb() { + acquireWakelockGnss(); +} + +void Gnss::releaseWakelockCb() { + releaseWakelockGnss(); +} + + +void Gnss::acquireWakelockGnss() { + sWakelockHeldGnss = true; + updateWakelock(); +} + +void Gnss::releaseWakelockGnss() { + sWakelockHeldGnss = false; + updateWakelock(); +} + +void Gnss::acquireWakelockFused() { + sWakelockHeldFused = true; + updateWakelock(); +} + +void Gnss::releaseWakelockFused() { + sWakelockHeldFused = false; + updateWakelock(); +} + +void Gnss::updateWakelock() { + // Track the state of the last request - in case the wake lock in the layer above is reference + // counted. + static bool sWakelockHeld = false; + + if (sGnssCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + if (sWakelockHeldGnss || sWakelockHeldFused) { + if (!sWakelockHeld) { + ALOGI("%s: GNSS HAL Wakelock acquired due to gps: %d, fused: %d", __func__, + sWakelockHeldGnss, sWakelockHeldFused); + sWakelockHeld = true; + auto ret = sGnssCbIface->gnssAcquireWakelockCb(); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + } + } else { + if (sWakelockHeld) { + ALOGI("%s: GNSS HAL Wakelock released", __func__); + } else { + // To avoid burning power, always release, even if logic got here with sWakelock false + // which it shouldn't, unless underlying *.h implementation makes duplicate requests. + ALOGW("%s: GNSS HAL Wakelock released, duplicate request", __func__); + } + sWakelockHeld = false; + auto ret = sGnssCbIface->gnssReleaseWakelockCb(); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } + } +} + +void Gnss::requestUtcTimeCb() { + if (sGnssCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + auto ret = sGnssCbIface->gnssRequestTimeCb(); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +pthread_t Gnss::createThreadCb(const char* name, void (*start)(void*), void* arg) { + return createPthread(name, start, arg, &sThreadFuncArgsList); +} + +void Gnss::setSystemInfoCb(const LegacyGnssSystemInfo* info) { + if (sGnssCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + if (info == nullptr) { + ALOGE("Invalid GnssSystemInfo from GNSS HAL %s", __func__); + return; + } + + IGnssCallback::GnssSystemInfo gnssInfo = { + .yearOfHw = info->year_of_hw + }; + + auto ret = sGnssCbIface->gnssSetSystemInfoCb(gnssInfo); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + + +// Methods from ::android::hardware::gnss::V1_0::IGnss follow. +Return<bool> Gnss::setCallback(const sp<IGnssCallback>& callback) { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return false; + } + + sGnssCbIface = callback; + + return (mGnssIface->init(&sGnssCb) == 0); +} + +Return<bool> Gnss::start() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return false; + } + + return (mGnssIface->start() == 0); +} + +Return<bool> Gnss::stop() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return false; + } + + return (mGnssIface->stop() == 0); +} + +Return<void> Gnss::cleanup() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + } else { + mGnssIface->cleanup(); + } + return Void(); +} + +Return<bool> Gnss::injectLocation(double latitudeDegrees, + double longitudeDegrees, + float accuracyMeters) { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return false; + } + + return (mGnssIface->inject_location(latitudeDegrees, longitudeDegrees, accuracyMeters) == 0); +} + +Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs, + int32_t uncertaintyMs) { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return false; + } + + return (mGnssIface->inject_time(timeMs, timeReferenceMs, uncertaintyMs) == 0); +} + +Return<void> Gnss::deleteAidingData(IGnss::GnssAidingData aidingDataFlags) { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + } else { + mGnssIface->delete_aiding_data(static_cast<GpsAidingData>(aidingDataFlags)); + } + return Void(); +} + +Return<bool> Gnss::setPositionMode(IGnss::GnssPositionMode mode, + IGnss::GnssPositionRecurrence recurrence, + uint32_t minIntervalMs, + uint32_t preferredAccuracyMeters, + uint32_t preferredTimeMs) { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return false; + } + + return (mGnssIface->set_position_mode(static_cast<GpsPositionMode>(mode), + static_cast<GpsPositionRecurrence>(recurrence), + minIntervalMs, + preferredAccuracyMeters, + preferredTimeMs) == 0); +} + +Return<sp<IAGnssRil>> Gnss::getExtensionAGnssRil() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mGnssRil == nullptr) { + const AGpsRilInterface* agpsRilIface = static_cast<const AGpsRilInterface*>( + mGnssIface->get_extension(AGPS_RIL_INTERFACE)); + if (agpsRilIface == nullptr) { + ALOGE("%s GnssRil interface not implemented by GNSS HAL", __func__); + } else { + mGnssRil = new AGnssRil(agpsRilIface); + } + } + return mGnssRil; +} + +Return<sp<IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mGnssConfig == nullptr) { + const GnssConfigurationInterface* gnssConfigIface = + static_cast<const GnssConfigurationInterface*>( + mGnssIface->get_extension(GNSS_CONFIGURATION_INTERFACE)); + + if (gnssConfigIface == nullptr) { + ALOGE("%s GnssConfiguration interface not implemented by GNSS HAL", __func__); + } else { + mGnssConfig = new GnssConfiguration(gnssConfigIface); + } + } + return mGnssConfig; +} + +Return<sp<IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mGnssGeofencingIface == nullptr) { + const GpsGeofencingInterface* gpsGeofencingIface = + static_cast<const GpsGeofencingInterface*>( + mGnssIface->get_extension(GPS_GEOFENCING_INTERFACE)); + + if (gpsGeofencingIface == nullptr) { + ALOGE("%s GnssGeofencing interface not implemented by GNSS HAL", __func__); + } else { + mGnssGeofencingIface = new GnssGeofencing(gpsGeofencingIface); + } + } + + return mGnssGeofencingIface; +} + +Return<sp<IAGnss>> Gnss::getExtensionAGnss() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mAGnssIface == nullptr) { + const AGpsInterface* agpsIface = static_cast<const AGpsInterface*>( + mGnssIface->get_extension(AGPS_INTERFACE)); + if (agpsIface == nullptr) { + ALOGE("%s AGnss interface not implemented by GNSS HAL", __func__); + } else { + mAGnssIface = new AGnss(agpsIface); + } + } + return mAGnssIface; +} + +Return<sp<IGnssNi>> Gnss::getExtensionGnssNi() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mGnssNi == nullptr) { + const GpsNiInterface* gpsNiIface = static_cast<const GpsNiInterface*>( + mGnssIface->get_extension(GPS_NI_INTERFACE)); + if (gpsNiIface == nullptr) { + ALOGE("%s GnssNi interface not implemented by GNSS HAL", __func__); + } else { + mGnssNi = new GnssNi(gpsNiIface); + } + } + return mGnssNi; +} + +Return<sp<IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mGnssMeasurement == nullptr) { + const GpsMeasurementInterface* gpsMeasurementIface = + static_cast<const GpsMeasurementInterface*>( + mGnssIface->get_extension(GPS_MEASUREMENT_INTERFACE)); + + if (gpsMeasurementIface == nullptr) { + ALOGE("%s GnssMeasurement interface not implemented by GNSS HAL", __func__); + } else { + mGnssMeasurement = new GnssMeasurement(gpsMeasurementIface); + } + } + return mGnssMeasurement; +} + +Return<sp<IGnssNavigationMessage>> Gnss::getExtensionGnssNavigationMessage() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mGnssNavigationMessage == nullptr) { + const GpsNavigationMessageInterface* gpsNavigationMessageIface = + static_cast<const GpsNavigationMessageInterface*>( + mGnssIface->get_extension(GPS_NAVIGATION_MESSAGE_INTERFACE)); + + if (gpsNavigationMessageIface == nullptr) { + ALOGE("%s GnssNavigationMessage interface not implemented by GNSS HAL", + __func__); + } else { + mGnssNavigationMessage = new GnssNavigationMessage(gpsNavigationMessageIface); + } + } + + return mGnssNavigationMessage; +} + +Return<sp<IGnssXtra>> Gnss::getExtensionXtra() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mGnssXtraIface == nullptr) { + const GpsXtraInterface* gpsXtraIface = static_cast<const GpsXtraInterface*>( + mGnssIface->get_extension(GPS_XTRA_INTERFACE)); + + if (gpsXtraIface == nullptr) { + ALOGE("%s GnssXtra interface not implemented by HAL", __func__); + } else { + mGnssXtraIface = new GnssXtra(gpsXtraIface); + } + } + + return mGnssXtraIface; +} + +Return<sp<IGnssDebug>> Gnss::getExtensionGnssDebug() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mGnssDebug == nullptr) { + const GpsDebugInterface* gpsDebugIface = static_cast<const GpsDebugInterface*>( + mGnssIface->get_extension(GPS_DEBUG_INTERFACE)); + + if (gpsDebugIface == nullptr) { + ALOGE("%s: GnssDebug interface is not implemented by HAL", __func__); + } else { + mGnssDebug = new GnssDebug(gpsDebugIface); + } + } + + return mGnssDebug; +} + +Return<sp<IGnssBatching>> Gnss::getExtensionGnssBatching() { + if (mGnssIface == nullptr) { + ALOGE("%s: Gnss interface is unavailable", __func__); + return nullptr; + } + + if (mGnssBatching == nullptr) { + hw_module_t* module; + const FlpLocationInterface* flpLocationIface = nullptr; + int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, (hw_module_t const**)&module); + + if (err != 0) { + ALOGE("gnss flp hw_get_module failed: %d", err); + } else if (module == nullptr) { + ALOGE("Fused Location hw_get_module returned null module"); + } else if (module->methods == nullptr) { + ALOGE("Fused Location hw_get_module returned null methods"); + } else { + hw_device_t* device; + err = module->methods->open(module, FUSED_LOCATION_HARDWARE_MODULE_ID, &device); + if (err != 0) { + ALOGE("flpDevice open failed: %d", err); + } else { + flp_device_t * flpDevice = reinterpret_cast<flp_device_t*>(device); + flpLocationIface = flpDevice->get_flp_interface(flpDevice); + } + } + + if (flpLocationIface == nullptr) { + ALOGE("%s: GnssBatching interface is not implemented by HAL", __func__); + } else { + mGnssBatching = new GnssBatching(flpLocationIface); + } + } + return mGnssBatching; +} + +IGnss* HIDL_FETCH_IGnss(const char* /* hal */) { + hw_module_t* module; + IGnss* iface = nullptr; + int err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); + + if (err == 0) { + hw_device_t* device; + err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device); + if (err == 0) { + iface = new Gnss(reinterpret_cast<gps_device_t*>(device)); + } else { + ALOGE("gnssDevice open %s failed: %d", GPS_HARDWARE_MODULE_ID, err); + } + } else { + ALOGE("gnss hw_get_module %s failed: %d", GPS_HARDWARE_MODULE_ID, err); + } + return iface; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/Gnss.h b/gnss/1.0/default/Gnss.h new file mode 100644 index 0000000..63614fa --- /dev/null +++ b/gnss/1.0/default/Gnss.h
@@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_gnss_V1_0_Gnss_H_ +#define android_hardware_gnss_V1_0_Gnss_H_ + +#include <AGnss.h> +#include <AGnssRil.h> +#include <GnssBatching.h> +#include <GnssConfiguration.h> +#include <GnssDebug.h> +#include <GnssGeofencing.h> +#include <GnssMeasurement.h> +#include <GnssNavigationMessage.h> +#include <GnssNi.h> +#include <GnssXtra.h> + +#include <ThreadCreationWrapper.h> +#include <android/hardware/gnss/1.0/IGnss.h> +#include <hardware/fused_location.h> +#include <hardware/gps.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +using LegacyGnssSystemInfo = ::GnssSystemInfo; + +/* + * Represents the standard GNSS interface. Also contains wrapper methods to allow methods from + * IGnssCallback interface to be passed into the conventional implementation of the GNSS HAL. + */ +struct Gnss : public IGnss { + Gnss(gps_device_t* gnss_device); + ~Gnss(); + + /* + * Methods from ::android::hardware::gnss::V1_0::IGnss follow. + * These declarations were generated from Gnss.hal. + */ + Return<bool> setCallback(const sp<IGnssCallback>& callback) override; + Return<bool> start() override; + Return<bool> stop() override; + Return<void> cleanup() override; + Return<bool> injectLocation(double latitudeDegrees, + double longitudeDegrees, + float accuracyMeters) override; + Return<bool> injectTime(int64_t timeMs, + int64_t timeReferenceMs, + int32_t uncertaintyMs) override; + Return<void> deleteAidingData(IGnss::GnssAidingData aidingDataFlags) override; + Return<bool> setPositionMode(IGnss::GnssPositionMode mode, + IGnss::GnssPositionRecurrence recurrence, + uint32_t minIntervalMs, + uint32_t preferredAccuracyMeters, + uint32_t preferredTimeMs) override; + Return<sp<IAGnssRil>> getExtensionAGnssRil() override; + Return<sp<IGnssGeofencing>> getExtensionGnssGeofencing() override; + Return<sp<IAGnss>> getExtensionAGnss() override; + Return<sp<IGnssNi>> getExtensionGnssNi() override; + Return<sp<IGnssMeasurement>> getExtensionGnssMeasurement() override; + Return<sp<IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override; + Return<sp<IGnssXtra>> getExtensionXtra() override; + Return<sp<IGnssConfiguration>> getExtensionGnssConfiguration() override; + Return<sp<IGnssDebug>> getExtensionGnssDebug() override; + Return<sp<IGnssBatching>> getExtensionGnssBatching() override; + + /* + * Callback methods to be passed into the conventional GNSS HAL by the default + * implementation. These methods are not part of the IGnss base class. + */ + static void locationCb(GpsLocation* location); + static void statusCb(GpsStatus* gnss_status); + static void nmeaCb(GpsUtcTime timestamp, const char* nmea, int length); + static void setCapabilitiesCb(uint32_t capabilities); + static void acquireWakelockCb(); + static void releaseWakelockCb(); + static void requestUtcTimeCb(); + static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg); + static void gnssSvStatusCb(GnssSvStatus* status); + /* + * Deprecated callback added for backward compatibility to devices that do + * not support GnssSvStatus. + */ + static void gpsSvStatusCb(GpsSvStatus* status); + static void setSystemInfoCb(const LegacyGnssSystemInfo* info); + + /* + * Wakelock consolidation, only needed for dual use of a gps.h & fused_location.h HAL + * + * Ensures that if the last call from either legacy .h was to acquire a wakelock, that a + * wakelock is held. Otherwise releases it. + */ + static void acquireWakelockFused(); + static void releaseWakelockFused(); + + /* + * Holds function pointers to the callback methods. + */ + static GpsCallbacks sGnssCb; + + private: + // for wakelock consolidation, see above + static void acquireWakelockGnss(); + static void releaseWakelockGnss(); + static void updateWakelock(); + static bool sWakelockHeldGnss; + static bool sWakelockHeldFused; + + sp<GnssXtra> mGnssXtraIface = nullptr; + sp<AGnssRil> mGnssRil = nullptr; + sp<GnssGeofencing> mGnssGeofencingIface = nullptr; + sp<AGnss> mAGnssIface = nullptr; + sp<GnssNi> mGnssNi = nullptr; + sp<GnssMeasurement> mGnssMeasurement = nullptr; + sp<GnssNavigationMessage> mGnssNavigationMessage = nullptr; + sp<GnssDebug> mGnssDebug = nullptr; + sp<GnssConfiguration> mGnssConfig = nullptr; + sp<GnssBatching> mGnssBatching = nullptr; + const GpsInterface* mGnssIface = nullptr; + static sp<IGnssCallback> sGnssCbIface; + static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList; + static bool sInterfaceExists; +}; + +extern "C" IGnss* HIDL_FETCH_IGnss(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_Gnss_H_
diff --git a/gnss/1.0/default/GnssBatching.cpp b/gnss/1.0/default/GnssBatching.cpp new file mode 100644 index 0000000..02b38cb --- /dev/null +++ b/gnss/1.0/default/GnssBatching.cpp
@@ -0,0 +1,225 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_GnssBatchingInterface" + +#include "GnssBatching.h" +#include <Gnss.h> // for wakelock consolidation +#include <GnssUtils.h> + +#include <cutils/log.h> // for ALOGE +#include <vector> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +sp<IGnssBatchingCallback> GnssBatching::sGnssBatchingCbIface = nullptr; +bool GnssBatching::sFlpSupportsBatching = false; + +FlpCallbacks GnssBatching::sFlpCb = { + .size = sizeof(FlpCallbacks), + .location_cb = locationCb, + .acquire_wakelock_cb = acquireWakelockCb, + .release_wakelock_cb = releaseWakelockCb, + .set_thread_event_cb = setThreadEventCb, + .flp_capabilities_cb = flpCapabilitiesCb, + .flp_status_cb = flpStatusCb, +}; + +GnssBatching::GnssBatching(const FlpLocationInterface* flpLocationIface) : + mFlpLocationIface(flpLocationIface) { +} + +/* + * This enum is used locally by various methods below. It is only used by the default + * implementation and is not part of the GNSS interface. + */ +enum BatchingValues : uint16_t { + // Numbers 0-3 were used in earlier implementations - using 4 to be distinct to the HAL + FLP_GNSS_BATCHING_CLIENT_ID = 4, + // Tech. mask of GNSS, and sensor aiding, for legacy HAL to fit with GnssBatching API + FLP_TECH_MASK_GNSS_AND_SENSORS = FLP_TECH_MASK_GNSS | FLP_TECH_MASK_SENSORS, + // Putting a cap to avoid possible memory issues. Unlikely values this high are supported. + MAX_LOCATIONS_PER_BATCH = 1000 +}; + +void GnssBatching::locationCb(int32_t locationsCount, FlpLocation** locations) { + if (sGnssBatchingCbIface == nullptr) { + ALOGE("%s: GNSS Batching Callback Interface configured incorrectly", __func__); + return; + } + + if (locations == nullptr) { + ALOGE("%s: Invalid locations from GNSS HAL", __func__); + return; + } + + if (locationsCount < 0) { + ALOGE("%s: Negative location count: %d set to 0", __func__, locationsCount); + locationsCount = 0; + } else if (locationsCount > MAX_LOCATIONS_PER_BATCH) { + ALOGW("%s: Unexpected high location count: %d set to %d", __func__, locationsCount, + MAX_LOCATIONS_PER_BATCH); + locationsCount = MAX_LOCATIONS_PER_BATCH; + } + + /** + * Note: + * Some existing implementations may drop duplicate locations. These could be expanded here + * but as there's ambiguity between no-GPS-fix vs. dropped duplicates in that implementation, + * and that's not specified by the fused_location.h, that isn't safe to do here. + * Fortunately, this shouldn't be a major issue in cases where GNSS batching is typically + * used (e.g. when user is likely in vehicle/bicycle.) + */ + std::vector<android::hardware::gnss::V1_0::GnssLocation> gnssLocations; + for (int iLocation = 0; iLocation < locationsCount; iLocation++) { + if (locations[iLocation] == nullptr) { + ALOGE("%s: Null location at slot: %d of %d, skipping", __func__, iLocation, + locationsCount); + continue; + } + if ((locations[iLocation]->sources_used & ~FLP_TECH_MASK_GNSS_AND_SENSORS) != 0) + { + ALOGE("%s: Unrequested location type %d at slot: %d of %d, skipping", __func__, + locations[iLocation]->sources_used, iLocation, locationsCount); + continue; + } + gnssLocations.push_back(convertToGnssLocation(locations[iLocation])); + } + + auto ret = sGnssBatchingCbIface->gnssLocationBatchCb(gnssLocations); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void GnssBatching::acquireWakelockCb() { + Gnss::acquireWakelockFused(); +} + +void GnssBatching::releaseWakelockCb() { + Gnss::releaseWakelockFused(); +} + +// this can just return success, because threads are now set up on demand in the jni layer +int32_t GnssBatching::setThreadEventCb(ThreadEvent /*event*/) { + return FLP_RESULT_SUCCESS; +} + +void GnssBatching::flpCapabilitiesCb(int32_t capabilities) { + ALOGD("%s capabilities %d", __func__, capabilities); + + if (capabilities & CAPABILITY_GNSS) { + // once callback is received and capabilities high enough, we know version is + // high enough for flush() + sFlpSupportsBatching = true; + } +} + +void GnssBatching::flpStatusCb(int32_t status) { + ALOGD("%s (default implementation) not forwarding status: %d", __func__, status); +} + +// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow. +Return<bool> GnssBatching::init(const sp<IGnssBatchingCallback>& callback) { + if (mFlpLocationIface == nullptr) { + ALOGE("%s: Flp batching is unavailable", __func__); + return false; + } + + sGnssBatchingCbIface = callback; + + return (mFlpLocationIface->init(&sFlpCb) == 0); +} + +Return<uint16_t> GnssBatching::getBatchSize() { + if (mFlpLocationIface == nullptr) { + ALOGE("%s: Flp batching interface is unavailable", __func__); + return 0; + } + + return mFlpLocationIface->get_batch_size(); +} + +Return<bool> GnssBatching::start(const IGnssBatching::Options& options) { + if (mFlpLocationIface == nullptr) { + ALOGE("%s: Flp batching interface is unavailable", __func__); + return false; + } + + if (!sFlpSupportsBatching) { + ALOGE("%s: Flp batching interface not supported, no capabilities callback received", + __func__); + return false; + } + + FlpBatchOptions optionsHw; + // Legacy code used 9999 mW for High accuracy, and 21 mW for balanced. + // New GNSS API just expects reasonable GNSS chipset behavior - do something efficient + // given the interval. This 100 mW limit should be quite sufficient (esp. given legacy code + // implementations may not even use this value.) + optionsHw.max_power_allocation_mW = 100; + optionsHw.sources_to_use = FLP_TECH_MASK_GNSS_AND_SENSORS; + optionsHw.flags = 0; + if (options.flags & Flag::WAKEUP_ON_FIFO_FULL) { + optionsHw.flags |= FLP_BATCH_WAKEUP_ON_FIFO_FULL; + } + optionsHw.period_ns = options.periodNanos; + optionsHw.smallest_displacement_meters = 0; // Zero offset - just use time interval + + return (mFlpLocationIface->start_batching(FLP_GNSS_BATCHING_CLIENT_ID, &optionsHw) + == FLP_RESULT_SUCCESS); +} + +Return<void> GnssBatching::flush() { + if (mFlpLocationIface == nullptr) { + ALOGE("%s: Flp batching interface is unavailable", __func__); + return Void(); + } + + mFlpLocationIface->flush_batched_locations(); + + return Void(); +} + +Return<bool> GnssBatching::stop() { + if (mFlpLocationIface == nullptr) { + ALOGE("%s: Flp batching interface is unavailable", __func__); + return false; + } + + return (mFlpLocationIface->stop_batching(FLP_GNSS_BATCHING_CLIENT_ID) == FLP_RESULT_SUCCESS); +} + +Return<void> GnssBatching::cleanup() { + if (mFlpLocationIface == nullptr) { + ALOGE("%s: Flp batching interface is unavailable", __func__); + return Void(); + } + + mFlpLocationIface->cleanup(); + + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/GnssBatching.h b/gnss/1.0/default/GnssBatching.h new file mode 100644 index 0000000..001c27d --- /dev/null +++ b/gnss/1.0/default/GnssBatching.h
@@ -0,0 +1,67 @@ +#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H +#define ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H + +#include <android/hardware/gnss/1.0/IGnssBatching.h> +#include <hardware/fused_location.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IGnssBatching; +using ::android::hardware::gnss::V1_0::IGnssBatchingCallback; +using ::android::hidl::base::V1_0::IBase; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +struct GnssBatching : public IGnssBatching { + GnssBatching(const FlpLocationInterface* flpLocationIface); + + // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow. + Return<bool> init(const sp<IGnssBatchingCallback>& callback) override; + Return<uint16_t> getBatchSize() override; + Return<bool> start(const IGnssBatching::Options& options ) override; + Return<void> flush() override; + Return<bool> stop() override; + Return<void> cleanup() override; + + /* + * Callback methods to be passed into the conventional FLP HAL by the default + * implementation. These methods are not part of the IGnssBatching base class. + */ + static void locationCb(int32_t locationsCount, FlpLocation** locations); + static void acquireWakelockCb(); + static void releaseWakelockCb(); + static int32_t setThreadEventCb(ThreadEvent event); + static void flpCapabilitiesCb(int32_t capabilities); + static void flpStatusCb(int32_t status); + + /* + * Holds function pointers to the callback methods. + */ + static FlpCallbacks sFlpCb; + + private: + const FlpLocationInterface* mFlpLocationIface = nullptr; + static sp<IGnssBatchingCallback> sGnssBatchingCbIface; + static bool sFlpSupportsBatching; +}; + +extern "C" IGnssBatching* HIDL_FETCH_IGnssBatching(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
diff --git a/gnss/1.0/default/GnssConfiguration.cpp b/gnss/1.0/default/GnssConfiguration.cpp new file mode 100644 index 0000000..0c1aa86 --- /dev/null +++ b/gnss/1.0/default/GnssConfiguration.cpp
@@ -0,0 +1,117 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_GnssConfigurationInterface" + +#include <log/log.h> + +#include "GnssConfiguration.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +GnssConfiguration::GnssConfiguration(const GnssConfigurationInterface* gnssConfigInfc) + : mGnssConfigIface(gnssConfigInfc) {} + +// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow. +Return<bool> GnssConfiguration::setSuplEs(bool enabled) { + if (mGnssConfigIface == nullptr) { + ALOGE("%s: GNSS Configuration interface is not available.", __func__); + return false; + } + + std::string config = "SUPL_ES=" + std::to_string(enabled ? 1 : 0) + "\n"; + mGnssConfigIface->configuration_update(config.c_str(), config.size()); + return true; +} + +Return<bool> GnssConfiguration::setSuplVersion(uint32_t version) { + if (mGnssConfigIface == nullptr) { + ALOGE("%s: GNSS Configuration interface is not available.", __func__); + return false; + } + + std::string config = "SUPL_VER=" + std::to_string(version) + "\n"; + mGnssConfigIface->configuration_update(config.c_str(), config.size()); + + return true; +} + +Return<bool> GnssConfiguration::setSuplMode(uint8_t mode) { + if (mGnssConfigIface == nullptr) { + ALOGE("%s: GNSS Configuration interface is not available.", __func__); + return false; + } + + std::string config = "SUPL_MODE=" + std::to_string(mode) + "\n"; + mGnssConfigIface->configuration_update(config.c_str(), config.size()); + return true; +} + +Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfile) { + if (mGnssConfigIface == nullptr) { + ALOGE("%s: GNSS Configuration interface is not available.", __func__); + return false; + } + + std::string config = "LPP_PROFILE=" + std::to_string(lppProfile) + "\n"; + mGnssConfigIface->configuration_update(config.c_str(), config.size()); + return true; +} + +Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) { + if (mGnssConfigIface == nullptr) { + ALOGE("%s: GNSS Configuration interface is not available.", __func__); + return false; + } + + std::string config = "A_GLONASS_POS_PROTOCOL_SELECT=" + + std::to_string(protocol) + "\n"; + mGnssConfigIface->configuration_update(config.c_str(), config.size()); + return true; +} + +Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) { + if (mGnssConfigIface == nullptr) { + ALOGE("%s: GNSS Configuration interface is not available.", __func__); + return false; + } + + std::string config = "GPS_LOCK=" + std::to_string(lock) + "\n"; + mGnssConfigIface->configuration_update(config.c_str(), config.size()); + return true; +} + +Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) { + if (mGnssConfigIface == nullptr) { + ALOGE("%s: GNSS Configuration interface is not available.", __func__); + return false; + } + + std::string config = "USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=" + std::to_string(enabled ? 1 : 0) + + "\n"; + mGnssConfigIface->configuration_update(config.c_str(), config.size()); + return true; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/GnssConfiguration.h b/gnss/1.0/default/GnssConfiguration.h new file mode 100644 index 0000000..a6eca88 --- /dev/null +++ b/gnss/1.0/default/GnssConfiguration.h
@@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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. + */ + + +#ifndef android_hardware_gnss_V1_0_GnssConfiguration_H_ +#define android_hardware_gnss_V1_0_GnssConfiguration_H_ + +#include <android/hardware/gnss/1.0/IGnssConfiguration.h> +#include <hardware/gps.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IGnssConfiguration; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* + * Interface for passing GNSS configuration info from platform to HAL. + */ +struct GnssConfiguration : public IGnssConfiguration { + GnssConfiguration(const GnssConfigurationInterface* gnssConfigIface); + + /* + * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow. + * These declarations were generated from IGnssConfiguration.hal. + */ + Return<bool> setSuplVersion(uint32_t version) override; + Return<bool> setSuplMode(uint8_t mode) override; + Return<bool> setSuplEs(bool enabled) override; + Return<bool> setLppProfile(uint8_t lppProfile) override; + Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override; + Return<bool> setEmergencySuplPdn(bool enable) override; + Return<bool> setGpsLock(uint8_t lock) override; + + private: + const GnssConfigurationInterface* mGnssConfigIface = nullptr; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_GnssConfiguration_H_
diff --git a/gnss/1.0/default/GnssDebug.cpp b/gnss/1.0/default/GnssDebug.cpp new file mode 100644 index 0000000..cfc38ca --- /dev/null +++ b/gnss/1.0/default/GnssDebug.cpp
@@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_GnssDebugInterface" + +#include <log/log.h> + +#include "GnssDebug.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +GnssDebug::GnssDebug(const GpsDebugInterface* gpsDebugIface) : mGnssDebugIface(gpsDebugIface) {} + +// Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow. +Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb) { + /* + * This is a new interface and hence there is no way to retrieve the + * debug data from the HAL. + */ + DebugData data = {}; + + _hidl_cb(data); + + /* + * Log the debug data sent from the conventional Gnss HAL. This code is + * moved here from GnssLocationProvider. + */ + if (mGnssDebugIface) { + char buffer[kMaxDebugStrLen + 1]; + size_t length = mGnssDebugIface->get_internal_state(buffer, kMaxDebugStrLen); + length = std::max(length, kMaxDebugStrLen); + buffer[length] = '\0'; + ALOGD("Gnss Debug Data: %s", buffer); + } + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/GnssDebug.h b/gnss/1.0/default/GnssDebug.h new file mode 100644 index 0000000..9a17dde --- /dev/null +++ b/gnss/1.0/default/GnssDebug.h
@@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_gnss_V1_0_GnssDebug_H_ +#define android_hardware_gnss_V1_0_GnssDebug_H_ + +#include <android/hardware/gnss/1.0/IGnssDebug.h> +#include <hidl/Status.h> +#include <hardware/gps.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IGnssDebug; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* Interface for GNSS Debug support. */ +struct GnssDebug : public IGnssDebug { + GnssDebug(const GpsDebugInterface* gpsDebugIface); + + /* + * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow. + * These declarations were generated from IGnssDebug.hal. + */ + Return<void> getDebugData(getDebugData_cb _hidl_cb) override; + + private: + /* + * Constant added for backward compatibility to conventional GPS Hals which + * returned a debug string. + */ + const size_t kMaxDebugStrLen = 2047; + const GpsDebugInterface* mGnssDebugIface = nullptr; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_GnssDebug_H_
diff --git a/gnss/1.0/default/GnssGeofencing.cpp b/gnss/1.0/default/GnssGeofencing.cpp new file mode 100644 index 0000000..54c4aaa --- /dev/null +++ b/gnss/1.0/default/GnssGeofencing.cpp
@@ -0,0 +1,225 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHal_GnssGeofencing" + +#include "GnssGeofencing.h" +#include <GnssUtils.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +std::vector<std::unique_ptr<ThreadFuncArgs>> GnssGeofencing::sThreadFuncArgsList; +sp<IGnssGeofenceCallback> GnssGeofencing::mGnssGeofencingCbIface = nullptr; +bool GnssGeofencing::sInterfaceExists = false; + +GpsGeofenceCallbacks GnssGeofencing::sGnssGfCb = { + .geofence_transition_callback = gnssGfTransitionCb, + .geofence_status_callback = gnssGfStatusCb, + .geofence_add_callback = gnssGfAddCb, + .geofence_remove_callback = gnssGfRemoveCb, + .geofence_pause_callback = gnssGfPauseCb, + .geofence_resume_callback = gnssGfResumeCb, + .create_thread_cb = createThreadCb +}; + +GnssGeofencing::GnssGeofencing(const GpsGeofencingInterface* gpsGeofencingIface) + : mGnssGeofencingIface(gpsGeofencingIface) { + /* Error out if an instance of the interface already exists. */ + LOG_ALWAYS_FATAL_IF(sInterfaceExists); + sInterfaceExists = true; +} + +GnssGeofencing::~GnssGeofencing() { + sThreadFuncArgsList.clear(); + sInterfaceExists = false; +} +void GnssGeofencing::gnssGfTransitionCb(int32_t geofenceId, + GpsLocation* location, + int32_t transition, + GpsUtcTime timestamp) { + if (mGnssGeofencingCbIface == nullptr) { + ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__); + return; + } + + if (location == nullptr) { + ALOGE("%s : Invalid location from GNSS HAL", __func__); + return; + } + + GnssLocation gnssLocation = convertToGnssLocation(location); + auto ret = mGnssGeofencingCbIface->gnssGeofenceTransitionCb( + geofenceId, + gnssLocation, + static_cast<IGnssGeofenceCallback::GeofenceTransition>(transition), + timestamp); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void GnssGeofencing::gnssGfStatusCb(int32_t status, GpsLocation* location) { + if (mGnssGeofencingCbIface == nullptr) { + ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__); + return; + } + + GnssLocation gnssLocation; + + if (location != nullptr) { + gnssLocation = convertToGnssLocation(location); + } else { + gnssLocation = {}; + } + + auto ret = mGnssGeofencingCbIface->gnssGeofenceStatusCb( + static_cast<IGnssGeofenceCallback::GeofenceAvailability>(status), gnssLocation); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void GnssGeofencing::gnssGfAddCb(int32_t geofenceId, int32_t status) { + if (mGnssGeofencingCbIface == nullptr) { + ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__); + return; + } + + auto ret = mGnssGeofencingCbIface->gnssGeofenceAddCb( + geofenceId, static_cast<IGnssGeofenceCallback::GeofenceStatus>(status)); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void GnssGeofencing::gnssGfRemoveCb(int32_t geofenceId, int32_t status) { + if (mGnssGeofencingCbIface == nullptr) { + ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__); + return; + } + + auto ret = mGnssGeofencingCbIface->gnssGeofenceRemoveCb( + geofenceId, static_cast<IGnssGeofenceCallback::GeofenceStatus>(status)); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void GnssGeofencing::gnssGfPauseCb(int32_t geofenceId, int32_t status) { + if (mGnssGeofencingCbIface == nullptr) { + ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__); + return; + } + + auto ret = mGnssGeofencingCbIface->gnssGeofencePauseCb( + geofenceId, static_cast<IGnssGeofenceCallback::GeofenceStatus>(status)); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +void GnssGeofencing::gnssGfResumeCb(int32_t geofenceId, int32_t status) { + if (mGnssGeofencingCbIface == nullptr) { + ALOGE("%s: GNSS Geofence Callback Interface configured incorrectly", __func__); + return; + } + + auto ret = mGnssGeofencingCbIface->gnssGeofenceResumeCb( + geofenceId, static_cast<IGnssGeofenceCallback::GeofenceStatus>(status)); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +pthread_t GnssGeofencing::createThreadCb(const char* name, void (*start)(void*), void* arg) { + return createPthread(name, start, arg, &sThreadFuncArgsList); +} + +// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow. +Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback) { + mGnssGeofencingCbIface = callback; + + if (mGnssGeofencingIface == nullptr) { + ALOGE("%s: GnssGeofencing interface is not available", __func__); + } else { + mGnssGeofencingIface->init(&sGnssGfCb); + } + + return Void(); +} + +Return<void> GnssGeofencing::addGeofence( + int32_t geofenceId, + double latitudeDegrees, + double longitudeDegrees, + double radiusMeters, + IGnssGeofenceCallback::GeofenceTransition lastTransition, + int32_t monitorTransitions, + uint32_t notificationResponsivenessMs, + uint32_t unknownTimerMs) { + if (mGnssGeofencingIface == nullptr) { + ALOGE("%s: GnssGeofencing interface is not available", __func__); + return Void(); + } else { + mGnssGeofencingIface->add_geofence_area( + geofenceId, + latitudeDegrees, + longitudeDegrees, + radiusMeters, + static_cast<int32_t>(lastTransition), + monitorTransitions, + notificationResponsivenessMs, + unknownTimerMs); + } + return Void(); +} + +Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId) { + if (mGnssGeofencingIface == nullptr) { + ALOGE("%s: GnssGeofencing interface is not available", __func__); + } else { + mGnssGeofencingIface->pause_geofence(geofenceId); + } + return Void(); +} + +Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) { + if (mGnssGeofencingIface == nullptr) { + ALOGE("%s: GnssGeofencing interface is not available", __func__); + } else { + mGnssGeofencingIface->resume_geofence(geofenceId, monitorTransitions); + } + return Void(); +} + +Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId) { + if (mGnssGeofencingIface == nullptr) { + ALOGE("%s: GnssGeofencing interface is not available", __func__); + } else { + mGnssGeofencingIface->remove_geofence_area(geofenceId); + } + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/GnssGeofencing.h b/gnss/1.0/default/GnssGeofencing.h new file mode 100644 index 0000000..124b893 --- /dev/null +++ b/gnss/1.0/default/GnssGeofencing.h
@@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_gnss_V1_0_GnssGeofencing_H_ +#define android_hardware_gnss_V1_0_GnssGeofencing_H_ + +#include <ThreadCreationWrapper.h> +#include <android/hardware/gnss/1.0/IGnssGeofencing.h> +#include <hidl/Status.h> +#include <hardware/gps.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback; +using ::android::hardware::gnss::V1_0::IGnssGeofencing; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* + * Interface for GNSS Geofencing support. It also contains wrapper methods to allow + * methods from IGnssGeofenceCallback interface to be passed into the + * conventional implementation of the GNSS HAL. + */ +struct GnssGeofencing : public IGnssGeofencing { + GnssGeofencing(const GpsGeofencingInterface* gpsGeofencingIface); + ~GnssGeofencing(); + + /* + * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow. + * These declarations were generated from IGnssGeofencing.hal. + */ + Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback) override; + Return<void> addGeofence(int32_t geofenceId, + double latitudeDegrees, + double longitudeDegrees, + double radiusMeters, + IGnssGeofenceCallback::GeofenceTransition lastTransition, + int32_t monitorTransitions, + uint32_t notificationResponsivenessMs, + uint32_t unknownTimerMs) override; + + Return<void> pauseGeofence(int32_t geofenceId) override; + Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions) override; + Return<void> removeGeofence(int32_t geofenceId) override; + + /* + * Callback methods to be passed into the conventional GNSS HAL by the default + * implementation. These methods are not part of the IGnssGeofencing base class. + */ + static void gnssGfTransitionCb(int32_t geofence_id, GpsLocation* location, + int32_t transition, GpsUtcTime timestamp); + static void gnssGfStatusCb(int32_t status, GpsLocation* last_location); + static void gnssGfAddCb(int32_t geofence_id, int32_t status); + static void gnssGfRemoveCb(int32_t geofence_id, int32_t status); + static void gnssGfPauseCb(int32_t geofence_id, int32_t status); + static void gnssGfResumeCb(int32_t geofence_id, int32_t status); + static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg); + + /* + * Holds function pointers to the callback methods. + */ + static GpsGeofenceCallbacks sGnssGfCb; + + private: + static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList; + static sp<IGnssGeofenceCallback> mGnssGeofencingCbIface; + const GpsGeofencingInterface* mGnssGeofencingIface = nullptr; + static bool sInterfaceExists; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_GnssGeofencing_H_
diff --git a/gnss/1.0/default/GnssMeasurement.cpp b/gnss/1.0/default/GnssMeasurement.cpp new file mode 100644 index 0000000..6c9b838 --- /dev/null +++ b/gnss/1.0/default/GnssMeasurement.cpp
@@ -0,0 +1,261 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_GnssMeasurementInterface" + +#include "GnssMeasurement.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +sp<IGnssMeasurementCallback> GnssMeasurement::sGnssMeasureCbIface = nullptr; +GpsMeasurementCallbacks GnssMeasurement::sGnssMeasurementCbs = { + .size = sizeof(GpsMeasurementCallbacks), + .measurement_callback = gpsMeasurementCb, + .gnss_measurement_callback = gnssMeasurementCb +}; + +GnssMeasurement::GnssMeasurement(const GpsMeasurementInterface* gpsMeasurementIface) + : mGnssMeasureIface(gpsMeasurementIface) {} + +void GnssMeasurement::gnssMeasurementCb(LegacyGnssData* legacyGnssData) { + if (sGnssMeasureCbIface == nullptr) { + ALOGE("%s: GNSSMeasurement Callback Interface configured incorrectly", __func__); + return; + } + + if (legacyGnssData == nullptr) { + ALOGE("%s: Invalid GnssData from GNSS HAL", __func__); + return; + } + + IGnssMeasurementCallback::GnssData gnssData; + gnssData.measurementCount = std::min(legacyGnssData->measurement_count, + static_cast<size_t>(GnssMax::SVS_COUNT)); + + for (size_t i = 0; i < gnssData.measurementCount; i++) { + auto entry = legacyGnssData->measurements[i]; + auto state = static_cast<GnssMeasurementState>(entry.state); + if (state & IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED) { + state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_KNOWN; + } + if (state & IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED) { + state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_KNOWN; + } + gnssData.measurements[i] = { + .flags = entry.flags, + .svid = entry.svid, + .constellation = static_cast<GnssConstellationType>(entry.constellation), + .timeOffsetNs = entry.time_offset_ns, + .state = state, + .receivedSvTimeInNs = entry.received_sv_time_in_ns, + .receivedSvTimeUncertaintyInNs = entry.received_sv_time_uncertainty_in_ns, + .cN0DbHz = entry.c_n0_dbhz, + .pseudorangeRateMps = entry.pseudorange_rate_mps, + .pseudorangeRateUncertaintyMps = entry.pseudorange_rate_uncertainty_mps, + .accumulatedDeltaRangeState = entry.accumulated_delta_range_state, + .accumulatedDeltaRangeM = entry.accumulated_delta_range_m, + .accumulatedDeltaRangeUncertaintyM = entry.accumulated_delta_range_uncertainty_m, + .carrierFrequencyHz = entry.carrier_frequency_hz, + .carrierCycles = entry.carrier_cycles, + .carrierPhase = entry.carrier_phase, + .carrierPhaseUncertainty = entry.carrier_phase_uncertainty, + .multipathIndicator = static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>( + entry.multipath_indicator), + .snrDb = entry.snr_db + }; + } + + auto clockVal = legacyGnssData->clock; + gnssData.clock = { + .gnssClockFlags = clockVal.flags, + .leapSecond = clockVal.leap_second, + .timeNs = clockVal.time_ns, + .timeUncertaintyNs = clockVal.time_uncertainty_ns, + .fullBiasNs = clockVal.full_bias_ns, + .biasNs = clockVal.bias_ns, + .biasUncertaintyNs = clockVal.bias_uncertainty_ns, + .driftNsps = clockVal.drift_nsps, + .driftUncertaintyNsps = clockVal.drift_uncertainty_nsps, + .hwClockDiscontinuityCount = clockVal.hw_clock_discontinuity_count + }; + + auto ret = sGnssMeasureCbIface->GnssMeasurementCb(gnssData); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +/* + * The code in the following method has been moved here from GnssLocationProvider. + * It converts GpsData to GnssData. This code is no longer required in + * GnssLocationProvider since GpsData is deprecated and no longer part of the + * GNSS interface. + */ +void GnssMeasurement::gpsMeasurementCb(GpsData* gpsData) { + if (sGnssMeasureCbIface == nullptr) { + ALOGE("%s: GNSSMeasurement Callback Interface configured incorrectly", __func__); + return; + } + + if (gpsData == nullptr) { + ALOGE("%s: Invalid GpsData from GNSS HAL", __func__); + return; + } + + IGnssMeasurementCallback::GnssData gnssData; + gnssData.measurementCount = std::min(gpsData->measurement_count, + static_cast<size_t>(GnssMax::SVS_COUNT)); + + + for (size_t i = 0; i < gnssData.measurementCount; i++) { + auto entry = gpsData->measurements[i]; + gnssData.measurements[i].flags = entry.flags; + gnssData.measurements[i].svid = static_cast<int32_t>(entry.prn); + if (entry.prn >= 1 && entry.prn <= 32) { + gnssData.measurements[i].constellation = GnssConstellationType::GPS; + } else { + gnssData.measurements[i].constellation = + GnssConstellationType::UNKNOWN; + } + + gnssData.measurements[i].timeOffsetNs = entry.time_offset_ns; + gnssData.measurements[i].state = entry.state; + gnssData.measurements[i].receivedSvTimeInNs = entry.received_gps_tow_ns; + gnssData.measurements[i].receivedSvTimeUncertaintyInNs = + entry.received_gps_tow_uncertainty_ns; + gnssData.measurements[i].cN0DbHz = entry.c_n0_dbhz; + gnssData.measurements[i].pseudorangeRateMps = entry.pseudorange_rate_mps; + gnssData.measurements[i].pseudorangeRateUncertaintyMps = + entry.pseudorange_rate_uncertainty_mps; + gnssData.measurements[i].accumulatedDeltaRangeState = + entry.accumulated_delta_range_state; + gnssData.measurements[i].accumulatedDeltaRangeM = + entry.accumulated_delta_range_m; + gnssData.measurements[i].accumulatedDeltaRangeUncertaintyM = + entry.accumulated_delta_range_uncertainty_m; + + if (entry.flags & GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY) { + gnssData.measurements[i].carrierFrequencyHz = entry.carrier_frequency_hz; + } else { + gnssData.measurements[i].carrierFrequencyHz = 0; + } + + if (entry.flags & GNSS_MEASUREMENT_HAS_CARRIER_PHASE) { + gnssData.measurements[i].carrierPhase = entry.carrier_phase; + } else { + gnssData.measurements[i].carrierPhase = 0; + } + + if (entry.flags & GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY) { + gnssData.measurements[i].carrierPhaseUncertainty = entry.carrier_phase_uncertainty; + } else { + gnssData.measurements[i].carrierPhaseUncertainty = 0; + } + + gnssData.measurements[i].multipathIndicator = + static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>( + entry.multipath_indicator); + + if (entry.flags & GNSS_MEASUREMENT_HAS_SNR) { + gnssData.measurements[i].snrDb = entry.snr_db; + } else { + gnssData.measurements[i].snrDb = 0; + } + } + + auto clockVal = gpsData->clock; + static uint32_t discontinuity_count_to_handle_old_clock_type = 0; + auto flags = clockVal.flags; + + gnssData.clock.leapSecond = clockVal.leap_second; + /* + * GnssClock only supports the more effective HW_CLOCK type, so type + * handling and documentation complexity has been removed. To convert the + * old GPS_CLOCK types (active only in a limited number of older devices), + * the GPS time information is handled as an always discontinuous HW clock, + * with the GPS time information put into the full_bias_ns instead - so that + * time_ns - full_bias_ns = local estimate of GPS time. Additionally, the + * sign of full_bias_ns and bias_ns has flipped between GpsClock & + * GnssClock, so that is also handled below. + */ + switch (clockVal.type) { + case GPS_CLOCK_TYPE_UNKNOWN: + // Clock type unsupported. + ALOGE("Unknown clock type provided."); + break; + case GPS_CLOCK_TYPE_LOCAL_HW_TIME: + // Already local hardware time. No need to do anything. + break; + case GPS_CLOCK_TYPE_GPS_TIME: + // GPS time, need to convert. + flags |= GPS_CLOCK_HAS_FULL_BIAS; + clockVal.full_bias_ns = clockVal.time_ns; + clockVal.time_ns = 0; + gnssData.clock.hwClockDiscontinuityCount = + discontinuity_count_to_handle_old_clock_type++; + break; + } + + gnssData.clock.timeNs = clockVal.time_ns; + gnssData.clock.timeUncertaintyNs = clockVal.time_uncertainty_ns; + /* + * Definition of sign for full_bias_ns & bias_ns has been changed since N, + * so flip signs here. + */ + gnssData.clock.fullBiasNs = -(clockVal.full_bias_ns); + gnssData.clock.biasNs = -(clockVal.bias_ns); + gnssData.clock.biasUncertaintyNs = clockVal.bias_uncertainty_ns; + gnssData.clock.driftNsps = clockVal.drift_nsps; + gnssData.clock.driftUncertaintyNsps = clockVal.drift_uncertainty_nsps; + gnssData.clock.gnssClockFlags = clockVal.flags; + + auto ret = sGnssMeasureCbIface->GnssMeasurementCb(gnssData); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow. +Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback( + const sp<IGnssMeasurementCallback>& callback) { + if (mGnssMeasureIface == nullptr) { + ALOGE("%s: GnssMeasure interface is unavailable", __func__); + return GnssMeasurementStatus::ERROR_GENERIC; + } + sGnssMeasureCbIface = callback; + + return static_cast<GnssMeasurement::GnssMeasurementStatus>( + mGnssMeasureIface->init(&sGnssMeasurementCbs)); +} + +Return<void> GnssMeasurement::close() { + if (mGnssMeasureIface == nullptr) { + ALOGE("%s: GnssMeasure interface is unavailable", __func__); + } else { + mGnssMeasureIface->close(); + } + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/GnssMeasurement.h b/gnss/1.0/default/GnssMeasurement.h new file mode 100644 index 0000000..9ff1435 --- /dev/null +++ b/gnss/1.0/default/GnssMeasurement.h
@@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_gnss_V1_0_GnssMeasurement_H_ +#define android_hardware_gnss_V1_0_GnssMeasurement_H_ + +#include <ThreadCreationWrapper.h> +#include <android/hardware/gnss/1.0/IGnssMeasurement.h> +#include <hidl/Status.h> +#include <hardware/gps.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IGnssMeasurement; +using ::android::hardware::gnss::V1_0::IGnssMeasurementCallback; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +using LegacyGnssData = ::GnssData; + +/* + * Extended interface for GNSS Measurements support. Also contains wrapper methods to allow methods + * from IGnssMeasurementCallback interface to be passed into the conventional implementation of the + * GNSS HAL. + */ +struct GnssMeasurement : public IGnssMeasurement { + GnssMeasurement(const GpsMeasurementInterface* gpsMeasurementIface); + + /* + * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow. + * These declarations were generated from IGnssMeasurement.hal. + */ + Return<GnssMeasurementStatus> setCallback( + const sp<IGnssMeasurementCallback>& callback) override; + Return<void> close() override; + + /* + * Callback methods to be passed into the conventional GNSS HAL by the default + * implementation. These methods are not part of the IGnssMeasurement base class. + */ + static void gnssMeasurementCb(LegacyGnssData* data); + /* + * Deprecated callback added for backward compatibity for devices that do + * not support GnssData measurements. + */ + static void gpsMeasurementCb(GpsData* data); + + /* + * Holds function pointers to the callback methods. + */ + static GpsMeasurementCallbacks sGnssMeasurementCbs; + + private: + const GpsMeasurementInterface* mGnssMeasureIface = nullptr; + static sp<IGnssMeasurementCallback> sGnssMeasureCbIface; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_GnssMeasurement_H_
diff --git a/gnss/1.0/default/GnssNavigationMessage.cpp b/gnss/1.0/default/GnssNavigationMessage.cpp new file mode 100644 index 0000000..6f509d0 --- /dev/null +++ b/gnss/1.0/default/GnssNavigationMessage.cpp
@@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_GnssNavigationMessageInterface" + +#include <log/log.h> + +#include "GnssNavigationMessage.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +sp<IGnssNavigationMessageCallback> GnssNavigationMessage::sGnssNavigationMsgCbIface = nullptr; + +GpsNavigationMessageCallbacks GnssNavigationMessage::sGnssNavigationMessageCb = { + .size = sizeof(GpsNavigationMessageCallbacks), + .navigation_message_callback = nullptr, + .gnss_navigation_message_callback = gnssNavigationMessageCb +}; + +GnssNavigationMessage::GnssNavigationMessage( + const GpsNavigationMessageInterface* gpsNavigationMessageIface) : + mGnssNavigationMessageIface(gpsNavigationMessageIface) {} + +void GnssNavigationMessage::gnssNavigationMessageCb(LegacyGnssNavigationMessage* message) { + if (sGnssNavigationMsgCbIface == nullptr) { + ALOGE("%s: GnssNavigation Message Callback Interface configured incorrectly", __func__); + return; + } + + if (message == nullptr) { + ALOGE("%s, received invalid GnssNavigationMessage from GNSS HAL", __func__); + return; + } + + IGnssNavigationMessageCallback::GnssNavigationMessage navigationMsg; + + navigationMsg.svid = message->svid; + navigationMsg.type = + static_cast<IGnssNavigationMessageCallback::GnssNavigationMessageType>(message->type); + navigationMsg.status = message->status; + navigationMsg.messageId = message->message_id; + navigationMsg.submessageId = message->submessage_id; + navigationMsg.data.setToExternal(message->data, message->data_length); + + auto ret = sGnssNavigationMsgCbIface->gnssNavigationMessageCb(navigationMsg); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +// Methods from ::android::hardware::gnss::V1_0::IGnssNavigationMessage follow. +Return<GnssNavigationMessage::GnssNavigationMessageStatus> GnssNavigationMessage::setCallback( + const sp<IGnssNavigationMessageCallback>& callback) { + if (mGnssNavigationMessageIface == nullptr) { + ALOGE("%s: GnssNavigationMessage not available", __func__); + return GnssNavigationMessageStatus::ERROR_GENERIC; + } + + sGnssNavigationMsgCbIface = callback; + + return static_cast<GnssNavigationMessage::GnssNavigationMessageStatus>( + mGnssNavigationMessageIface->init(&sGnssNavigationMessageCb)); +} + +Return<void> GnssNavigationMessage::close() { + if (mGnssNavigationMessageIface == nullptr) { + ALOGE("%s: GnssNavigationMessage not available", __func__); + } else { + mGnssNavigationMessageIface->close(); + } + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/GnssNavigationMessage.h b/gnss/1.0/default/GnssNavigationMessage.h new file mode 100644 index 0000000..882854b --- /dev/null +++ b/gnss/1.0/default/GnssNavigationMessage.h
@@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_gnss_V1_0_GnssNavigationMessage_H_ +#define android_hardware_gnss_V1_0_GnssNavigationMessage_H_ + +#include <android/hardware/gnss/1.0/IGnssNavigationMessage.h> +#include <hidl/Status.h> +#include <hardware/gps.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IGnssNavigationMessage; +using ::android::hardware::gnss::V1_0::IGnssNavigationMessageCallback; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +using LegacyGnssNavigationMessage = ::GnssNavigationMessage; + +/* + * Extended interface for GNSS navigation message reporting support. Also contains wrapper methods + * to allow methods from IGnssNavigationMessageCallback interface to be passed into the conventional + * implementation of the GNSS HAL. + */ +struct GnssNavigationMessage : public IGnssNavigationMessage { + GnssNavigationMessage(const GpsNavigationMessageInterface* gpsNavigationMessageIface); + + /* + * Methods from ::android::hardware::gnss::V1_0::IGnssNavigationMessage follow. + * These declarations were generated from IGnssNavigationMessage.hal. + */ + Return<GnssNavigationMessageStatus> setCallback( + const sp<IGnssNavigationMessageCallback>& callback) override; + Return<void> close() override; + + /* + * Callback methods to be passed into the conventional GNSS HAL by the default implementation. + * These methods are not part of the IGnssNavigationMessage base class. + */ + static void gnssNavigationMessageCb(LegacyGnssNavigationMessage* message); + + /* + * Holds function pointers to the callback methods. + */ + static GpsNavigationMessageCallbacks sGnssNavigationMessageCb; + private: + const GpsNavigationMessageInterface* mGnssNavigationMessageIface = nullptr; + static sp<IGnssNavigationMessageCallback> sGnssNavigationMsgCbIface; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_GnssNavigationMessage_H_
diff --git a/gnss/1.0/default/GnssNi.cpp b/gnss/1.0/default/GnssNi.cpp new file mode 100644 index 0000000..d17891d --- /dev/null +++ b/gnss/1.0/default/GnssNi.cpp
@@ -0,0 +1,109 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_GnssNiInterface" + +#include "GnssNi.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +std::vector<std::unique_ptr<ThreadFuncArgs>> GnssNi::sThreadFuncArgsList; +sp<IGnssNiCallback> GnssNi::sGnssNiCbIface = nullptr; +bool GnssNi::sInterfaceExists = false; + +GpsNiCallbacks GnssNi::sGnssNiCb = { + .notify_cb = niNotifyCb, + .create_thread_cb = createThreadCb +}; + +GnssNi::GnssNi(const GpsNiInterface* gpsNiIface) : mGnssNiIface(gpsNiIface) { + /* Error out if an instance of the interface already exists. */ + LOG_ALWAYS_FATAL_IF(sInterfaceExists); + sInterfaceExists = true; +} + +GnssNi::~GnssNi() { + sThreadFuncArgsList.clear(); + sInterfaceExists = false; +} + +pthread_t GnssNi::createThreadCb(const char* name, void (*start)(void*), void* arg) { + return createPthread(name, start, arg, &sThreadFuncArgsList); +} + +void GnssNi::niNotifyCb(GpsNiNotification* notification) { + if (sGnssNiCbIface == nullptr) { + ALOGE("%s: GNSS NI Callback Interface configured incorrectly", __func__); + return; + } + + if (notification == nullptr) { + ALOGE("%s: Invalid GpsNotification callback from GNSS HAL", __func__); + return; + } + + IGnssNiCallback::GnssNiNotification notificationGnss = { + .notificationId = notification->notification_id, + .niType = static_cast<IGnssNiCallback::GnssNiType>(notification->ni_type), + .notifyFlags = notification->notify_flags, + .timeoutSec = static_cast<uint32_t>(notification->timeout), + .defaultResponse = + static_cast<IGnssNiCallback::GnssUserResponseType>(notification->default_response), + .requestorId = notification->requestor_id, + .notificationMessage = notification->text, + .requestorIdEncoding = + static_cast<IGnssNiCallback::GnssNiEncodingType>(notification->requestor_id_encoding), + .notificationIdEncoding = + static_cast<IGnssNiCallback::GnssNiEncodingType>(notification->text_encoding) + }; + + auto ret = sGnssNiCbIface->niNotifyCb(notificationGnss); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow. +Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback) { + if (mGnssNiIface == nullptr) { + ALOGE("%s: GnssNi interface is unavailable", __func__); + return Void(); + } + + sGnssNiCbIface = callback; + + mGnssNiIface->init(&sGnssNiCb); + return Void(); +} + +Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse) { + if (mGnssNiIface == nullptr) { + ALOGE("%s: GnssNi interface is unavailable", __func__); + } else { + mGnssNiIface->respond(notifId, static_cast<GpsUserResponseType>(userResponse)); + } + return Void(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/GnssNi.h b/gnss/1.0/default/GnssNi.h new file mode 100644 index 0000000..fe850b1 --- /dev/null +++ b/gnss/1.0/default/GnssNi.h
@@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_gnss_V1_0_GnssNi_H_ +#define android_hardware_gnss_V1_0_GnssNi_H_ + +#include <ThreadCreationWrapper.h> +#include <android/hardware/gnss/1.0/IGnssNi.h> +#include <hidl/Status.h> +#include <hardware/gps.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IGnssNi; +using ::android::hardware::gnss::V1_0::IGnssNiCallback; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* + * Extended interface for Network-initiated (NI) support. This interface is used to respond to + * NI notifications originating from the HAL. Also contains wrapper methods to allow methods from + * IGnssNiCallback interface to be passed into the conventional implementation of the GNSS HAL. + */ +struct GnssNi : public IGnssNi { + GnssNi(const GpsNiInterface* gpsNiIface); + ~GnssNi(); + + /* + * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow. + * These declarations were generated from IGnssNi.hal. + */ + Return<void> setCallback(const sp<IGnssNiCallback>& callback) override; + Return<void> respond(int32_t notifId, + IGnssNiCallback::GnssUserResponseType userResponse) override; + + /* + * Callback methods to be passed into the conventional GNSS HAL by the default + * implementation. These methods are not part of the IGnssNi base class. + */ + static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg); + static void niNotifyCb(GpsNiNotification* notification); + + /* + * Holds function pointers to the callback methods. + */ + static GpsNiCallbacks sGnssNiCb; + + private: + const GpsNiInterface* mGnssNiIface = nullptr; + static sp<IGnssNiCallback> sGnssNiCbIface; + static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList; + static bool sInterfaceExists; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_GnssNi_H_
diff --git a/gnss/1.0/default/GnssUtils.cpp b/gnss/1.0/default/GnssUtils.cpp new file mode 100644 index 0000000..d9956d6 --- /dev/null +++ b/gnss/1.0/default/GnssUtils.cpp
@@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "GnssUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using android::hardware::gnss::V1_0::GnssLocation; + +GnssLocation convertToGnssLocation(GpsLocation* location) { + GnssLocation gnssLocation = {}; + if (location != nullptr) { + gnssLocation = { + // Bit operation AND with 1f below is needed to clear vertical accuracy, + // speed accuracy and bearing accuracy flags as some vendors are found + // to be setting these bits in pre-Android-O devices + .gnssLocationFlags = static_cast<uint16_t>(location->flags & 0x1f), + .latitudeDegrees = location->latitude, + .longitudeDegrees = location->longitude, + .altitudeMeters = location->altitude, + .speedMetersPerSec = location->speed, + .bearingDegrees = location->bearing, + .horizontalAccuracyMeters = location->accuracy, + // Older chipsets do not provide the following 3 fields, hence the flags + // HAS_VERTICAL_ACCURACY, HAS_SPEED_ACCURACY and HAS_BEARING_ACCURACY are + // not set and the field are set to zeros. + .verticalAccuracyMeters = 0, + .speedAccuracyMetersPerSecond = 0, + .bearingAccuracyDegrees = 0, + .timestamp = location->timestamp + }; + } + + return gnssLocation; +} + +GnssLocation convertToGnssLocation(FlpLocation* location) { + GnssLocation gnssLocation = {}; + if (location != nullptr) { + gnssLocation = { + // Bit mask applied (and 0's below) for same reason as above with GpsLocation + .gnssLocationFlags = static_cast<uint16_t>(location->flags & 0x1f), + .latitudeDegrees = location->latitude, + .longitudeDegrees = location->longitude, + .altitudeMeters = location->altitude, + .speedMetersPerSec = location->speed, + .bearingDegrees = location->bearing, + .horizontalAccuracyMeters = location->accuracy, + .verticalAccuracyMeters = 0, + .speedAccuracyMetersPerSecond = 0, + .bearingAccuracyDegrees = 0, + .timestamp = location->timestamp + }; + } + + return gnssLocation; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/GnssUtils.h b/gnss/1.0/default/GnssUtils.h new file mode 100644 index 0000000..38d4b2d --- /dev/null +++ b/gnss/1.0/default/GnssUtils.h
@@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef android_hardware_gnss_V1_0_GnssUtil_H_ +#define android_hardware_gnss_V1_0_GnssUtil_H_ + +#include <hardware/fused_location.h> +#include <hardware/gps.h> +#include <android/hardware/gnss/1.0/types.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +/* + * This method converts a GpsLocation struct to a GnssLocation + * struct. + */ +GnssLocation convertToGnssLocation(GpsLocation* location); + +/* + * This method converts an FlpLocation struct to a GnssLocation + * struct. + */ +GnssLocation convertToGnssLocation(FlpLocation* location); + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif
diff --git a/gnss/1.0/default/GnssXtra.cpp b/gnss/1.0/default/GnssXtra.cpp new file mode 100644 index 0000000..d124ce1 --- /dev/null +++ b/gnss/1.0/default/GnssXtra.cpp
@@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "GnssHAL_GnssXtraInterface" + +#include "GnssXtra.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +std::vector<std::unique_ptr<ThreadFuncArgs>> GnssXtra::sThreadFuncArgsList; +sp<IGnssXtraCallback> GnssXtra::sGnssXtraCbIface = nullptr; +bool GnssXtra::sInterfaceExists = false; + +GpsXtraCallbacks GnssXtra::sGnssXtraCb = { + .download_request_cb = gnssXtraDownloadRequestCb, + .create_thread_cb = createThreadCb, +}; + +GnssXtra::~GnssXtra() { + sThreadFuncArgsList.clear(); + sInterfaceExists = false; +} + +pthread_t GnssXtra::createThreadCb(const char* name, void (*start)(void*), void* arg) { + return createPthread(name, start, arg, &sThreadFuncArgsList); +} + +GnssXtra::GnssXtra(const GpsXtraInterface* xtraIface) : mGnssXtraIface(xtraIface) { + /* Error out if an instance of the interface already exists. */ + LOG_ALWAYS_FATAL_IF(sInterfaceExists); + sInterfaceExists = true; +} + +void GnssXtra::gnssXtraDownloadRequestCb() { + if (sGnssXtraCbIface == nullptr) { + ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__); + return; + } + + auto ret = sGnssXtraCbIface->downloadRequestCb(); + if (!ret.isOk()) { + ALOGE("%s: Unable to invoke callback", __func__); + } +} + +// Methods from ::android::hardware::gnss::V1_0::IGnssXtra follow. +Return<bool> GnssXtra::setCallback(const sp<IGnssXtraCallback>& callback) { + if (mGnssXtraIface == nullptr) { + ALOGE("%s: Gnss Xtra interface is unavailable", __func__); + return false; + } + + sGnssXtraCbIface = callback; + + return (mGnssXtraIface->init(&sGnssXtraCb) == 0); +} + +Return<bool> GnssXtra::injectXtraData(const hidl_string& xtraData) { + if (mGnssXtraIface == nullptr) { + ALOGE("%s: Gnss Xtra interface is unavailable", __func__); + return false; + } + + char* buf = new char[xtraData.size()]; + const char* data = xtraData.c_str(); + + memcpy(buf, data, xtraData.size()); + + int ret = mGnssXtraIface->inject_xtra_data(buf, xtraData.size()); + delete[] buf; + return (ret == 0); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android
diff --git a/gnss/1.0/default/GnssXtra.h b/gnss/1.0/default/GnssXtra.h new file mode 100644 index 0000000..7a0733a --- /dev/null +++ b/gnss/1.0/default/GnssXtra.h
@@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef android_hardware_gnss_V1_0_GnssXtra_H_ +#define android_hardware_gnss_V1_0_GnssXtra_H_ + +#include <ThreadCreationWrapper.h> +#include <android/hardware/gnss/1.0/IGnssXtra.h> +#include <hardware/gps.h> +#include <hidl/Status.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gnss::V1_0::IGnssXtra; +using ::android::hardware::gnss::V1_0::IGnssXtraCallback; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +/* + * This interface is used by the GNSS HAL to request the framework to download XTRA data. + * Also contains wrapper methods to allow methods from IGnssXtraCallback interface to be passed + * into the conventional implementation of the GNSS HAL. + */ +struct GnssXtra : public IGnssXtra { + GnssXtra(const GpsXtraInterface* xtraIface); + ~GnssXtra(); + + /* + * Methods from ::android::hardware::gnss::V1_0::IGnssXtra follow. + * These declarations were generated from IGnssXtra.hal. + */ + Return<bool> setCallback(const sp<IGnssXtraCallback>& callback) override; + Return<bool> injectXtraData(const hidl_string& xtraData) override; + + /* + * Callback methods to be passed into the conventional GNSS HAL by the default implementation. + * These methods are not part of the IGnssXtra base class. + */ + static pthread_t createThreadCb(const char* name, void (*start)(void*), void* arg); + static void gnssXtraDownloadRequestCb(); + + /* + * Holds function pointers to the callback methods. + */ + static GpsXtraCallbacks sGnssXtraCb; + + private: + const GpsXtraInterface* mGnssXtraIface = nullptr; + static sp<IGnssXtraCallback> sGnssXtraCbIface; + static std::vector<std::unique_ptr<ThreadFuncArgs>> sThreadFuncArgsList; + static bool sInterfaceExists; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_V1_0_GnssXtra_H_
diff --git a/gnss/1.0/default/ThreadCreationWrapper.cpp b/gnss/1.0/default/ThreadCreationWrapper.cpp new file mode 100644 index 0000000..2a5638f --- /dev/null +++ b/gnss/1.0/default/ThreadCreationWrapper.cpp
@@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <ThreadCreationWrapper.h> + +void* threadFunc(void* arg) { + ThreadFuncArgs* threadArgs = reinterpret_cast<ThreadFuncArgs*>(arg); + threadArgs->fptr(threadArgs->args); + return nullptr; +} + +pthread_t createPthread(const char* name, + void (*start)(void*), + void* arg, std::vector<std::unique_ptr<ThreadFuncArgs>> * listArgs) { + pthread_t threadId; + auto threadArgs = new ThreadFuncArgs(start, arg); + auto argPtr = std::unique_ptr<ThreadFuncArgs>(threadArgs); + + listArgs->push_back(std::move(argPtr)); + + int ret = pthread_create(&threadId, nullptr, threadFunc, reinterpret_cast<void*>( + threadArgs)); + if (ret != 0) { + ALOGE("pthread creation unsuccessful"); + } else { + pthread_setname_np(threadId, name); + } + return threadId; +}
diff --git a/gnss/1.0/default/ThreadCreationWrapper.h b/gnss/1.0/default/ThreadCreationWrapper.h new file mode 100644 index 0000000..df0a9e4 --- /dev/null +++ b/gnss/1.0/default/ThreadCreationWrapper.h
@@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_GNSS_THREADCREATIONWRAPPER_H +#define ANDROID_HARDWARE_GNSS_THREADCREATIONWRAPPER_H + +#include <pthread.h> +#include <vector> +#include <cutils/log.h> + +typedef void (*threadEntryFunc)(void* ret); + +/* + * This class facilitates createThreadCb methods in various GNSS interfaces to wrap + * pthread_create() from libc since its function signature differs from what is required by the + * conventional GNSS HAL. The arguments passed to pthread_create() need to be on heap and not on + * the stack of createThreadCb. + */ +struct ThreadFuncArgs { + ThreadFuncArgs(void (*start)(void*), void* arg) : fptr(start), args(arg) {} + + /* pointer to the function of type void()(void*) that needs to be wrapped */ + threadEntryFunc fptr; + /* argument for fptr to be called with */ + void* args; +}; + +/* + * This method is simply a wrapper. It is required since pthread_create() requires an entry + * function pointer of type void*()(void*) and the GNSS hal requires as input a function pointer of + * type void()(void*). + */ +void* threadFunc(void* arg); + +/* + * This method is called by createThreadCb with a pointer to the vector that + * holds the pointers to the thread arguments. The arg and start parameters are + * first used to create a ThreadFuncArgs object which is then saved in the + * listArgs parameters. The created ThreadFuncArgs object is then used to invoke + * threadFunc() method which in-turn invokes pthread_create. + */ +pthread_t createPthread(const char* name, void (*start)(void*), void* arg, + std::vector<std::unique_ptr<ThreadFuncArgs>> * listArgs); + +#endif
diff --git a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc new file mode 100644 index 0000000..f1116f4 --- /dev/null +++ b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
@@ -0,0 +1,7 @@ +service gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service + class main + user system +# +# TODO:(b/35757613) - STOPSHIP - HAL cannot have direct inet access +# + group system inet
diff --git a/gnss/1.0/default/service.cpp b/gnss/1.0/default/service.cpp new file mode 100644 index 0000000..5a8acc1 --- /dev/null +++ b/gnss/1.0/default/service.cpp
@@ -0,0 +1,12 @@ +#define LOG_TAG "android.hardware.gnss@1.0-service" + +#include <android/hardware/gnss/1.0/IGnss.h> + +#include <hidl/LegacySupport.h> + +using android::hardware::gnss::V1_0::IGnss; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IGnss>(); +}
diff --git a/gnss/1.0/types.hal b/gnss/1.0/types.hal new file mode 100644 index 0000000..d5e0e9b --- /dev/null +++ b/gnss/1.0/types.hal
@@ -0,0 +1,112 @@ +/* + * Copyright (C) 2016 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.gnss@1.0; + +@export(name="", value_prefix="GNSS_MAX_") +enum GnssMax : uint32_t { +/** Maximum number of SVs for gnssSvStatusCb(). */ + SVS_COUNT = 64, +}; + +/* Milliseconds since January 1, 1970 */ +typedef int64_t GnssUtcTime; + +/* + * Constellation type of GnssSvInfo + */ + +@export(name="", value_prefix="GNSS_CONSTELLATION_") +enum GnssConstellationType : uint8_t { + UNKNOWN = 0, + GPS = 1, + SBAS = 2, + GLONASS = 3, + QZSS = 4, + BEIDOU = 5, + GALILEO = 6, +}; + +/** Bit mask to indicate which values are valid in a GnssLocation object. */ +@export(name="", value_prefix="GPS_LOCATION_") +enum GnssLocationFlags : uint16_t { + /** GnssLocation has valid latitude and longitude. */ + HAS_LAT_LONG = 0x0001, + /** GnssLocation has valid altitude. */ + HAS_ALTITUDE = 0x0002, + /** GnssLocation has valid speed. */ + HAS_SPEED = 0x0004, + /** GnssLocation has valid bearing. */ + HAS_BEARING = 0x0008, + /** GpsLocation has valid horizontal accuracy. */ + HAS_HORIZONTAL_ACCURACY = 0x0010, + /** GpsLocation has valid vertical accuracy. */ + HAS_VERTICAL_ACCURACY = 0x0020, + /** GpsLocation has valid speed accuracy. */ + HAS_SPEED_ACCURACY = 0x0040, + /** GpsLocation has valid bearing accuracy. */ + HAS_BEARING_ACCURACY = 0x0080 +}; + +/* Represents a location. */ +struct GnssLocation { + /* Contains GnssLocationFlags bits. */ + bitfield<GnssLocationFlags> gnssLocationFlags; + + /* Represents latitude in degrees. */ + double latitudeDegrees; + + /* Represents longitude in degrees. */ + double longitudeDegrees; + + /* + * Represents altitude in meters above the WGS 84 reference ellipsoid. + */ + double altitudeMeters; + + /* Represents speed in meters per second. */ + float speedMetersPerSec; + + /* Represents heading in degrees. */ + float bearingDegrees; + + /* + * Represents expected horizontal position accuracy, radial, in meters + * (68% confidence). + */ + float horizontalAccuracyMeters; + + /* + * Represents expected vertical position accuracy in meters + * (68% confidence). + */ + float verticalAccuracyMeters; + + /* + * Represents expected speed accuracy in meter per seconds + * (68% confidence). + */ + float speedAccuracyMetersPerSecond; + + /* + * Represents expected bearing accuracy in degrees + * (68% confidence). + */ + float bearingAccuracyDegrees; + + /* Timestamp for the location fix. */ + GnssUtcTime timestamp; +};
diff --git a/gnss/1.0/vts/functional/Android.bp b/gnss/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..6d96059 --- /dev/null +++ b/gnss/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@ +// +// Copyright (C) 2017 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. +// + +cc_test { + name: "VtsHalGnssV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalGnssV1_0TargetTest.cpp"], + shared_libs: [ + "android.hardware.gnss@1.0", + "libbase", + "libcutils", + "libhidlbase", + "libhidltransport", + "liblog", + "libnativehelper", + "libutils", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +} \ No newline at end of file
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp new file mode 100644 index 0000000..8f131cf --- /dev/null +++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -0,0 +1,279 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "VtsHalGnssV1_0TargetTest" +#include <android/hardware/gnss/1.0/IGnss.h> +#include <android/log.h> + +#include <VtsHalHidlTargetTestBase.h> + +#include <chrono> +#include <condition_variable> +#include <mutex> + +using android::hardware::Return; +using android::hardware::Void; + +using android::hardware::gnss::V1_0::GnssLocation; +using android::hardware::gnss::V1_0::GnssLocationFlags; +using android::hardware::gnss::V1_0::IGnss; +using android::hardware::gnss::V1_0::IGnssCallback; +using android::sp; + +#define TIMEOUT_SECONDS 5 // for basic commands/responses + +// The main test class for GNSS HAL. +class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + /* TODO(b/35678469): Setup the init.rc for VTS such that there's a + * single caller + * to the GNSS HAL - as part of confirming that the info & capabilities + * callbacks trigger. + */ + + gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>(); + ASSERT_NE(gnss_hal_, nullptr); + + gnss_cb_ = new GnssCallback(*this); + ASSERT_NE(gnss_cb_, nullptr); + + auto result = gnss_hal_->setCallback(gnss_cb_); + if (!result.isOk()) { + ALOGE("result of failed callback set %s", result.description().c_str()); + } + + ASSERT_TRUE(result.isOk()); + ASSERT_TRUE(result); + + /* TODO(b/35678469): Implement the capabilities & info (year) checks & + * value store here. + */ + } + + virtual void TearDown() override { + if (gnss_hal_ != nullptr) { + gnss_hal_->cleanup(); + } + } + + /* Used as a mechanism to inform the test that a callback has occurred */ + inline void notify() { + std::unique_lock<std::mutex> lock(mtx_); + count++; + cv_.notify_one(); + } + + /* Test code calls this function to wait for a callback */ + inline std::cv_status wait(int timeoutSeconds) { + std::unique_lock<std::mutex> lock(mtx_); + + std::cv_status status = std::cv_status::no_timeout; + auto now = std::chrono::system_clock::now(); + while (count == 0) { + status = cv_.wait_until(lock, now + std::chrono::seconds(timeoutSeconds)); + if (status == std::cv_status::timeout) return status; + } + count--; + return status; + } + + /* Callback class for data & Event. */ + class GnssCallback : public IGnssCallback { + GnssHalTest& parent_; + + public: + GnssCallback(GnssHalTest& parent) : parent_(parent){}; + + virtual ~GnssCallback() = default; + + // Dummy callback handlers + Return<void> gnssStatusCb( + const IGnssCallback::GnssStatusValue /* status */) override { + return Void(); + } + Return<void> gnssSvStatusCb( + const IGnssCallback::GnssSvStatus& /* svStatus */) override { + return Void(); + } + Return<void> gnssNmeaCb( + int64_t /* timestamp */, + const android::hardware::hidl_string& /* nmea */) override { + return Void(); + } + Return<void> gnssAcquireWakelockCb() override { return Void(); } + Return<void> gnssReleaseWakelockCb() override { return Void(); } + Return<void> gnssRequestTimeCb() override { return Void(); } + + // Actual (test) callback handlers + Return<void> gnssLocationCb(const GnssLocation& location) override { + ALOGI("Location received"); + parent_.location_called_count_++; + parent_.last_location_ = location; + parent_.notify(); + return Void(); + } + + Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override { + ALOGI("Capabilities received %d", capabilities); + parent_.capabilities_called_count_++; + parent_.last_capabilities_ = capabilities; + parent_.notify(); + return Void(); + } + + Return<void> gnssSetSystemInfoCb( + const IGnssCallback::GnssSystemInfo& info) override { + ALOGI("Info received, year %d", info.yearOfHw); + parent_.info_called_count_++; + parent_.last_info_ = info; + parent_.notify(); + return Void(); + } + }; + + sp<IGnss> gnss_hal_; // GNSS HAL to call into + sp<IGnssCallback> gnss_cb_; // Primary callback interface + + /* Count of calls to set the following items, and the latest item (used by + * test.) + */ + int capabilities_called_count_; + uint32_t last_capabilities_; + + int location_called_count_; + GnssLocation last_location_; + + int info_called_count_; + IGnssCallback::GnssSystemInfo last_info_; + + private: + std::mutex mtx_; + std::condition_variable cv_; + int count; +}; + +/* + * SetCallbackCapabilitiesCleanup: + * Sets up the callback, awaits the capabilities, and calls cleanup + * + * Since this is just the basic operation of SetUp() and TearDown(), + * the function definition is intentionally kept empty + */ +TEST_F(GnssHalTest, SetCallbackCapabilitiesCleanup) {} + +void CheckLocation(GnssLocation& location) { + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG); + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE); + EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED); + EXPECT_TRUE(location.gnssLocationFlags & + GnssLocationFlags::HAS_HORIZONTAL_ACCURACY); + EXPECT_GE(location.latitudeDegrees, -90.0); + EXPECT_LE(location.latitudeDegrees, 90.0); + EXPECT_GE(location.longitudeDegrees, -180.0); + EXPECT_LE(location.longitudeDegrees, 180.0); + EXPECT_GE(location.altitudeMeters, -1000.0); + EXPECT_LE(location.altitudeMeters, 30000.0); + EXPECT_GE(location.speedMetersPerSec, 0.0); + EXPECT_LE(location.speedMetersPerSec, 5.0); // VTS tests are stationary. + + /* + * Tolerating some especially high values for accuracy estimate, in case of + * first fix with especially poor geoemtry (happens occasionally) + */ + EXPECT_GT(location.horizontalAccuracyMeters, 0.0); + EXPECT_LE(location.horizontalAccuracyMeters, 200.0); + + /* + * Some devices may define bearing as -180 to +180, others as 0 to 360. + * Both are okay & understandable. + */ + if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) { + EXPECT_GE(location.bearingDegrees, -180.0); + EXPECT_LE(location.bearingDegrees, 360.0); + } + if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) { + EXPECT_GT(location.verticalAccuracyMeters, 0.0); + EXPECT_LE(location.verticalAccuracyMeters, 500.0); + } + if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) { + EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0); + EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0); + } + if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) { + EXPECT_GT(location.bearingAccuracyDegrees, 0.0); + EXPECT_LE(location.bearingAccuracyDegrees, 360.0); + } + + // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+) + EXPECT_GT(location.timestamp, 1.48e12); + + /* TODO(b/35678469): Check if the hardware year is 2017+, and if so, + * that bearing, plus vertical, speed & bearing accuracy are present. + * And allow bearing to be not present, only if associated with a speed of 0.0 + */ +} + +/* + * GetLocation: + * Turns on location, waits 45 second for at least 5 locations, + * and checks them for reasonable validity. + */ +TEST_F(GnssHalTest, GetLocation) { +#define MIN_INTERVAL_MSEC 500 +#define PREFERRED_ACCURACY 0 // Ideally perfect (matches GnssLocationProvider) +#define PREFERRED_TIME_MSEC 0 // Ideally immediate + +#define LOCATION_TIMEOUT_FIRST_SEC 45 +#define LOCATION_TIMEOUT_SUBSEQUENT_SEC 3 +#define LOCATIONS_TO_CHECK 5 + + auto result = gnss_hal_->setPositionMode( + IGnss::GnssPositionMode::MS_BASED, + IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC, MIN_INTERVAL_MSEC, + PREFERRED_ACCURACY, PREFERRED_TIME_MSEC); + + ASSERT_TRUE(result.isOk()); + ASSERT_TRUE(result); + + result = gnss_hal_->start(); + + ASSERT_TRUE(result.isOk()); + ASSERT_TRUE(result); + + EXPECT_EQ(std::cv_status::no_timeout, wait(LOCATION_TIMEOUT_FIRST_SEC)); + EXPECT_EQ(location_called_count_, 1); + CheckLocation(last_location_); + + for (int i = 1; i < LOCATIONS_TO_CHECK; i++) { + EXPECT_EQ(std::cv_status::no_timeout, + wait(LOCATION_TIMEOUT_SUBSEQUENT_SEC)); + EXPECT_EQ(location_called_count_, i + 1); + CheckLocation(last_location_); + } + + result = gnss_hal_->stop(); + + ASSERT_TRUE(result.isOk()); + ASSERT_TRUE(result); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +}
diff --git a/gnss/Android.bp b/gnss/Android.bp new file mode 100644 index 0000000..33f70eb --- /dev/null +++ b/gnss/Android.bp
@@ -0,0 +1,5 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/vts/functional", +]
diff --git a/graphics/Android.bp b/graphics/Android.bp new file mode 100644 index 0000000..eaa47ae --- /dev/null +++ b/graphics/Android.bp
@@ -0,0 +1,13 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "allocator/2.0", + "allocator/2.0/default", + "allocator/2.0/vts/functional", + "common/1.0", + "composer/2.1", + "composer/2.1/default", + "composer/2.1/vts/functional", + "mapper/2.0", + "mapper/2.0/default", + "mapper/2.0/vts/functional", +]
diff --git a/graphics/allocator/2.0/Android.bp b/graphics/allocator/2.0/Android.bp new file mode 100644 index 0000000..69ddd9b --- /dev/null +++ b/graphics/allocator/2.0/Android.bp
@@ -0,0 +1,71 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.graphics.allocator@2.0_hal", + srcs: [ + "types.hal", + "IAllocator.hal", + "IAllocatorClient.hal", + ], +} + +genrule { + name: "android.hardware.graphics.allocator@2.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.allocator@2.0", + srcs: [ + ":android.hardware.graphics.allocator@2.0_hal", + ], + out: [ + "android/hardware/graphics/allocator/2.0/types.cpp", + "android/hardware/graphics/allocator/2.0/AllocatorAll.cpp", + "android/hardware/graphics/allocator/2.0/AllocatorClientAll.cpp", + ], +} + +genrule { + name: "android.hardware.graphics.allocator@2.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.allocator@2.0", + srcs: [ + ":android.hardware.graphics.allocator@2.0_hal", + ], + out: [ + "android/hardware/graphics/allocator/2.0/types.h", + "android/hardware/graphics/allocator/2.0/IAllocator.h", + "android/hardware/graphics/allocator/2.0/IHwAllocator.h", + "android/hardware/graphics/allocator/2.0/BnHwAllocator.h", + "android/hardware/graphics/allocator/2.0/BpHwAllocator.h", + "android/hardware/graphics/allocator/2.0/BsAllocator.h", + "android/hardware/graphics/allocator/2.0/IAllocatorClient.h", + "android/hardware/graphics/allocator/2.0/IHwAllocatorClient.h", + "android/hardware/graphics/allocator/2.0/BnHwAllocatorClient.h", + "android/hardware/graphics/allocator/2.0/BpHwAllocatorClient.h", + "android/hardware/graphics/allocator/2.0/BsAllocatorClient.h", + ], +} + +cc_library_shared { + name: "android.hardware.graphics.allocator@2.0", + generated_sources: ["android.hardware.graphics.allocator@2.0_genc++"], + generated_headers: ["android.hardware.graphics.allocator@2.0_genc++_headers"], + export_generated_headers: ["android.hardware.graphics.allocator@2.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], +}
diff --git a/graphics/allocator/2.0/Android.mk b/graphics/allocator/2.0/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/graphics/allocator/2.0/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/graphics/allocator/2.0/IAllocator.hal b/graphics/allocator/2.0/IAllocator.hal new file mode 100644 index 0000000..00d07d5 --- /dev/null +++ b/graphics/allocator/2.0/IAllocator.hal
@@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 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.graphics.allocator@2.0; + +import IAllocatorClient; + +interface IAllocator { + enum Capability : int32_t { + /* reserved */ + INVALID = 0, + + /* + * IAllocatorClient::testAllocate must always return UNDEFINED unless + * this capability is supported. + */ + TEST_ALLOCATE = 1, + + /* + * IAllocatorClient::BufferDescriptorInfo::layerCount must be 1 unless + * this capability is supported. + */ + LAYERED_BUFFERS = 2, + }; + + /* + * Provides a list of supported capabilities (as described in the + * definition of Capability above). This list must not change after + * initialization. + * + * @return capabilities is a list of supported capabilities. + */ + @entry + @exit + @callflow(next="*") + getCapabilities() generates (vec<Capability> capabilities); + + /* + * Retrieves implementation-defined debug information, which will be + * displayed during, for example, `dumpsys SurfaceFlinger`. + * + * @return debugInfo is a string of debug information. + */ + @entry + @exit + @callflow(next="*") + dumpDebugInfo() generates (string debugInfo); + + /* + * Creates a client of the allocator. All resources created by the client + * are owned by the client and are only visible to the client, unless they + * are exported by exportHandle. + * + * @return error is NONE upon success. Otherwise, + * NO_RESOURCES when no more client can currently be created. + * @return client is the newly created client. + */ + @entry + @callflow(next="*") + createClient() generates (Error error, IAllocatorClient client); +};
diff --git a/graphics/allocator/2.0/IAllocatorClient.hal b/graphics/allocator/2.0/IAllocatorClient.hal new file mode 100644 index 0000000..080e3ea --- /dev/null +++ b/graphics/allocator/2.0/IAllocatorClient.hal
@@ -0,0 +1,165 @@ +/* + * Copyright (C) 2016 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.graphics.allocator@2.0; + +import android.hardware.graphics.common@1.0::PixelFormat; + +interface IAllocatorClient { + struct BufferDescriptorInfo { + /* + * The width specifies how many columns of pixels must be in the + * allocated buffer, but does not necessarily represent the offset in + * columns between the same column in adjacent rows. The rows may be + * padded. + */ + uint32_t width; + + /* + * The height specifies how many rows of pixels must be in the + * allocated buffer. + */ + uint32_t height; + + /* + * The number of image layers that must be in the allocated buffer. + */ + uint32_t layerCount; + + /* Buffer pixel format. */ + PixelFormat format; + + /* + * Buffer producer usage mask; valid flags can be found in the + * definition of ProducerUsage. + */ + uint64_t producerUsageMask; + + /* + * Buffer consumer usage mask; valid flags can be found in the + * definition of ConsumerUsage. + */ + uint64_t consumerUsageMask; + }; + + /* + * Creates a new, opaque buffer descriptor. + * + * @param descriptorInfo specifies the attributes of the buffer + * descriptor. + * @return error is NONE upon success. Otherwise, + * BAD_VALUE when any attribute in descriptorInfo is invalid. + * NO_RESOURCES when no more descriptors can currently be created. + * @return descriptor is the newly created buffer descriptor. + */ + @entry + @callflow(next="*") + createDescriptor(BufferDescriptorInfo descriptorInfo) + generates (Error error, + BufferDescriptor descriptor); + + /* + * Destroys an existing buffer descriptor. + * + * @param descriptor is the descriptor to destroy. + * @return error is either NONE or BAD_DESCRIPTOR. + */ + @exit + @callflow(next="*") + destroyDescriptor(BufferDescriptor descriptor) generates (Error error); + + /* + * Tests whether a buffer allocation can succeed, ignoring potential + * resource contention which might lead to a NO_RESOURCES error. + * + * @param descriptors is a list of buffer descriptors. + * @return error is NONE or NOT_SHARED upon success; + * NONE when buffers can be created and share a backing store. + * NOT_SHARED when buffers can be created but require more than a + * backing store. + * Otherwise, + * BAD_DESCRIPTOR when any of the descriptors is invalid. + * UNSUPPORTED when any of the descriptors can never be satisfied. + * UNDEFINED when TEST_ALLOCATE is not listed in getCapabilities. + */ + @callflow(next="allocate") + testAllocate(vec<BufferDescriptor> descriptors) generates (Error error); + + /* + * Attempts to allocate a list of buffers sharing a backing store. + * + * Each buffer must correspond to one of the descriptors passed into the + * function and must hold a reference to its backing store. If the device + * is unable to share the backing store between the buffers, it must + * attempt to allocate the buffers with different backing stores and + * return NOT_SHARED if it is successful. + * + * @param descriptors is the buffer descriptors to attempt to allocate. + * @return error is NONE or NOT_SHARED upon success; + * NONE when buffers can be created and share a backing store. + * NOT_SHARED when buffers can be created but require more than a + * backing store. + * Otherwise, + * BAD_DESCRIPTOR when any of the descriptors is invalid. + * UNSUPPORTED when any of the descriptors can never be satisfied. + * NO_RESOURCES when any of the buffers cannot be created at this + * time. + * @return buffers is the allocated buffers. + */ + @callflow(next="exportHandle") + allocate(vec<BufferDescriptor> descriptors) + generates (Error error, + vec<Buffer> buffers); + + /* + * Frees a buffer. + * + * @param buffer is the buffer to be freed. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer is invalid. + */ + @exit + @callflow(next="*") + free(Buffer buffer) generates (Error error); + + /* + * Exports a buffer for use in other client libraries or for cross-process + * sharing. + * + * The exported handle is a handle to the backing store of the buffer, not + * to the buffer itself. It however may not hold any reference to the + * backing store and may be considered invalid by client libraries. To use + * it and, in most cases, to save it for later use, a client must make a + * clone of the handle and have the cloned handle hold a reference to the + * backing store. Such a cloned handle will stay valid even after the + * original buffer is freed. Refer to native_handle_clone and IMapper for + * how a handle is cloned and how a reference is added. + * + * @param descriptor is the descriptor used to allocate the buffer. + * @param buffer is the buffer to be exported. + * @return error is NONE upon success. Otherwise, + * BAD_DESCRIPTOR when the descriptor is invalid. + * BAD_BUFFER when the buffer is invalid. + * BAD_VALUE when descriptor and buffer do not match. + * NO_RESOURCES when the buffer cannot be exported at this time. + * @return bufferHandle is the exported handle. + */ + @callflow(next="free") + exportHandle(BufferDescriptor descriptor, + Buffer buffer) + generates (Error error, + handle bufferHandle); +};
diff --git a/graphics/allocator/2.0/default/Android.bp b/graphics/allocator/2.0/default/Android.bp new file mode 100644 index 0000000..b8d4fde --- /dev/null +++ b/graphics/allocator/2.0/default/Android.bp
@@ -0,0 +1,44 @@ +cc_library_shared { + name: "android.hardware.graphics.allocator@2.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["Gralloc.cpp"], + cppflags: ["-Wall", "-Wextra"], + shared_libs: [ + "android.hardware.graphics.allocator@2.0", + "libbase", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], +} + +cc_binary { + name: "android.hardware.graphics.allocator@2.0-service", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["service.cpp"], + init_rc: ["android.hardware.graphics.allocator@2.0-service.rc"], + + shared_libs: [ + "android.hardware.graphics.allocator@2.0", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], +} + +cc_library_static { + name: "libgralloc1-adapter", + defaults: ["hidl_defaults"], + srcs: ["gralloc1-adapter.cpp", "Gralloc1On0Adapter.cpp"], + include_dirs: ["system/core/libsync/include"], + cflags: ["-Wall", "-Wextra", "-Wno-unused-parameter"], + export_include_dirs: ["."], +}
diff --git a/graphics/allocator/2.0/default/Gralloc.cpp b/graphics/allocator/2.0/default/Gralloc.cpp new file mode 100644 index 0000000..0b9e863 --- /dev/null +++ b/graphics/allocator/2.0/default/Gralloc.cpp
@@ -0,0 +1,471 @@ +/* + * Copyright 2016 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. + */ + +#define LOG_TAG "GrallocPassthrough" + +#include <mutex> +#include <type_traits> +#include <unordered_set> +#include <vector> + +#include <string.h> + +#include <hardware/gralloc1.h> +#include <log/log.h> + +#include "Gralloc.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace allocator { +namespace V2_0 { +namespace implementation { + +class GrallocHal : public IAllocator { +public: + GrallocHal(const hw_module_t* module); + virtual ~GrallocHal(); + + // IAllocator interface + Return<void> getCapabilities(getCapabilities_cb hidl_cb) override; + Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; + Return<void> createClient(createClient_cb hidl_cb) override; + + Error createDescriptor( + const IAllocatorClient::BufferDescriptorInfo& descriptorInfo, + BufferDescriptor* outDescriptor); + Error destroyDescriptor(BufferDescriptor descriptor); + + Error testAllocate(const hidl_vec<BufferDescriptor>& descriptors); + Error allocate(const hidl_vec<BufferDescriptor>& descriptors, + hidl_vec<Buffer>* outBuffers); + Error free(Buffer buffer); + + Error exportHandle(Buffer buffer, const native_handle_t** outHandle); + +private: + void initCapabilities(); + + template<typename T> + void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn); + void initDispatch(); + + bool hasCapability(Capability capability) const; + + gralloc1_device_t* mDevice; + + std::unordered_set<Capability> mCapabilities; + + struct { + GRALLOC1_PFN_DUMP dump; + GRALLOC1_PFN_CREATE_DESCRIPTOR createDescriptor; + GRALLOC1_PFN_DESTROY_DESCRIPTOR destroyDescriptor; + GRALLOC1_PFN_SET_DIMENSIONS setDimensions; + GRALLOC1_PFN_SET_FORMAT setFormat; + GRALLOC1_PFN_SET_LAYER_COUNT setLayerCount; + GRALLOC1_PFN_SET_CONSUMER_USAGE setConsumerUsage; + GRALLOC1_PFN_SET_PRODUCER_USAGE setProducerUsage; + GRALLOC1_PFN_ALLOCATE allocate; + GRALLOC1_PFN_RELEASE release; + } mDispatch; +}; + +class GrallocClient : public IAllocatorClient { +public: + GrallocClient(GrallocHal& hal); + virtual ~GrallocClient(); + + // IAllocatorClient interface + Return<void> createDescriptor(const BufferDescriptorInfo& descriptorInfo, + createDescriptor_cb hidl_cb) override; + Return<Error> destroyDescriptor(BufferDescriptor descriptor) override; + + Return<Error> testAllocate( + const hidl_vec<BufferDescriptor>& descriptors) override; + Return<void> allocate(const hidl_vec<BufferDescriptor>& descriptors, + allocate_cb hidl_cb) override; + Return<Error> free(Buffer buffer) override; + + Return<void> exportHandle(BufferDescriptor descriptor, + Buffer buffer, exportHandle_cb hidl_cb) override; + +private: + GrallocHal& mHal; + + std::mutex mMutex; + std::unordered_set<BufferDescriptor> mDescriptors; + std::unordered_set<Buffer> mBuffers; +}; + +GrallocHal::GrallocHal(const hw_module_t* module) + : mDevice(nullptr), mDispatch() +{ + int status = gralloc1_open(module, &mDevice); + if (status) { + LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s", + strerror(-status)); + } + + initCapabilities(); + initDispatch(); +} + +GrallocHal::~GrallocHal() +{ + gralloc1_close(mDevice); +} + +void GrallocHal::initCapabilities() +{ + uint32_t count = 0; + mDevice->getCapabilities(mDevice, &count, nullptr); + + std::vector<Capability> caps(count); + mDevice->getCapabilities(mDevice, &count, reinterpret_cast< + std::underlying_type<Capability>::type*>(caps.data())); + caps.resize(count); + + mCapabilities.insert(caps.cbegin(), caps.cend()); +} + +template<typename T> +void GrallocHal::initDispatch(gralloc1_function_descriptor_t desc, T* outPfn) +{ + auto pfn = mDevice->getFunction(mDevice, desc); + if (!pfn) { + LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc); + } + + *outPfn = reinterpret_cast<T>(pfn); +} + +void GrallocHal::initDispatch() +{ + initDispatch(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump); + initDispatch(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR, + &mDispatch.createDescriptor); + initDispatch(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR, + &mDispatch.destroyDescriptor); + initDispatch(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions); + initDispatch(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat); + if (hasCapability(Capability::LAYERED_BUFFERS)) { + initDispatch(GRALLOC1_FUNCTION_SET_LAYER_COUNT, + &mDispatch.setLayerCount); + } + initDispatch(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE, + &mDispatch.setConsumerUsage); + initDispatch(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE, + &mDispatch.setProducerUsage); + initDispatch(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate); + initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release); +} + +bool GrallocHal::hasCapability(Capability capability) const +{ + return (mCapabilities.count(capability) > 0); +} + +Return<void> GrallocHal::getCapabilities(getCapabilities_cb hidl_cb) +{ + std::vector<Capability> caps( + mCapabilities.cbegin(), mCapabilities.cend()); + + hidl_vec<Capability> reply; + reply.setToExternal(caps.data(), caps.size()); + hidl_cb(reply); + + return Void(); +} + +Return<void> GrallocHal::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) +{ + uint32_t len = 0; + mDispatch.dump(mDevice, &len, nullptr); + + std::vector<char> buf(len + 1); + mDispatch.dump(mDevice, &len, buf.data()); + buf.resize(len + 1); + buf[len] = '\0'; + + hidl_string reply; + reply.setToExternal(buf.data(), len); + hidl_cb(reply); + + return Void(); +} + +Return<void> GrallocHal::createClient(createClient_cb hidl_cb) +{ + sp<IAllocatorClient> client = new GrallocClient(*this); + hidl_cb(Error::NONE, client); + + return Void(); +} + +Error GrallocHal::createDescriptor( + const IAllocatorClient::BufferDescriptorInfo& descriptorInfo, + BufferDescriptor* outDescriptor) +{ + gralloc1_buffer_descriptor_t descriptor; + int32_t err = mDispatch.createDescriptor(mDevice, &descriptor); + if (err != GRALLOC1_ERROR_NONE) { + return static_cast<Error>(err); + } + + err = mDispatch.setDimensions(mDevice, descriptor, + descriptorInfo.width, descriptorInfo.height); + if (err == GRALLOC1_ERROR_NONE) { + err = mDispatch.setFormat(mDevice, descriptor, + static_cast<int32_t>(descriptorInfo.format)); + } + if (err == GRALLOC1_ERROR_NONE) { + if (hasCapability(Capability::LAYERED_BUFFERS)) { + err = mDispatch.setLayerCount(mDevice, descriptor, + descriptorInfo.layerCount); + } else if (descriptorInfo.layerCount != 1) { + err = GRALLOC1_ERROR_BAD_VALUE; + } + } + if (err == GRALLOC1_ERROR_NONE) { + uint64_t producerUsageMask = descriptorInfo.producerUsageMask; + if (producerUsageMask & GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN) { + producerUsageMask |= GRALLOC1_PRODUCER_USAGE_CPU_READ; + } + if (producerUsageMask & GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN) { + producerUsageMask |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE; + } + err = mDispatch.setProducerUsage(mDevice, descriptor, + descriptorInfo.producerUsageMask); + } + if (err == GRALLOC1_ERROR_NONE) { + uint64_t consumerUsageMask = descriptorInfo.consumerUsageMask; + if (consumerUsageMask & GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN) { + consumerUsageMask |= GRALLOC1_CONSUMER_USAGE_CPU_READ; + } + err = mDispatch.setConsumerUsage(mDevice, descriptor, + consumerUsageMask); + } + + if (err == GRALLOC1_ERROR_NONE) { + *outDescriptor = descriptor; + } else { + mDispatch.destroyDescriptor(mDevice, descriptor); + } + + return static_cast<Error>(err); +} + +Error GrallocHal::destroyDescriptor(BufferDescriptor descriptor) +{ + int32_t err = mDispatch.destroyDescriptor(mDevice, descriptor); + return static_cast<Error>(err); +} + +Error GrallocHal::testAllocate(const hidl_vec<BufferDescriptor>& descriptors) +{ + if (!hasCapability(Capability::TEST_ALLOCATE)) { + return Error::UNDEFINED; + } + + int32_t err = mDispatch.allocate(mDevice, descriptors.size(), + descriptors.data(), nullptr); + return static_cast<Error>(err); +} + +Error GrallocHal::allocate(const hidl_vec<BufferDescriptor>& descriptors, + hidl_vec<Buffer>* outBuffers) +{ + std::vector<buffer_handle_t> buffers(descriptors.size()); + int32_t err = mDispatch.allocate(mDevice, descriptors.size(), + descriptors.data(), buffers.data()); + if (err == GRALLOC1_ERROR_NONE || err == GRALLOC1_ERROR_NOT_SHARED) { + outBuffers->resize(buffers.size()); + for (size_t i = 0; i < outBuffers->size(); i++) { + (*outBuffers)[i] = static_cast<Buffer>( + reinterpret_cast<uintptr_t>(buffers[i])); + } + } + + return static_cast<Error>(err); +} + +Error GrallocHal::free(Buffer buffer) +{ + buffer_handle_t handle = reinterpret_cast<buffer_handle_t>( + static_cast<uintptr_t>(buffer)); + + int32_t err = mDispatch.release(mDevice, handle); + return static_cast<Error>(err); +} + +Error GrallocHal::exportHandle(Buffer buffer, + const native_handle_t** outHandle) +{ + // we rely on the caller to validate buffer here + *outHandle = reinterpret_cast<buffer_handle_t>( + static_cast<uintptr_t>(buffer)); + return Error::NONE; +} + +GrallocClient::GrallocClient(GrallocHal& hal) + : mHal(hal) +{ +} + +GrallocClient::~GrallocClient() +{ + if (!mBuffers.empty()) { + ALOGW("client destroyed with valid buffers"); + for (auto buf : mBuffers) { + mHal.free(buf); + } + } + + if (!mDescriptors.empty()) { + ALOGW("client destroyed with valid buffer descriptors"); + for (auto desc : mDescriptors) { + mHal.destroyDescriptor(desc); + } + } +} + +Return<void> GrallocClient::createDescriptor( + const BufferDescriptorInfo& descriptorInfo, + createDescriptor_cb hidl_cb) +{ + BufferDescriptor descriptor = 0; + Error err = mHal.createDescriptor(descriptorInfo, &descriptor); + + if (err == Error::NONE) { + std::lock_guard<std::mutex> lock(mMutex); + + auto result = mDescriptors.insert(descriptor); + if (!result.second) { + ALOGW("duplicated buffer descriptor id returned"); + mHal.destroyDescriptor(descriptor); + err = Error::NO_RESOURCES; + } + } + + hidl_cb(err, descriptor); + return Void(); +} + +Return<Error> GrallocClient::destroyDescriptor(BufferDescriptor descriptor) +{ + { + std::lock_guard<std::mutex> lock(mMutex); + if (!mDescriptors.erase(descriptor)) { + return Error::BAD_DESCRIPTOR; + } + } + + return mHal.destroyDescriptor(descriptor); +} + +Return<Error> GrallocClient::testAllocate( + const hidl_vec<BufferDescriptor>& descriptors) +{ + return mHal.testAllocate(descriptors); +} + +Return<void> GrallocClient::allocate( + const hidl_vec<BufferDescriptor>& descriptors, + allocate_cb hidl_cb) { + hidl_vec<Buffer> buffers; + Error err = mHal.allocate(descriptors, &buffers); + + if (err == Error::NONE || err == Error::NOT_SHARED) { + std::lock_guard<std::mutex> lock(mMutex); + + for (size_t i = 0; i < buffers.size(); i++) { + auto result = mBuffers.insert(buffers[i]); + if (!result.second) { + ALOGW("duplicated buffer id returned"); + + for (size_t j = 0; j < buffers.size(); j++) { + if (j < i) { + mBuffers.erase(buffers[i]); + } + mHal.free(buffers[i]); + } + + buffers = hidl_vec<Buffer>(); + err = Error::NO_RESOURCES; + break; + } + } + } + + hidl_cb(err, buffers); + return Void(); +} + +Return<Error> GrallocClient::free(Buffer buffer) +{ + { + std::lock_guard<std::mutex> lock(mMutex); + if (!mBuffers.erase(buffer)) { + return Error::BAD_BUFFER; + } + } + + return mHal.free(buffer); +} + +Return<void> GrallocClient::exportHandle(BufferDescriptor /*descriptor*/, + Buffer buffer, exportHandle_cb hidl_cb) +{ + const native_handle_t* handle = nullptr; + + { + std::lock_guard<std::mutex> lock(mMutex); + if (mBuffers.count(buffer) == 0) { + hidl_cb(Error::BAD_BUFFER, handle); + return Void(); + } + } + + Error err = mHal.exportHandle(buffer, &handle); + + hidl_cb(err, handle); + return Void(); +} + +IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) { + const hw_module_t* module = nullptr; + int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); + if (err) { + ALOGE("failed to get gralloc module"); + return nullptr; + } + + uint8_t major = (module->module_api_version >> 8) & 0xff; + if (major != 1) { + ALOGE("unknown gralloc module major version %d", major); + return nullptr; + } + + return new GrallocHal(module); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace allocator +} // namespace graphics +} // namespace hardware +} // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc.h b/graphics/allocator/2.0/default/Gralloc.h new file mode 100644 index 0000000..c79eeaa --- /dev/null +++ b/graphics/allocator/2.0/default/Gralloc.h
@@ -0,0 +1,38 @@ +/* + * Copyright 2016 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. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H +#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H + +#include <android/hardware/graphics/allocator/2.0/IAllocator.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace allocator { +namespace V2_0 { +namespace implementation { + +extern "C" IAllocator* HIDL_FETCH_IAllocator(const char* name); + +} // namespace implementation +} // namespace V2_0 +} // namespace allocator +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
diff --git a/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp b/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp new file mode 100644 index 0000000..4b9c9e1 --- /dev/null +++ b/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp
@@ -0,0 +1,560 @@ +/* + * Copyright 2016 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. + */ + +#undef LOG_TAG +#define LOG_TAG "Gralloc1On0Adapter" +//#define LOG_NDEBUG 0 + +#include "Gralloc1On0Adapter.h" +#include "gralloc1-adapter.h" + +#include <hardware/gralloc.h> + +#include <utils/Log.h> +#include <sync/sync.h> + +#include <inttypes.h> + +template <typename PFN, typename T> +static gralloc1_function_pointer_t asFP(T function) +{ + static_assert(std::is_same<PFN, T>::value, "Incompatible function pointer"); + return reinterpret_cast<gralloc1_function_pointer_t>(function); +} + +namespace android { +namespace hardware { + +Gralloc1On0Adapter::Gralloc1On0Adapter(const hw_module_t* module) + : gralloc1_device_t(), + mModule(reinterpret_cast<const gralloc_module_t*>(module)), + mDevice(nullptr) +{ + ALOGV("Constructing"); + + int minor = 0; + mModule->perform(mModule, + GRALLOC1_ADAPTER_PERFORM_GET_REAL_MODULE_API_VERSION_MINOR, + &minor); + mMinorVersion = minor; + + common.tag = HARDWARE_DEVICE_TAG, + common.version = HARDWARE_DEVICE_API_VERSION(0, 0), + common.module = const_cast<struct hw_module_t*>(module), + common.close = closeHook, + + getCapabilities = getCapabilitiesHook; + getFunction = getFunctionHook; + int error = ::gralloc_open(&(mModule->common), &mDevice); + if (error) { + ALOGE("Failed to open gralloc0 module: %d", error); + } + ALOGV("Opened gralloc0 device %p", mDevice); +} + +Gralloc1On0Adapter::~Gralloc1On0Adapter() +{ + ALOGV("Destructing"); + if (mDevice) { + ALOGV("Closing gralloc0 device %p", mDevice); + ::gralloc_close(mDevice); + } +} + +void Gralloc1On0Adapter::doGetCapabilities(uint32_t* outCount, + int32_t* outCapabilities) +{ + *outCount = 0; +} + +gralloc1_function_pointer_t Gralloc1On0Adapter::doGetFunction( + int32_t intDescriptor) +{ + constexpr auto lastDescriptor = + static_cast<int32_t>(GRALLOC1_LAST_FUNCTION); + if (intDescriptor < 0 || intDescriptor > lastDescriptor) { + ALOGE("Invalid function descriptor"); + return nullptr; + } + + auto descriptor = + static_cast<gralloc1_function_descriptor_t>(intDescriptor); + switch (descriptor) { + case GRALLOC1_FUNCTION_DUMP: + return asFP<GRALLOC1_PFN_DUMP>(dumpHook); + case GRALLOC1_FUNCTION_CREATE_DESCRIPTOR: + return asFP<GRALLOC1_PFN_CREATE_DESCRIPTOR>(createDescriptorHook); + case GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR: + return asFP<GRALLOC1_PFN_DESTROY_DESCRIPTOR>(destroyDescriptorHook); + case GRALLOC1_FUNCTION_SET_CONSUMER_USAGE: + return asFP<GRALLOC1_PFN_SET_CONSUMER_USAGE>(setConsumerUsageHook); + case GRALLOC1_FUNCTION_SET_DIMENSIONS: + return asFP<GRALLOC1_PFN_SET_DIMENSIONS>(setDimensionsHook); + case GRALLOC1_FUNCTION_SET_FORMAT: + return asFP<GRALLOC1_PFN_SET_FORMAT>(setFormatHook); + case GRALLOC1_FUNCTION_SET_LAYER_COUNT: + return asFP<GRALLOC1_PFN_SET_LAYER_COUNT>(setLayerCountHook); + case GRALLOC1_FUNCTION_SET_PRODUCER_USAGE: + return asFP<GRALLOC1_PFN_SET_PRODUCER_USAGE>(setProducerUsageHook); + case GRALLOC1_FUNCTION_GET_BACKING_STORE: + return asFP<GRALLOC1_PFN_GET_BACKING_STORE>( + bufferHook<decltype(&Buffer::getBackingStore), + &Buffer::getBackingStore, gralloc1_backing_store_t*>); + case GRALLOC1_FUNCTION_GET_CONSUMER_USAGE: + return asFP<GRALLOC1_PFN_GET_CONSUMER_USAGE>(getConsumerUsageHook); + case GRALLOC1_FUNCTION_GET_DIMENSIONS: + return asFP<GRALLOC1_PFN_GET_DIMENSIONS>( + bufferHook<decltype(&Buffer::getDimensions), + &Buffer::getDimensions, uint32_t*, uint32_t*>); + case GRALLOC1_FUNCTION_GET_FORMAT: + return asFP<GRALLOC1_PFN_GET_FORMAT>( + bufferHook<decltype(&Buffer::getFormat), + &Buffer::getFormat, int32_t*>); + case GRALLOC1_FUNCTION_GET_LAYER_COUNT: + return asFP<GRALLOC1_PFN_GET_LAYER_COUNT>( + bufferHook<decltype(&Buffer::getLayerCount), + &Buffer::getLayerCount, uint32_t*>); + case GRALLOC1_FUNCTION_GET_PRODUCER_USAGE: + return asFP<GRALLOC1_PFN_GET_PRODUCER_USAGE>(getProducerUsageHook); + case GRALLOC1_FUNCTION_GET_STRIDE: + return asFP<GRALLOC1_PFN_GET_STRIDE>( + bufferHook<decltype(&Buffer::getStride), + &Buffer::getStride, uint32_t*>); + case GRALLOC1_FUNCTION_ALLOCATE: + if (mDevice != nullptr) { + return asFP<GRALLOC1_PFN_ALLOCATE>(allocateHook); + } else { + return nullptr; + } + case GRALLOC1_FUNCTION_RETAIN: + return asFP<GRALLOC1_PFN_RETAIN>(retainHook); + case GRALLOC1_FUNCTION_RELEASE: + return asFP<GRALLOC1_PFN_RELEASE>(releaseHook); + case GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES: + return asFP<GRALLOC1_PFN_GET_NUM_FLEX_PLANES>( + bufferHook<decltype(&Buffer::getNumFlexPlanes), + &Buffer::getNumFlexPlanes, uint32_t*>); + case GRALLOC1_FUNCTION_LOCK: + return asFP<GRALLOC1_PFN_LOCK>( + lockHook<void*, &Gralloc1On0Adapter::lock>); + case GRALLOC1_FUNCTION_LOCK_FLEX: + return asFP<GRALLOC1_PFN_LOCK_FLEX>( + lockHook<struct android_flex_layout, + &Gralloc1On0Adapter::lockFlex>); + case GRALLOC1_FUNCTION_UNLOCK: + return asFP<GRALLOC1_PFN_UNLOCK>(unlockHook); + case GRALLOC1_FUNCTION_INVALID: + ALOGE("Invalid function descriptor"); + return nullptr; + } + + ALOGE("Unknown function descriptor: %d", intDescriptor); + return nullptr; +} + +void Gralloc1On0Adapter::dump(uint32_t* outSize, char* outBuffer) +{ + ALOGV("dump(%u (%p), %p", outSize ? *outSize : 0, outSize, outBuffer); + + if (!mDevice->dump) { + // dump is optional on gralloc0 implementations + *outSize = 0; + return; + } + + if (!outBuffer) { + constexpr int32_t BUFFER_LENGTH = 4096; + char buffer[BUFFER_LENGTH] = {}; + mDevice->dump(mDevice, buffer, BUFFER_LENGTH); + buffer[BUFFER_LENGTH - 1] = 0; // Ensure the buffer is null-terminated + size_t actualLength = std::strlen(buffer); + mCachedDump.resize(actualLength); + std::copy_n(buffer, actualLength, mCachedDump.begin()); + *outSize = static_cast<uint32_t>(actualLength); + } else { + *outSize = std::min(*outSize, + static_cast<uint32_t>(mCachedDump.size())); + outBuffer = std::copy_n(mCachedDump.cbegin(), *outSize, outBuffer); + } +} + +gralloc1_error_t Gralloc1On0Adapter::createDescriptor( + gralloc1_buffer_descriptor_t* outDescriptor) +{ + auto descriptorId = sNextBufferDescriptorId++; + std::lock_guard<std::mutex> lock(mDescriptorMutex); + mDescriptors.emplace(descriptorId, std::make_shared<Descriptor>()); + + ALOGV("Created descriptor %" PRIu64, descriptorId); + + *outDescriptor = descriptorId; + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t Gralloc1On0Adapter::destroyDescriptor( + gralloc1_buffer_descriptor_t descriptor) +{ + ALOGV("Destroying descriptor %" PRIu64, descriptor); + + std::lock_guard<std::mutex> lock(mDescriptorMutex); + if (mDescriptors.count(descriptor) == 0) { + return GRALLOC1_ERROR_BAD_DESCRIPTOR; + } + + mDescriptors.erase(descriptor); + return GRALLOC1_ERROR_NONE; +} + +Gralloc1On0Adapter::Buffer::Buffer(buffer_handle_t handle, + gralloc1_backing_store_t store, const Descriptor& descriptor, + uint32_t stride, uint32_t numFlexPlanes, bool wasAllocated) + : mHandle(handle), + mReferenceCount(1), + mStore(store), + mDescriptor(descriptor), + mStride(stride), + mNumFlexPlanes(numFlexPlanes), + mWasAllocated(wasAllocated) {} + +gralloc1_error_t Gralloc1On0Adapter::allocate( + gralloc1_buffer_descriptor_t id, + const std::shared_ptr<Descriptor>& descriptor, + buffer_handle_t* outBufferHandle) +{ + ALOGV("allocate(%" PRIu64 ")", id); + + // If this function is being called, it's because we handed out its function + // pointer, which only occurs when mDevice has been loaded successfully and + // we are permitted to allocate + + int usage = static_cast<int>(descriptor->producerUsage) | + static_cast<int>(descriptor->consumerUsage); + buffer_handle_t handle = nullptr; + int stride = 0; + ALOGV("Calling alloc(%p, %u, %u, %i, %u)", mDevice, descriptor->width, + descriptor->height, descriptor->format, usage); + auto error = mDevice->alloc(mDevice, + static_cast<int>(descriptor->width), + static_cast<int>(descriptor->height), descriptor->format, + usage, &handle, &stride); + if (error != 0) { + ALOGE("gralloc0 allocation failed: %d (%s)", error, + strerror(-error)); + return GRALLOC1_ERROR_NO_RESOURCES; + } + + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_SET_USAGES, + handle, + static_cast<int>(descriptor->producerUsage), + static_cast<int>(descriptor->consumerUsage)); + + uint64_t backingStore = 0; + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_BACKING_STORE, + handle, &backingStore); + int numFlexPlanes = 0; + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_NUM_FLEX_PLANES, + handle, &numFlexPlanes); + + *outBufferHandle = handle; + auto buffer = std::make_shared<Buffer>(handle, backingStore, + *descriptor, stride, numFlexPlanes, true); + + std::lock_guard<std::mutex> lock(mBufferMutex); + mBuffers.emplace(handle, std::move(buffer)); + + return GRALLOC1_ERROR_NONE; +} + +int32_t Gralloc1On0Adapter::allocateHook(gralloc1_device* device, + uint32_t numDescriptors, + const gralloc1_buffer_descriptor_t* descriptors, + buffer_handle_t* outBuffers) +{ + if (!outBuffers) { + return GRALLOC1_ERROR_UNDEFINED; + } + + auto adapter = getAdapter(device); + + gralloc1_error_t error = GRALLOC1_ERROR_NONE; + uint32_t i; + for (i = 0; i < numDescriptors; i++) { + auto descriptor = adapter->getDescriptor(descriptors[i]); + if (!descriptor) { + error = GRALLOC1_ERROR_BAD_DESCRIPTOR; + break; + } + + buffer_handle_t bufferHandle = nullptr; + error = adapter->allocate(descriptors[i], descriptor, &bufferHandle); + if (error != GRALLOC1_ERROR_NONE) { + break; + } + + outBuffers[i] = bufferHandle; + } + + if (error == GRALLOC1_ERROR_NONE) { + if (numDescriptors > 1) { + error = GRALLOC1_ERROR_NOT_SHARED; + } + } else { + for (uint32_t j = 0; j < i; j++) { + adapter->release(adapter->getBuffer(outBuffers[j])); + outBuffers[j] = nullptr; + } + } + + return error; +} + +gralloc1_error_t Gralloc1On0Adapter::retain( + const std::shared_ptr<Buffer>& buffer) +{ + std::lock_guard<std::mutex> lock(mBufferMutex); + buffer->retain(); + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t Gralloc1On0Adapter::release( + const std::shared_ptr<Buffer>& buffer) +{ + std::lock_guard<std::mutex> lock(mBufferMutex); + if (!buffer->release()) { + return GRALLOC1_ERROR_NONE; + } + + buffer_handle_t handle = buffer->getHandle(); + if (buffer->wasAllocated()) { + ALOGV("Calling free(%p)", handle); + int result = mDevice->free(mDevice, handle); + if (result != 0) { + ALOGE("gralloc0 free failed: %d", result); + } + } else { + ALOGV("Calling unregisterBuffer(%p)", handle); + int result = mModule->unregisterBuffer(mModule, handle); + if (result != 0) { + ALOGE("gralloc0 unregister failed: %d", result); + } + } + + mBuffers.erase(handle); + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t Gralloc1On0Adapter::retain(buffer_handle_t bufferHandle) +{ + ALOGV("retain(%p)", bufferHandle); + + std::lock_guard<std::mutex> lock(mBufferMutex); + + if (mBuffers.count(bufferHandle) != 0) { + mBuffers[bufferHandle]->retain(); + return GRALLOC1_ERROR_NONE; + } + + ALOGV("Calling registerBuffer(%p)", bufferHandle); + int result = mModule->registerBuffer(mModule, bufferHandle); + if (result != 0) { + ALOGE("gralloc0 register failed: %d", result); + return GRALLOC1_ERROR_NO_RESOURCES; + } + + uint64_t backingStore = 0; + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_BACKING_STORE, + bufferHandle, &backingStore); + + int numFlexPlanes = 0; + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_NUM_FLEX_PLANES, + bufferHandle, &numFlexPlanes); + + int stride = 0; + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_STRIDE, + bufferHandle, &stride); + + int width = 0; + int height = 0; + int format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + int producerUsage = 0; + int consumerUsage = 0; + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_DIMENSIONS, + bufferHandle, &width, &height); + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_FORMAT, + bufferHandle, &format); + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_PRODUCER_USAGE, + bufferHandle, &producerUsage); + mModule->perform(mModule, GRALLOC1_ADAPTER_PERFORM_GET_CONSUMER_USAGE, + bufferHandle, &consumerUsage); + + Descriptor descriptor; + descriptor.setDimensions(width, height); + descriptor.setFormat(format); + descriptor.setProducerUsage( + static_cast<gralloc1_producer_usage_t>(producerUsage)); + descriptor.setConsumerUsage( + static_cast<gralloc1_consumer_usage_t>(consumerUsage)); + + auto buffer = std::make_shared<Buffer>(bufferHandle, backingStore, + descriptor, stride, numFlexPlanes, false); + mBuffers.emplace(bufferHandle, std::move(buffer)); + return GRALLOC1_ERROR_NONE; +} + +static void syncWaitForever(int fd, const char* logname) +{ + if (fd < 0) { + return; + } + + const int warningTimeout = 3500; + const int error = sync_wait(fd, warningTimeout); + if (error < 0 && errno == ETIME) { + ALOGE("%s: fence %d didn't signal in %u ms", logname, fd, + warningTimeout); + sync_wait(fd, -1); + } +} + +gralloc1_error_t Gralloc1On0Adapter::lock( + const std::shared_ptr<Buffer>& buffer, + gralloc1_producer_usage_t producerUsage, + gralloc1_consumer_usage_t consumerUsage, + const gralloc1_rect_t& accessRegion, void** outData, + int acquireFence) +{ + if (mMinorVersion >= 3) { + int result = mModule->lockAsync(mModule, buffer->getHandle(), + static_cast<int32_t>(producerUsage | consumerUsage), + accessRegion.left, accessRegion.top, accessRegion.width, + accessRegion.height, outData, acquireFence); + if (result != 0) { + return GRALLOC1_ERROR_UNSUPPORTED; + } + } else { + syncWaitForever(acquireFence, "Gralloc1On0Adapter::lock"); + + int result = mModule->lock(mModule, buffer->getHandle(), + static_cast<int32_t>(producerUsage | consumerUsage), + accessRegion.left, accessRegion.top, accessRegion.width, + accessRegion.height, outData); + ALOGV("gralloc0 lock returned %d", result); + if (result != 0) { + return GRALLOC1_ERROR_UNSUPPORTED; + } else if (acquireFence >= 0) { + close(acquireFence); + } + } + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t Gralloc1On0Adapter::lockFlex( + const std::shared_ptr<Buffer>& buffer, + gralloc1_producer_usage_t producerUsage, + gralloc1_consumer_usage_t consumerUsage, + const gralloc1_rect_t& accessRegion, + struct android_flex_layout* outFlex, + int acquireFence) +{ + if (mMinorVersion >= 3) { + int result = mModule->perform(mModule, + GRALLOC1_ADAPTER_PERFORM_LOCK_FLEX, + buffer->getHandle(), + static_cast<int>(producerUsage), + static_cast<int>(consumerUsage), + accessRegion.left, + accessRegion.top, + accessRegion.width, + accessRegion.height, + outFlex, acquireFence); + if (result != 0) { + return GRALLOC1_ERROR_UNSUPPORTED; + } + } else { + syncWaitForever(acquireFence, "Gralloc1On0Adapter::lockFlex"); + + int result = mModule->perform(mModule, + GRALLOC1_ADAPTER_PERFORM_LOCK_FLEX, + buffer->getHandle(), + static_cast<int>(producerUsage), + static_cast<int>(consumerUsage), + accessRegion.left, + accessRegion.top, + accessRegion.width, + accessRegion.height, + outFlex, -1); + if (result != 0) { + return GRALLOC1_ERROR_UNSUPPORTED; + } else if (acquireFence >= 0) { + close(acquireFence); + } + } + + return GRALLOC1_ERROR_NONE; +} + +gralloc1_error_t Gralloc1On0Adapter::unlock( + const std::shared_ptr<Buffer>& buffer, + int* outReleaseFence) +{ + if (mMinorVersion >= 3) { + int fenceFd = -1; + int result = mModule->unlockAsync(mModule, buffer->getHandle(), + &fenceFd); + if (result != 0) { + close(fenceFd); + ALOGE("gralloc0 unlockAsync failed: %d", result); + } else { + *outReleaseFence = fenceFd; + } + } else { + int result = mModule->unlock(mModule, buffer->getHandle()); + if (result != 0) { + ALOGE("gralloc0 unlock failed: %d", result); + } else { + *outReleaseFence = -1; + } + } + return GRALLOC1_ERROR_NONE; +} + +std::shared_ptr<Gralloc1On0Adapter::Descriptor> +Gralloc1On0Adapter::getDescriptor(gralloc1_buffer_descriptor_t descriptorId) +{ + std::lock_guard<std::mutex> lock(mDescriptorMutex); + if (mDescriptors.count(descriptorId) == 0) { + return nullptr; + } + + return mDescriptors[descriptorId]; +} + +std::shared_ptr<Gralloc1On0Adapter::Buffer> Gralloc1On0Adapter::getBuffer( + buffer_handle_t bufferHandle) +{ + std::lock_guard<std::mutex> lock(mBufferMutex); + if (mBuffers.count(bufferHandle) == 0) { + return nullptr; + } + + return mBuffers[bufferHandle]; +} + +std::atomic<gralloc1_buffer_descriptor_t> + Gralloc1On0Adapter::sNextBufferDescriptorId(1); + +} // namespace hardware +} // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc1On0Adapter.h b/graphics/allocator/2.0/default/Gralloc1On0Adapter.h new file mode 100644 index 0000000..180015d --- /dev/null +++ b/graphics/allocator/2.0/default/Gralloc1On0Adapter.h
@@ -0,0 +1,458 @@ +/* + * Copyright 2016 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. + */ + +#ifndef ANDROID_HARDWARE_GRALLOC_1_ON_0_ADAPTER_H +#define ANDROID_HARDWARE_GRALLOC_1_ON_0_ADAPTER_H + +#include <hardware/gralloc1.h> +#include <log/log.h> + +#include <atomic> +#include <memory> +#include <mutex> +#include <string> +#include <unordered_map> +#include <utility> + +struct gralloc_module_t; +struct alloc_device_t; + +namespace android { +namespace hardware { + +class Gralloc1On0Adapter : public gralloc1_device_t +{ +public: + Gralloc1On0Adapter(const hw_module_t* module); + ~Gralloc1On0Adapter(); + + gralloc1_device_t* getDevice() { + return static_cast<gralloc1_device_t*>(this); + } + +private: + static inline Gralloc1On0Adapter* getAdapter(gralloc1_device_t* device) { + return static_cast<Gralloc1On0Adapter*>(device); + } + + static int closeHook(struct hw_device_t* device) { + delete getAdapter(reinterpret_cast<gralloc1_device_t*>(device)); + return 0; + } + + // getCapabilities + + void doGetCapabilities(uint32_t* outCount, + int32_t* /*gralloc1_capability_t*/ outCapabilities); + static void getCapabilitiesHook(gralloc1_device_t* device, + uint32_t* outCount, + int32_t* /*gralloc1_capability_t*/ outCapabilities) { + getAdapter(device)->doGetCapabilities(outCount, outCapabilities); + } + + // getFunction + + gralloc1_function_pointer_t doGetFunction( + int32_t /*gralloc1_function_descriptor_t*/ descriptor); + static gralloc1_function_pointer_t getFunctionHook( + gralloc1_device_t* device, + int32_t /*gralloc1_function_descriptor_t*/ descriptor) { + return getAdapter(device)->doGetFunction(descriptor); + } + + // dump + + void dump(uint32_t* outSize, char* outBuffer); + static void dumpHook(gralloc1_device_t* device, uint32_t* outSize, + char* outBuffer) { + return getAdapter(device)->dump(outSize, outBuffer); + } + std::string mCachedDump; + + // Buffer descriptor lifecycle functions + + struct Descriptor; + + gralloc1_error_t createDescriptor( + gralloc1_buffer_descriptor_t* outDescriptor); + static int32_t createDescriptorHook(gralloc1_device_t* device, + gralloc1_buffer_descriptor_t* outDescriptor) { + auto error = getAdapter(device)->createDescriptor(outDescriptor); + return static_cast<int32_t>(error); + } + + gralloc1_error_t destroyDescriptor(gralloc1_buffer_descriptor_t descriptor); + static int32_t destroyDescriptorHook(gralloc1_device_t* device, + gralloc1_buffer_descriptor_t descriptor) { + auto error = getAdapter(device)->destroyDescriptor(descriptor); + return static_cast<int32_t>(error); + } + + // Buffer descriptor modification functions + + struct Descriptor : public std::enable_shared_from_this<Descriptor> { + Descriptor() + : width(0), + height(0), + format(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), + layerCount(1), + producerUsage(GRALLOC1_PRODUCER_USAGE_NONE), + consumerUsage(GRALLOC1_CONSUMER_USAGE_NONE) {} + + gralloc1_error_t setDimensions(uint32_t w, uint32_t h) { + width = w; + height = h; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t setFormat(int32_t f) { + format = f; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t setLayerCount(uint32_t lc) { + layerCount = lc; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t setProducerUsage(gralloc1_producer_usage_t usage) { + producerUsage = usage; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t setConsumerUsage(gralloc1_consumer_usage_t usage) { + consumerUsage = usage; + return GRALLOC1_ERROR_NONE; + } + + uint32_t width; + uint32_t height; + int32_t format; + uint32_t layerCount; + gralloc1_producer_usage_t producerUsage; + gralloc1_consumer_usage_t consumerUsage; + }; + + template <typename ...Args> + static int32_t callDescriptorFunction(gralloc1_device_t* device, + gralloc1_buffer_descriptor_t descriptorId, + gralloc1_error_t (Descriptor::*member)(Args...), Args... args) { + auto descriptor = getAdapter(device)->getDescriptor(descriptorId); + if (!descriptor) { + return static_cast<int32_t>(GRALLOC1_ERROR_BAD_DESCRIPTOR); + } + auto error = ((*descriptor).*member)(std::forward<Args>(args)...); + return static_cast<int32_t>(error); + } + + static int32_t setConsumerUsageHook(gralloc1_device_t* device, + gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) { + auto usage = static_cast<gralloc1_consumer_usage_t>(intUsage); + return callDescriptorFunction(device, descriptorId, + &Descriptor::setConsumerUsage, usage); + } + + static int32_t setDimensionsHook(gralloc1_device_t* device, + gralloc1_buffer_descriptor_t descriptorId, uint32_t width, + uint32_t height) { + return callDescriptorFunction(device, descriptorId, + &Descriptor::setDimensions, width, height); + } + + static int32_t setFormatHook(gralloc1_device_t* device, + gralloc1_buffer_descriptor_t descriptorId, int32_t format) { + return callDescriptorFunction(device, descriptorId, + &Descriptor::setFormat, format); + } + + static int32_t setLayerCountHook(gralloc1_device_t* device, + gralloc1_buffer_descriptor_t descriptorId, uint32_t layerCount) { + return callDescriptorFunction(device, descriptorId, + &Descriptor::setLayerCount, layerCount); + } + + static int32_t setProducerUsageHook(gralloc1_device_t* device, + gralloc1_buffer_descriptor_t descriptorId, uint64_t intUsage) { + auto usage = static_cast<gralloc1_producer_usage_t>(intUsage); + return callDescriptorFunction(device, descriptorId, + &Descriptor::setProducerUsage, usage); + } + + // Buffer handle query functions + + class Buffer { + public: + Buffer(buffer_handle_t handle, gralloc1_backing_store_t store, + const Descriptor& descriptor, uint32_t stride, + uint32_t numFlexPlanes, bool wasAllocated); + + buffer_handle_t getHandle() const { return mHandle; } + + void retain() { ++mReferenceCount; } + + // Returns true if the reference count has dropped to 0, indicating that + // the buffer needs to be released + bool release() { return --mReferenceCount == 0; } + + bool wasAllocated() const { return mWasAllocated; } + + gralloc1_error_t getBackingStore( + gralloc1_backing_store_t* outStore) const { + *outStore = mStore; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t getConsumerUsage( + gralloc1_consumer_usage_t* outUsage) const { + *outUsage = mDescriptor.consumerUsage; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t getDimensions(uint32_t* outWidth, + uint32_t* outHeight) const { + *outWidth = mDescriptor.width; + *outHeight = mDescriptor.height; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t getFormat(int32_t* outFormat) const { + *outFormat = mDescriptor.format; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t getLayerCount(uint32_t* outLayerCount) const { + *outLayerCount = mDescriptor.layerCount; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t getNumFlexPlanes(uint32_t* outNumPlanes) const { + *outNumPlanes = mNumFlexPlanes; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t getProducerUsage( + gralloc1_producer_usage_t* outUsage) const { + *outUsage = mDescriptor.producerUsage; + return GRALLOC1_ERROR_NONE; + } + + gralloc1_error_t getStride(uint32_t* outStride) const { + *outStride = mStride; + return GRALLOC1_ERROR_NONE; + } + + private: + + const buffer_handle_t mHandle; + size_t mReferenceCount; + + const gralloc1_backing_store_t mStore; + const Descriptor mDescriptor; + const uint32_t mStride; + const uint32_t mNumFlexPlanes; + + // Whether this buffer allocated in this process (as opposed to just + // being retained here), which determines whether to free or unregister + // the buffer when this Buffer is released + const bool mWasAllocated; + }; + + template <typename ...Args> + static int32_t callBufferFunction(gralloc1_device_t* device, + buffer_handle_t bufferHandle, + gralloc1_error_t (Buffer::*member)(Args...) const, Args... args) { + auto buffer = getAdapter(device)->getBuffer(bufferHandle); + if (!buffer) { + return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE); + } + auto error = ((*buffer).*member)(std::forward<Args>(args)...); + return static_cast<int32_t>(error); + } + + template <typename MF, MF memFunc, typename ...Args> + static int32_t bufferHook(gralloc1_device_t* device, + buffer_handle_t bufferHandle, Args... args) { + return Gralloc1On0Adapter::callBufferFunction(device, bufferHandle, + memFunc, std::forward<Args>(args)...); + } + + static int32_t getConsumerUsageHook(gralloc1_device_t* device, + buffer_handle_t bufferHandle, uint64_t* outUsage) { + auto usage = GRALLOC1_CONSUMER_USAGE_NONE; + auto error = callBufferFunction(device, bufferHandle, + &Buffer::getConsumerUsage, &usage); + if (error == GRALLOC1_ERROR_NONE) { + *outUsage = static_cast<uint64_t>(usage); + } + return error; + } + + static int32_t getProducerUsageHook(gralloc1_device_t* device, + buffer_handle_t bufferHandle, uint64_t* outUsage) { + auto usage = GRALLOC1_PRODUCER_USAGE_NONE; + auto error = callBufferFunction(device, bufferHandle, + &Buffer::getProducerUsage, &usage); + if (error == GRALLOC1_ERROR_NONE) { + *outUsage = static_cast<uint64_t>(usage); + } + return error; + } + + // Buffer management functions + + gralloc1_error_t allocate( + gralloc1_buffer_descriptor_t id, + const std::shared_ptr<Descriptor>& descriptor, + buffer_handle_t* outBufferHandle); + static int32_t allocateHook(gralloc1_device* device, + uint32_t numDescriptors, + const gralloc1_buffer_descriptor_t* descriptors, + buffer_handle_t* outBuffers); + + gralloc1_error_t retain(const std::shared_ptr<Buffer>& buffer); + gralloc1_error_t retain(buffer_handle_t bufferHandle); + static int32_t retainHook(gralloc1_device_t* device, + buffer_handle_t bufferHandle) + { + auto adapter = getAdapter(device); + return adapter->retain(bufferHandle); + } + + gralloc1_error_t release(const std::shared_ptr<Buffer>& buffer); + static int32_t releaseHook(gralloc1_device_t* device, + buffer_handle_t bufferHandle) { + auto adapter = getAdapter(device); + + auto buffer = adapter->getBuffer(bufferHandle); + if (!buffer) { + return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE); + } + + auto error = adapter->release(buffer); + return static_cast<int32_t>(error); + } + + // Buffer access functions + + gralloc1_error_t lock(const std::shared_ptr<Buffer>& buffer, + gralloc1_producer_usage_t producerUsage, + gralloc1_consumer_usage_t consumerUsage, + const gralloc1_rect_t& accessRegion, void** outData, + int acquireFence); + gralloc1_error_t lockFlex(const std::shared_ptr<Buffer>& buffer, + gralloc1_producer_usage_t producerUsage, + gralloc1_consumer_usage_t consumerUsage, + const gralloc1_rect_t& accessRegion, + struct android_flex_layout* outFlex, + int acquireFence); + + template <typename OUT, gralloc1_error_t (Gralloc1On0Adapter::*member)( + const std::shared_ptr<Buffer>&, gralloc1_producer_usage_t, + gralloc1_consumer_usage_t, const gralloc1_rect_t&, OUT*, + int)> + static int32_t lockHook(gralloc1_device_t* device, + buffer_handle_t bufferHandle, + uint64_t /*gralloc1_producer_usage_t*/ uintProducerUsage, + uint64_t /*gralloc1_consumer_usage_t*/ uintConsumerUsage, + const gralloc1_rect_t* accessRegion, OUT* outData, + int32_t acquireFenceFd) { + auto adapter = getAdapter(device); + + // Exactly one of producer and consumer usage must be *_USAGE_NONE, + // but we can't check this until the upper levels of the framework + // correctly distinguish between producer and consumer usage + /* + bool hasProducerUsage = + uintProducerUsage != GRALLOC1_PRODUCER_USAGE_NONE; + bool hasConsumerUsage = + uintConsumerUsage != GRALLOC1_CONSUMER_USAGE_NONE; + if (hasProducerUsage && hasConsumerUsage || + !hasProducerUsage && !hasConsumerUsage) { + return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE); + } + */ + + auto producerUsage = + static_cast<gralloc1_producer_usage_t>(uintProducerUsage); + auto consumerUsage = + static_cast<gralloc1_consumer_usage_t>(uintConsumerUsage); + + if (!outData) { + const auto producerCpuUsage = GRALLOC1_PRODUCER_USAGE_CPU_READ | + GRALLOC1_PRODUCER_USAGE_CPU_WRITE; + if ((producerUsage & producerCpuUsage) != 0) { + return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE); + } + if ((consumerUsage & GRALLOC1_CONSUMER_USAGE_CPU_READ) != 0) { + return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE); + } + } + + auto buffer = adapter->getBuffer(bufferHandle); + if (!buffer) { + return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE); + } + + if (!accessRegion) { + ALOGE("accessRegion is null"); + return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE); + } + + auto error = ((*adapter).*member)(buffer, producerUsage, consumerUsage, + *accessRegion, outData, acquireFenceFd); + return static_cast<int32_t>(error); + } + + gralloc1_error_t unlock(const std::shared_ptr<Buffer>& buffer, + int* outReleaseFence); + static int32_t unlockHook(gralloc1_device_t* device, + buffer_handle_t bufferHandle, int32_t* outReleaseFenceFd) { + auto adapter = getAdapter(device); + + auto buffer = adapter->getBuffer(bufferHandle); + if (!buffer) { + return static_cast<int32_t>(GRALLOC1_ERROR_BAD_HANDLE); + } + + int releaseFence = -1; + auto error = adapter->unlock(buffer, &releaseFence); + if (error == GRALLOC1_ERROR_NONE) { + *outReleaseFenceFd = releaseFence; + } + return static_cast<int32_t>(error); + } + + // Adapter internals + const gralloc_module_t* mModule; + uint8_t mMinorVersion; + alloc_device_t* mDevice; + + std::shared_ptr<Descriptor> getDescriptor( + gralloc1_buffer_descriptor_t descriptorId); + std::shared_ptr<Buffer> getBuffer(buffer_handle_t bufferHandle); + + static std::atomic<gralloc1_buffer_descriptor_t> sNextBufferDescriptorId; + std::mutex mDescriptorMutex; + std::unordered_map<gralloc1_buffer_descriptor_t, + std::shared_ptr<Descriptor>> mDescriptors; + std::mutex mBufferMutex; + std::unordered_map<buffer_handle_t, std::shared_ptr<Buffer>> mBuffers; +}; + +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRALLOC_1_ON_0_ADAPTER_H
diff --git a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc new file mode 100644 index 0000000..c4715cd --- /dev/null +++ b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
@@ -0,0 +1,5 @@ +service gralloc-2-0 /vendor/bin/hw/android.hardware.graphics.allocator@2.0-service + class hal + user system + group graphics drmrpc readproc + onrestart restart surfaceflinger
diff --git a/graphics/allocator/2.0/default/gralloc1-adapter.cpp b/graphics/allocator/2.0/default/gralloc1-adapter.cpp new file mode 100644 index 0000000..fcc59cd --- /dev/null +++ b/graphics/allocator/2.0/default/gralloc1-adapter.cpp
@@ -0,0 +1,32 @@ +/* + * Copyright 2016 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. + */ + +#include "Gralloc1On0Adapter.h" +#include "gralloc1-adapter.h" + +int gralloc1_adapter_device_open(const struct hw_module_t* module, + const char* id, struct hw_device_t** device) +{ + if (strcmp(id, GRALLOC_HARDWARE_MODULE_ID) != 0) { + ALOGE("unknown gralloc1 device id: %s", id); + return -EINVAL; + } + + auto adapter_device = new android::hardware::Gralloc1On0Adapter(module); + *device = &adapter_device->common; + + return 0; +}
diff --git a/graphics/allocator/2.0/default/gralloc1-adapter.h b/graphics/allocator/2.0/default/gralloc1-adapter.h new file mode 100644 index 0000000..b912ef6 --- /dev/null +++ b/graphics/allocator/2.0/default/gralloc1-adapter.h
@@ -0,0 +1,89 @@ +/* + * Copyright 2016 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. + */ +#ifndef ANDROID_HARDWARE_GRALLOC1_ADAPTER_H +#define ANDROID_HARDWARE_GRALLOC1_ADAPTER_H + +#include <hardware/hardware.h> + +__BEGIN_DECLS + +#define GRALLOC1_ADAPTER_MODULE_API_VERSION_1_0 \ + HARDWARE_MODULE_API_VERSION(1, 0) + +enum { + GRALLOC1_ADAPTER_PERFORM_FIRST = 10000, + + // void getRealModuleApiVersionMinor(..., int* outMinorVersion); + GRALLOC1_ADAPTER_PERFORM_GET_REAL_MODULE_API_VERSION_MINOR = + GRALLOC1_ADAPTER_PERFORM_FIRST, + + // void setUsages(..., buffer_handle_t buffer, + // int producerUsage, + // int consumerUsage); + GRALLOC1_ADAPTER_PERFORM_SET_USAGES = + GRALLOC1_ADAPTER_PERFORM_FIRST + 1, + + // void getDimensions(..., buffer_handle_t buffer, + // int* outWidth, + // int* outHeight); + GRALLOC1_ADAPTER_PERFORM_GET_DIMENSIONS = + GRALLOC1_ADAPTER_PERFORM_FIRST + 2, + + // void getFormat(..., buffer_handle_t buffer, int* outFormat); + GRALLOC1_ADAPTER_PERFORM_GET_FORMAT = + GRALLOC1_ADAPTER_PERFORM_FIRST + 3, + + // void getProducerUsage(..., buffer_handle_t buffer, int* outUsage); + GRALLOC1_ADAPTER_PERFORM_GET_PRODUCER_USAGE = + GRALLOC1_ADAPTER_PERFORM_FIRST + 4, + + // void getConsumerUsage(..., buffer_handle_t buffer, int* outUsage); + GRALLOC1_ADAPTER_PERFORM_GET_CONSUMER_USAGE = + GRALLOC1_ADAPTER_PERFORM_FIRST + 5, + + // void getBackingStore(..., buffer_handle_t buffer, + // uint64_t* outBackingStore); + GRALLOC1_ADAPTER_PERFORM_GET_BACKING_STORE = + GRALLOC1_ADAPTER_PERFORM_FIRST + 6, + + // void getNumFlexPlanes(..., buffer_handle_t buffer, + // int* outNumFlexPlanes); + GRALLOC1_ADAPTER_PERFORM_GET_NUM_FLEX_PLANES = + GRALLOC1_ADAPTER_PERFORM_FIRST + 7, + + // void getStride(..., buffer_handle_t buffer, int* outStride); + GRALLOC1_ADAPTER_PERFORM_GET_STRIDE = + GRALLOC1_ADAPTER_PERFORM_FIRST + 8, + + // void lockFlex(..., buffer_handle_t buffer, + // int producerUsage, + // int consumerUsage, + // int left, + // int top, + // int width, + // int height, + // android_flex_layout* outLayout, + // int acquireFence); + GRALLOC1_ADAPTER_PERFORM_LOCK_FLEX = + GRALLOC1_ADAPTER_PERFORM_FIRST + 9, +}; + +int gralloc1_adapter_device_open(const struct hw_module_t* module, + const char* id, struct hw_device_t** device); + +__END_DECLS + +#endif /* ANDROID_HARDWARE_GRALLOC1_ADAPTER_H */
diff --git a/graphics/allocator/2.0/default/service.cpp b/graphics/allocator/2.0/default/service.cpp new file mode 100644 index 0000000..a43740c --- /dev/null +++ b/graphics/allocator/2.0/default/service.cpp
@@ -0,0 +1,28 @@ +/* + * Copyright 2016 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. + */ + +#define LOG_TAG "android.hardware.graphics.allocator@2.0-service" + +#include <android/hardware/graphics/allocator/2.0/IAllocator.h> + +#include <hidl/LegacySupport.h> + +using android::hardware::graphics::allocator::V2_0::IAllocator; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IAllocator>(); +}
diff --git a/graphics/allocator/2.0/types.hal b/graphics/allocator/2.0/types.hal new file mode 100644 index 0000000..f9d1e1b --- /dev/null +++ b/graphics/allocator/2.0/types.hal
@@ -0,0 +1,147 @@ +/* + * Copyright (C) 2016 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.graphics.allocator@2.0; + +enum Error : int32_t { + NONE = 0, /* no error */ + BAD_DESCRIPTOR = 1, /* invalid BufferDescriptor */ + BAD_BUFFER = 2, /* invalid Buffer */ + BAD_VALUE = 3, /* invalid width, height, etc. */ + NOT_SHARED = 4, /* buffers not sharing backing store */ + NO_RESOURCES = 5, /* temporary failure due to resource contention */ + UNDEFINED = 6, /* an operation has no defined meaning */ + UNSUPPORTED = 7, /* permanent failure */ +}; + +enum ProducerUsage : uint64_t { + /* bit 0 is reserved */ + + /* buffer is read by CPU occasionally */ + CPU_READ = 1ULL << 1, + /* buffer is read by CPU frequently */ + CPU_READ_OFTEN = 1ULL << 2, + + /* bit 3 is reserved */ + /* bit 4 is reserved */ + + /* buffer is written by CPU occasionally */ + CPU_WRITE = 1ULL << 5, + /* buffer is written by CPU frequently */ + CPU_WRITE_OFTEN = 1ULL << 6, + + /* bit 7 is reserved */ + /* bit 8 is reserved */ + + /* buffer is used as a GPU render target */ + GPU_RENDER_TARGET = 1ULL << 9, + + /* bit 10 is reserved */ + /* bit 11 is reserved */ + /* bit 12 is reserved */ + /* bit 13 is reserved */ + + /* + * Buffer is allocated with hardware-level protection against copying the + * contents (or information derived from the contents) into unprotected + * memory. + */ + PROTECTED = 1ULL << 14, + + /* bit 15 is reserved */ + /* bit 16 is reserved */ + + /* buffer is used as a camera HAL output */ + CAMERA = 1ULL << 17, + + /* bit 18 is reserved */ + /* bit 19 is reserved */ + /* bit 20 is reserved */ + /* bit 21 is reserved */ + + /* buffer is used as a video decoder output */ + VIDEO_DECODER = 1ULL << 22, + + /* buffer is used as a sensor direct report output */ + SENSOR_DIRECT_DATA = 1ULL << 23, + + /* bits 24-27 are reserved for future versions */ + /* bits 28-31 are reserved for vendor extensions */ + + /* bits 32-47 are reserved for future versions */ + /* bits 48-63 are reserved for vendor extensions */ +}; + +enum ConsumerUsage : uint64_t { + /* bit 0 is reserved */ + + /* buffer is read by CPU occasionally */ + CPU_READ = 1ULL << 1, + /* buffer is read by CPU frequently */ + CPU_READ_OFTEN = 1ULL << 2, + + /* bit 3 is reserved */ + /* bit 4 is reserved */ + /* bit 5 is reserved */ + /* bit 6 is reserved */ + /* bit 7 is reserved */ + + /* buffer is used as a GPU texture */ + GPU_TEXTURE = 1ULL << 8, + + /* bit 9 is reserved */ + /* bit 10 is reserved */ + + /* buffer is used by hwcomposer HAL */ + HWCOMPOSER = 1ULL << 11, + /* buffer is a hwcomposer HAL client target */ + CLIENT_TARGET = 1ULL << 12, + + /* bit 13 is reserved */ + /* bit 14 is reserved */ + + /* buffer is used as a hwcomposer HAL cursor */ + CURSOR = 1ULL << 15, + + /* buffer is used as a video encoder input */ + VIDEO_ENCODER = 1ULL << 16, + + /* bit 17 is reserved */ + + /* buffer is used as a camera HAL input */ + CAMERA = 1ULL << 18, + + /* bit 19 is reserved */ + + /* buffer is used as a renderscript allocation */ + RENDERSCRIPT = 1ULL << 20, + + /* bit 21 is reserved */ + /* bit 22 is reserved */ + + /* buffer is used as as an OpenGL shader storage or uniform + buffer object */ + GPU_DATA_BUFFER = 1ULL << 23, + + /* bits 24-27 are reserved for future versions */ + /* bits 28-31 are reserved for vendor extensions */ + + /* bits 32-47 are reserved for future versions */ + /* bits 48-63 are reserved for vendor extensions */ +}; + +typedef uint64_t BufferDescriptor; +typedef uint64_t Buffer;
diff --git a/graphics/allocator/2.0/vts/functional/Android.bp b/graphics/allocator/2.0/vts/functional/Android.bp new file mode 100644 index 0000000..fb77ab3 --- /dev/null +++ b/graphics/allocator/2.0/vts/functional/Android.bp
@@ -0,0 +1,62 @@ +// +// Copyright (C) 2016 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. +// + +cc_library_static { + name: "libVtsHalGraphicsAllocatorTestUtils", + defaults: ["hidl_defaults"], + srcs: ["VtsHalGraphicsAllocatorTestUtils.cpp"], + shared_libs: [ + "android.hardware.graphics.allocator@2.0", + ], + static_libs: [ + "VtsHalHidlTargetTestBase", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-O0", + "-g", + ], + export_include_dirs: ["."], +} + +cc_test { + name: "VtsHalGraphicsAllocatorV2_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalGraphicsAllocatorV2_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.graphics.allocator@2.0", + ], + static_libs: [ + "libVtsHalGraphicsAllocatorTestUtils", + "VtsHalHidlTargetTestBase", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-O0", + "-g", + ] +}
diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp new file mode 100644 index 0000000..0dc43be --- /dev/null +++ b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp
@@ -0,0 +1,183 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <VtsHalHidlTargetTestBase.h> + +#include "VtsHalGraphicsAllocatorTestUtils.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace allocator { +namespace V2_0 { +namespace tests { + +Allocator::Allocator() { init(); } + +void Allocator::init() { + mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(); + ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service"; + + std::vector<IAllocator::Capability> capabilities = getCapabilities(); + mCapabilities.insert(capabilities.begin(), capabilities.end()); +} + +sp<IAllocator> Allocator::getRaw() const { return mAllocator; } + +bool Allocator::hasCapability(IAllocator::Capability capability) const { + return mCapabilities.count(capability) > 0; +} + +std::vector<IAllocator::Capability> Allocator::getCapabilities() { + std::vector<IAllocator::Capability> capabilities; + mAllocator->getCapabilities( + [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; }); + + return capabilities; +} + +std::string Allocator::dumpDebugInfo() { + std::string debugInfo; + mAllocator->dumpDebugInfo( + [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); }); + + return debugInfo; +} + +std::unique_ptr<AllocatorClient> Allocator::createClient() { + std::unique_ptr<AllocatorClient> client; + mAllocator->createClient([&](const auto& tmpError, const auto& tmpClient) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to create client"; + client = std::make_unique<AllocatorClient>(tmpClient); + }); + + return client; +} + +AllocatorClient::AllocatorClient(const sp<IAllocatorClient>& client) + : mClient(client) {} + +AllocatorClient::~AllocatorClient() { + for (auto buffer : mBuffers) { + EXPECT_EQ(Error::NONE, mClient->free(buffer)) + << "failed to free buffer " << buffer; + } + mBuffers.clear(); + + for (auto descriptor : mDescriptors) { + EXPECT_EQ(Error::NONE, mClient->destroyDescriptor(descriptor)) + << "failed to destroy descriptor " << descriptor; + } + mDescriptors.clear(); +} + +sp<IAllocatorClient> AllocatorClient::getRaw() const { return mClient; } + +BufferDescriptor AllocatorClient::createDescriptor( + const IAllocatorClient::BufferDescriptorInfo& info) { + BufferDescriptor descriptor = 0; + mClient->createDescriptor( + info, [&](const auto& tmpError, const auto& tmpDescriptor) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor"; + descriptor = tmpDescriptor; + + EXPECT_TRUE(mDescriptors.insert(descriptor).second) + << "duplicated descriptor id " << descriptor; + }); + + return descriptor; +} + +void AllocatorClient::destroyDescriptor(BufferDescriptor descriptor) { + ASSERT_EQ(Error::NONE, mClient->destroyDescriptor(descriptor)) + << "failed to destroy descriptor " << descriptor; + + mDescriptors.erase(descriptor); +} + +Error AllocatorClient::testAllocate( + const std::vector<BufferDescriptor>& descriptors) { + return mClient->testAllocate(descriptors); +} + +bool AllocatorClient::testAllocate(BufferDescriptor descriptor) { + std::vector<BufferDescriptor> descriptors(1, descriptor); + Error error = testAllocate(descriptors); + return (error == Error::NONE || error == Error::NOT_SHARED); +} + +Error AllocatorClient::allocate( + const std::vector<BufferDescriptor>& descriptors, + std::vector<Buffer>& buffers) { + Error error = Error::NO_RESOURCES; + mClient->allocate(descriptors, [&](const auto& tmpError, + const auto& tmpBuffers) { + ASSERT_TRUE(tmpError == Error::NONE || tmpError == Error::NOT_SHARED) + << "failed to allocate buffer"; + ASSERT_EQ(descriptors.size(), tmpBuffers.size()) << "invalid buffer count"; + + error = tmpError; + buffers = tmpBuffers; + + for (auto buffer : buffers) { + EXPECT_TRUE(mBuffers.insert(buffer).second) + << "duplicated buffer id " << buffer; + } + }); + + return error; +} + +Buffer AllocatorClient::allocate(BufferDescriptor descriptor) { + std::vector<BufferDescriptor> descriptors(1, descriptor); + std::vector<Buffer> buffers; + allocate(descriptors, buffers); + if (::testing::Test::HasFatalFailure()) { + return 0; + } + + return buffers[0]; +} + +void AllocatorClient::free(Buffer buffer) { + ASSERT_EQ(Error::NONE, mClient->free(buffer)) + << "failed to free buffer " << buffer; + + mBuffers.erase(buffer); +} + +native_handle_t* AllocatorClient::exportHandle(BufferDescriptor descriptor, + Buffer buffer) { + native_handle_t* handle; + mClient->exportHandle( + descriptor, buffer, [&](const auto& tmpError, const auto& tmpHandle) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to export buffer handle"; + ASSERT_NE(nullptr, tmpHandle.getNativeHandle()) + << "invalid buffer handle"; + + handle = native_handle_clone(tmpHandle.getNativeHandle()); + ASSERT_NE(nullptr, handle) << "failed to clone handle"; + }); + + return handle; +} + +} // namespace tests +} // namespace V2_0 +} // namespace allocator +} // namespace graphics +} // namespace hardware +} // namespace android
diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h new file mode 100644 index 0000000..c9bfe8f --- /dev/null +++ b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h
@@ -0,0 +1,98 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef VTS_HAL_GRAPHICS_ALLOCATOR_UTILS +#define VTS_HAL_GRAPHICS_ALLOCATOR_UTILS + +#include <memory> +#include <string> +#include <unordered_set> +#include <vector> + +#include <android/hardware/graphics/allocator/2.0/IAllocator.h> +#include <utils/StrongPointer.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace allocator { +namespace V2_0 { +namespace tests { + +class AllocatorClient; + +// A wrapper to IAllocator. +class Allocator { + public: + Allocator(); + + sp<IAllocator> getRaw() const; + + // Returns true when the allocator supports the specified capability. + bool hasCapability(IAllocator::Capability capability) const; + + std::vector<IAllocator::Capability> getCapabilities(); + std::string dumpDebugInfo(); + std::unique_ptr<AllocatorClient> createClient(); + + private: + void init(); + + sp<IAllocator> mAllocator; + std::unordered_set<IAllocator::Capability> mCapabilities; +}; + +// A wrapper to IAllocatorClient. +class AllocatorClient { + public: + AllocatorClient(const sp<IAllocatorClient>& client); + ~AllocatorClient(); + + sp<IAllocatorClient> getRaw() const; + + BufferDescriptor createDescriptor( + const IAllocatorClient::BufferDescriptorInfo& info); + void destroyDescriptor(BufferDescriptor descriptor); + + Error testAllocate(const std::vector<BufferDescriptor>& descriptors); + bool testAllocate(BufferDescriptor descriptor); + + Error allocate(const std::vector<BufferDescriptor>& descriptors, + std::vector<Buffer>& buffers); + Buffer allocate(BufferDescriptor descriptor); + void free(Buffer buffer); + + // Returns a handle to the buffer. The ownership of the handle is + // transferred to the caller. + native_handle_t* exportHandle(BufferDescriptor descriptor, Buffer buffer); + + private: + sp<IAllocatorClient> mClient; + + // Keep track of all descriptors and buffers. When a test fails with + // ASSERT_*, the destructor will clean up the resources for the test. + std::unordered_set<BufferDescriptor> mDescriptors; + std::unordered_set<Buffer> mBuffers; +}; + +} // namespace tests +} // namespace V2_0 +} // namespace allocator +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // VTS_HAL_GRAPHICS_ALLOCATOR_UTILS
diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp new file mode 100644 index 0000000..b1c764f --- /dev/null +++ b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp
@@ -0,0 +1,186 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "graphics_allocator_hidl_hal_test" + +#include <android-base/logging.h> +#include <VtsHalHidlTargetTestBase.h> + +#include "VtsHalGraphicsAllocatorTestUtils.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace allocator { +namespace V2_0 { +namespace tests { +namespace { + +using android::hardware::graphics::common::V1_0::PixelFormat; + +#define CHECK_FEATURE_OR_SKIP(FEATURE_NAME) \ + do { \ + if (!mAllocator->hasCapability(FEATURE_NAME)) { \ + std::cout << "[ SKIPPED ] Feature " << #FEATURE_NAME \ + << " not supported" << std::endl; \ + return; \ + } \ + } while (0) + +class GraphicsAllocatorHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>()); + ASSERT_NO_FATAL_FAILURE(mClient = mAllocator->createClient()); + + mDummyDescriptorInfo.width = 64; + mDummyDescriptorInfo.height = 64; + mDummyDescriptorInfo.layerCount = 1; + mDummyDescriptorInfo.format = PixelFormat::RGBA_8888; + mDummyDescriptorInfo.producerUsageMask = + static_cast<uint64_t>(ProducerUsage::CPU_WRITE); + mDummyDescriptorInfo.consumerUsageMask = + static_cast<uint64_t>(ConsumerUsage::CPU_READ); + } + + void TearDown() override {} + + std::unique_ptr<Allocator> mAllocator; + std::unique_ptr<AllocatorClient> mClient; + IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{}; +}; + +TEST_F(GraphicsAllocatorHidlTest, GetCapabilities) { + auto capabilities = mAllocator->getCapabilities(); + for (auto cap : capabilities) { + EXPECT_NE(IAllocator::Capability::INVALID, cap); + } +} + +TEST_F(GraphicsAllocatorHidlTest, DumpDebugInfo) { + mAllocator->dumpDebugInfo(); +} + +TEST_F(GraphicsAllocatorHidlTest, CreateDestroyDescriptor) { + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = + mClient->createDescriptor(mDummyDescriptorInfo)); + mClient->destroyDescriptor(descriptor); +} + +/** + * Test testAllocate with a single buffer descriptor. + */ +TEST_F(GraphicsAllocatorHidlTest, TestAllocateBasic) { + CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE); + + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = + mClient->createDescriptor(mDummyDescriptorInfo)); + + ASSERT_TRUE(mClient->testAllocate(descriptor)); +} + +/** + * Test testAllocate with two buffer descriptors. + */ +TEST_F(GraphicsAllocatorHidlTest, TestAllocateArray) { + CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE); + + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = + mClient->createDescriptor(mDummyDescriptorInfo)); + + hidl_vec<BufferDescriptor> descriptors; + descriptors.resize(2); + descriptors[0] = descriptor; + descriptors[1] = descriptor; + + auto error = mClient->testAllocate(descriptors); + ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED); +} + +/** + * Test allocate/free with a single buffer descriptor. + */ +TEST_F(GraphicsAllocatorHidlTest, AllocateFreeBasic) { + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = + mClient->createDescriptor(mDummyDescriptorInfo)); + + Buffer buffer; + ASSERT_NO_FATAL_FAILURE(buffer = mClient->allocate(descriptor)); + + mClient->free(buffer); +} + +/** + * Test allocate/free with an array of buffer descriptors. + */ +TEST_F(GraphicsAllocatorHidlTest, AllocateFreeArray) { + BufferDescriptor descriptor1; + ASSERT_NO_FATAL_FAILURE(descriptor1 = + mClient->createDescriptor(mDummyDescriptorInfo)); + + BufferDescriptor descriptor2; + ASSERT_NO_FATAL_FAILURE(descriptor2 = + mClient->createDescriptor(mDummyDescriptorInfo)); + + hidl_vec<BufferDescriptor> descriptors; + descriptors.resize(3); + descriptors[0] = descriptor1; + descriptors[1] = descriptor1; + descriptors[2] = descriptor2; + + std::vector<Buffer> buffers; + ASSERT_NO_FATAL_FAILURE(mClient->allocate(descriptors, buffers)); + + for (auto buf : buffers) { + mClient->free(buf); + } +} + +TEST_F(GraphicsAllocatorHidlTest, ExportHandle) { + BufferDescriptor descriptor; + ASSERT_NO_FATAL_FAILURE(descriptor = + mClient->createDescriptor(mDummyDescriptorInfo)); + + Buffer buffer; + ASSERT_NO_FATAL_FAILURE(buffer = mClient->allocate(descriptor)); + + native_handle_t* handle; + ASSERT_NO_FATAL_FAILURE(handle = mClient->exportHandle(descriptor, buffer)); + + native_handle_close(handle); + native_handle_delete(handle); +} + +} // namespace anonymous +} // namespace tests +} // namespace V2_0 +} // namespace allocator +} // namespace graphics +} // namespace hardware +} // namespace android + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + + return status; +}
diff --git a/graphics/allocator/Android.mk b/graphics/allocator/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/graphics/allocator/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/graphics/common/1.0/Android.bp b/graphics/common/1.0/Android.bp new file mode 100644 index 0000000..99370e8 --- /dev/null +++ b/graphics/common/1.0/Android.bp
@@ -0,0 +1,53 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.graphics.common@1.0_hal", + srcs: [ + "types.hal", + ], +} + +genrule { + name: "android.hardware.graphics.common@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.common@1.0", + srcs: [ + ":android.hardware.graphics.common@1.0_hal", + ], + out: [ + "android/hardware/graphics/common/1.0/types.cpp", + ], +} + +genrule { + name: "android.hardware.graphics.common@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.common@1.0", + srcs: [ + ":android.hardware.graphics.common@1.0_hal", + ], + out: [ + "android/hardware/graphics/common/1.0/types.h", + ], +} + +cc_library_shared { + name: "android.hardware.graphics.common@1.0", + generated_sources: ["android.hardware.graphics.common@1.0_genc++"], + generated_headers: ["android.hardware.graphics.common@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.graphics.common@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + ], +}
diff --git a/graphics/common/1.0/Android.mk b/graphics/common/1.0/Android.mk new file mode 100644 index 0000000..c08053d --- /dev/null +++ b/graphics/common/1.0/Android.mk
@@ -0,0 +1,291 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.graphics.common@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +# +# Build types.hal (ColorMode) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/ColorMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.ColorMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ColorTransform) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/ColorTransform.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.ColorTransform + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Dataspace) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Dataspace.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.Dataspace + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Hdr) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Hdr.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.Hdr + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PixelFormat) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/PixelFormat.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.PixelFormat + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Transform) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Transform.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.Transform + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.graphics.common@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +# +# Build types.hal (ColorMode) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/ColorMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.ColorMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ColorTransform) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/ColorTransform.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.ColorTransform + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Dataspace) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Dataspace.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.Dataspace + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Hdr) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Hdr.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.Hdr + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PixelFormat) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/PixelFormat.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.PixelFormat + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Transform) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Transform.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0::types.Transform + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.graphics.common@1.0-java-constants +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +# +GEN := $(intermediates)/android/hardware/graphics/common/V1_0/Constants.java +$(GEN): $(HIDL) +$(GEN): $(LOCAL_PATH)/types.hal + +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava-constants \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.graphics.common@1.0 + +$(GEN): + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +# Avoid dependency cycle of framework.jar -> this-library -> framework.jar +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj + +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/graphics/common/1.0/types.hal b/graphics/common/1.0/types.hal new file mode 100644 index 0000000..dfecec1 --- /dev/null +++ b/graphics/common/1.0/types.hal
@@ -0,0 +1,1409 @@ +/* + * Copyright (C) 2016 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.graphics.common@1.0; + +/** + * pixel format definitions + */ +@export(name="android_pixel_format_t", value_prefix="HAL_PIXEL_FORMAT_") +enum PixelFormat : int32_t { + /* + * "linear" color pixel formats: + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + * + * The color space determines, for example, if the formats are linear or + * gamma-corrected; or whether any special operations are performed when + * reading or writing into a buffer in one of these formats. + */ + RGBA_8888 = 1, + RGBX_8888 = 2, + RGB_888 = 3, + RGB_565 = 4, + BGRA_8888 = 5, + + /* + * The following formats use 10bit integers for R, G, and B and + * 2 bits for alpha. This is used to improve color precision on + * wide-color devices, e.g. Display-P3 or scRGB. + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + RGBA_1010102 = 0x2B, + + /* + * The following formats use a 16bit float per color component. + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + RGBA_FP16 = 0x16, + + /* + * 0x101 - 0x1FF + * + * This range is reserved for pixel formats that are specific to the HAL + * implementation. Implementations can use any value in this range to + * communicate video pixel formats between their HAL modules. These formats + * must not have an alpha channel. Additionally, an EGLimage created from a + * gralloc buffer of one of these formats must be supported for use with the + * GL_OES_EGL_image_external OpenGL ES extension. + */ + + /* + * Android YUV format: + * + * This format is exposed outside of the HAL to software decoders and + * applications. EGLImageKHR must support it in conjunction with the + * OES_EGL_image_external extension. + * + * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed + * by (W/2) x (H/2) Cr and Cb planes. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * + * y_size = stride * height + * c_stride = ALIGN(stride/2, 16) + * c_size = c_stride * height/2 + * size = y_size + c_size * 2 + * cr_offset = y_size + * cb_offset = y_size + c_size + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + YV12 = 0x32315659, // YCrCb 4:2:0 Planar + + + /* + * Android Y8 format: + * + * This format is exposed outside of the HAL to the framework. + * The expected gralloc usage flags are SW_* and HW_CAMERA_*, + * and no other HW_ flags will be used. + * + * Y8 is a YUV planar format comprised of a WxH Y plane, + * with each pixel being represented by 8 bits. + * + * It is equivalent to just the Y plane from YV12. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * + * size = stride * height + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + Y8 = 0x20203859, + + /* + * Android Y16 format: + * + * This format is exposed outside of the HAL to the framework. + * The expected gralloc usage flags are SW_* and HW_CAMERA_*, + * and no other HW_ flags will be used. + * + * Y16 is a YUV planar format comprised of a WxH Y plane, + * with each pixel being represented by 16 bits. + * + * It is just like Y8, but has double the bits per pixel (little endian). + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * - strides are specified in pixels, not in bytes + * + * size = stride * height * 2 + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer, except that dataSpace field + * HAL_DATASPACE_DEPTH indicates that this buffer contains a depth + * image where each sample is a distance value measured by a depth camera, + * plus an associated confidence value. + */ + Y16 = 0x20363159, + + /* + * Android RAW sensor format: + * + * This format is exposed outside of the camera HAL to applications. + * + * RAW16 is a single-channel, 16-bit, little endian format, typically + * representing raw Bayer-pattern images from an image sensor, with minimal + * processing. + * + * The exact pixel layout of the data in the buffer is sensor-dependent, and + * needs to be queried from the camera device. + * + * Generally, not all 16 bits are used; more common values are 10 or 12 + * bits. If not all bits are used, the lower-order bits are filled first. + * All parameters to interpret the raw data (black and white points, + * color space, etc) must be queried from the camera device. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * - strides are specified in pixels, not in bytes + * + * size = stride * height * 2 + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. + */ + RAW16 = 0x20, + + /* + * Android RAW10 format: + * + * This format is exposed outside of the camera HAL to applications. + * + * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row, + * unprocessed format, usually representing raw Bayer-pattern images coming from + * an image sensor. + * + * In an image buffer with this format, starting from the first pixel of each + * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one + * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte + * contains the 2 least significant bits of the 4 pixels, the exact layout data + * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth + * bit of the ith pixel): + * + * bit 7 bit 0 + * =====|=====|=====|=====|=====|=====|=====|=====| + * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]| + * |-----|-----|-----|-----|-----|-----|-----|-----| + * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]| + * =============================================== + * + * This format assumes + * - a width multiple of 4 pixels + * - an even height + * - a vertical stride equal to the height + * - strides are specified in bytes, not in pixels + * + * size = stride * height + * + * When stride is equal to width * (10 / 8), there will be no padding bytes at + * the end of each row, the entire image data is densely packed. When stride is + * larger than width * (10 / 8), padding bytes will be present at the end of each + * row (including the last row). + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace field should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. + */ + RAW10 = 0x25, + + /* + * Android RAW12 format: + * + * This format is exposed outside of camera HAL to applications. + * + * RAW12 is a single-channel, 12-bit per pixel, densely packed in each row, + * unprocessed format, usually representing raw Bayer-pattern images coming from + * an image sensor. + * + * In an image buffer with this format, starting from the first pixel of each + * row, each two consecutive pixels are packed into 3 bytes (24 bits). The first + * and second byte contains the top 8 bits of first and second pixel. The third + * byte contains the 4 least significant bits of the two pixels, the exact layout + * data for each two consecutive pixels is illustrated below (Pi[j] stands for + * the jth bit of the ith pixel): + * + * bit 7 bit 0 + * ======|======|======|======|======|======|======|======| + * Byte 0: |P0[11]|P0[10]|P0[ 9]|P0[ 8]|P0[ 7]|P0[ 6]|P0[ 5]|P0[ 4]| + * |------|------|------|------|------|------|------|------| + * Byte 1: |P1[11]|P1[10]|P1[ 9]|P1[ 8]|P1[ 7]|P1[ 6]|P1[ 5]|P1[ 4]| + * |------|------|------|------|------|------|------|------| + * Byte 2: |P1[ 3]|P1[ 2]|P1[ 1]|P1[ 0]|P0[ 3]|P0[ 2]|P0[ 1]|P0[ 0]| + * ======================================================= + * + * This format assumes: + * - a width multiple of 4 pixels + * - an even height + * - a vertical stride equal to the height + * - strides are specified in bytes, not in pixels + * + * size = stride * height + * + * When stride is equal to width * (12 / 8), there will be no padding bytes at + * the end of each row, the entire image data is densely packed. When stride is + * larger than width * (12 / 8), padding bytes will be present at the end of + * each row (including the last row). + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace field should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. + */ + RAW12 = 0x26, + + /* + * Android opaque RAW format: + * + * This format is exposed outside of the camera HAL to applications. + * + * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an + * image sensor. The actual structure of buffers of this format is + * implementation-dependent. + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT + * + * When used with ANativeWindow, the dataSpace field should be + * HAL_DATASPACE_ARBITRARY, as raw image sensor buffers require substantial + * extra metadata to define. + */ + RAW_OPAQUE = 0x24, + + /* + * Android binary blob graphics buffer format: + * + * This format is used to carry task-specific data which does not have a + * standard image structure. The details of the format are left to the two + * endpoints. + * + * A typical use case is for transporting JPEG-compressed images from the + * Camera HAL to the framework or to applications. + * + * Buffers of this format must have a height of 1, and width equal to their + * size in bytes. + * + * When used with ANativeWindow, the mapping of the dataSpace field to + * buffer contents for BLOB is as follows: + * + * dataSpace value | Buffer contents + * -------------------------------+----------------------------------------- + * HAL_DATASPACE_JFIF | An encoded JPEG image + * HAL_DATASPACE_DEPTH | An android_depth_points buffer + * HAL_DATASPACE_SENSOR | Sensor event data. + * Other | Unsupported + * + */ + BLOB = 0x21, + + /* + * Android format indicating that the choice of format is entirely up to the + * device-specific Gralloc implementation. + * + * The Gralloc implementation should examine the usage bits passed in when + * allocating a buffer with this format, and it should derive the pixel + * format from those usage flags. This format will never be used with any + * of the GRALLOC_USAGE_SW_* usage flags. + * + * If a buffer of this format is to be used as an OpenGL ES texture, the + * framework will assume that sampling the texture will always return an + * alpha value of 1.0 (i.e. the buffer contains only opaque pixel values). + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + IMPLEMENTATION_DEFINED = 0x22, + + /* + * Android flexible YCbCr 4:2:0 formats + * + * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:0 + * buffer layout, while still describing the general format in a + * layout-independent manner. While called YCbCr, it can be + * used to describe formats with either chromatic ordering, as well as + * whole planar or semiplanar layouts. + * + * struct android_ycbcr (below) is the the struct used to describe it. + * + * This format must be accepted by the gralloc module when + * USAGE_SW_WRITE_* or USAGE_SW_READ_* are set. + * + * This format is locked for use by gralloc's (*lock_ycbcr) method, and + * locking with the (*lock) method will return an error. + * + * When used with ANativeWindow, the dataSpace field describes the color + * space of the buffer. + */ + YCBCR_420_888 = 0x23, + + /* + * Android flexible YCbCr 4:2:2 formats + * + * This format allows platforms to use an efficient YCbCr/YCrCb 4:2:2 + * buffer layout, while still describing the general format in a + * layout-independent manner. While called YCbCr, it can be + * used to describe formats with either chromatic ordering, as well as + * whole planar or semiplanar layouts. + * + * This format is currently only used by SW readable buffers + * produced by MediaCodecs, so the gralloc module can ignore this format. + */ + YCBCR_422_888 = 0x27, + + /* + * Android flexible YCbCr 4:4:4 formats + * + * This format allows platforms to use an efficient YCbCr/YCrCb 4:4:4 + * buffer layout, while still describing the general format in a + * layout-independent manner. While called YCbCr, it can be + * used to describe formats with either chromatic ordering, as well as + * whole planar or semiplanar layouts. + * + * This format is currently only used by SW readable buffers + * produced by MediaCodecs, so the gralloc module can ignore this format. + */ + YCBCR_444_888 = 0x28, + + /* + * Android flexible RGB 888 formats + * + * This format allows platforms to use an efficient RGB/BGR/RGBX/BGRX + * buffer layout, while still describing the general format in a + * layout-independent manner. While called RGB, it can be + * used to describe formats with either color ordering and optional + * padding, as well as whole planar layout. + * + * This format is currently only used by SW readable buffers + * produced by MediaCodecs, so the gralloc module can ignore this format. + */ + FLEX_RGB_888 = 0x29, + + /* + * Android flexible RGBA 8888 formats + * + * This format allows platforms to use an efficient RGBA/BGRA/ARGB/ABGR + * buffer layout, while still describing the general format in a + * layout-independent manner. While called RGBA, it can be + * used to describe formats with any of the component orderings, as + * well as whole planar layout. + * + * This format is currently only used by SW readable buffers + * produced by MediaCodecs, so the gralloc module can ignore this format. + */ + FLEX_RGBA_8888 = 0x2A, + + /* Legacy formats (deprecated), used by ImageFormat.java */ + YCBCR_422_SP = 0x10, // NV16 + YCRCB_420_SP = 0x11, // NV21 + YCBCR_422_I = 0x14, // YUY2 + JPEG = 0x100, +}; + +/** + * Transformation definitions + * + * IMPORTANT NOTE: + * ROT_90 is applied CLOCKWISE and AFTER FLIP_{H|V}. + * + */ +@export(name="android_transform_t", value_prefix="HAL_TRANSFORM_") +enum Transform : int32_t { + /* flip source image horizontally (around the vertical axis) */ + FLIP_H = 0x01, + /* flip source image vertically (around the horizontal axis)*/ + FLIP_V = 0x02, + /* rotate source image 90 degrees clockwise */ + ROT_90 = 0x04, + /* rotate source image 180 degrees */ + ROT_180 = 0x03, + /* rotate source image 270 degrees clockwise */ + ROT_270 = 0x07, + + /* 0x08 is reserved */ +}; + +/** + * Dataspace Definitions + * ====================== + * + * Dataspace is the definition of how pixel values should be interpreted. + * + * For many formats, this is the colorspace of the image data, which includes + * primaries (including white point) and the transfer characteristic function, + * which describes both gamma curve and numeric range (within the bit depth). + * + * Other dataspaces include depth measurement data from a depth camera. + * + * A dataspace is comprised of a number of fields. + * + * Version + * -------- + * The top 2 bits represent the revision of the field specification. This is + * currently always 0. + * + * + * bits 31-30 29 - 0 + * +-----+----------------------------------------------------+ + * fields | Rev | Revision specific fields | + * +-----+----------------------------------------------------+ + * + * Field layout for version = 0: + * ---------------------------- + * + * A dataspace is comprised of the following fields: + * Standard + * Transfer function + * Range + * + * bits 31-30 29-27 26 - 22 21 - 16 15 - 0 + * +-----+-----+--------+--------+----------------------------+ + * fields | 0 |Range|Transfer|Standard| Legacy and custom | + * +-----+-----+--------+--------+----------------------------+ + * VV RRR TTTTT SSSSSS LLLLLLLL LLLLLLLL + * + * If range, transfer and standard fields are all 0 (e.g. top 16 bits are + * all zeroes), the bottom 16 bits contain either a legacy dataspace value, + * or a custom value. + */ +@export(name="android_dataspace_t", value_prefix="HAL_DATASPACE_") +enum Dataspace : int32_t { + /* + * Default-assumption data space, when not explicitly specified. + * + * It is safest to assume the buffer is an image with sRGB primaries and + * encoding ranges, but the consumer and/or the producer of the data may + * simply be using defaults. No automatic gamma transform should be + * expected, except for a possible display gamma transform when drawn to a + * screen. + */ + UNKNOWN = 0x0, + + /* + * Arbitrary dataspace with manually defined characteristics. Definition + * for colorspaces or other meaning must be communicated separately. + * + * This is used when specifying primaries, transfer characteristics, + * etc. separately. + * + * A typical use case is in video encoding parameters (e.g. for H.264), + * where a colorspace can have separately defined primaries, transfer + * characteristics, etc. + */ + ARBITRARY = 0x1, + + /* + * Color-description aspects + * + * The following aspects define various characteristics of the color + * specification. These represent bitfields, so that a data space value + * can specify each of them independently. + */ + + STANDARD_SHIFT = 16, + + /* + * Standard aspect + * + * Defines the chromaticity coordinates of the source primaries in terms of + * the CIE 1931 definition of x and y specified in ISO 11664-1. + */ + STANDARD_MASK = 63 << STANDARD_SHIFT, // 0x3F + + /* + * Chromacity coordinates are unknown or are determined by the application. + * Implementations shall use the following suggested standards: + * + * All YCbCr formats: BT709 if size is 720p or larger (since most video + * content is letterboxed this corresponds to width is + * 1280 or greater, or height is 720 or greater). + * BT601_625 if size is smaller than 720p or is JPEG. + * All RGB formats: BT709. + * + * For all other formats standard is undefined, and implementations should use + * an appropriate standard for the data represented. + */ + STANDARD_UNSPECIFIED = 0 << STANDARD_SHIFT, + + /* + * Primaries: x y + * green 0.300 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation + * for RGB conversion. + */ + STANDARD_BT709 = 1 << STANDARD_SHIFT, + + /* + * Primaries: x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation + * for RGB conversion from the one purely determined by the primaries + * to minimize the color shift into RGB space that uses BT.709 + * primaries. + */ + STANDARD_BT601_625 = 2 << STANDARD_SHIFT, + + /* + * Primaries: x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation + * for RGB conversion. + */ + STANDARD_BT601_625_UNADJUSTED = 3 << STANDARD_SHIFT, + + /* + * Primaries: x y + * green 0.310 0.595 + * blue 0.155 0.070 + * red 0.630 0.340 + * white (D65) 0.3127 0.3290 + * + * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation + * for RGB conversion from the one purely determined by the primaries + * to minimize the color shift into RGB space that uses BT.709 + * primaries. + */ + STANDARD_BT601_525 = 4 << STANDARD_SHIFT, + + /* + * Primaries: x y + * green 0.310 0.595 + * blue 0.155 0.070 + * red 0.630 0.340 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation + * for RGB conversion (as in SMPTE 240M). + */ + STANDARD_BT601_525_UNADJUSTED = 5 << STANDARD_SHIFT, + + /* + * Primaries: x y + * green 0.170 0.797 + * blue 0.131 0.046 + * red 0.708 0.292 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation + * for RGB conversion. + */ + STANDARD_BT2020 = 6 << STANDARD_SHIFT, + + /* + * Primaries: x y + * green 0.170 0.797 + * blue 0.131 0.046 + * red 0.708 0.292 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation + * for RGB conversion using the linear domain. + */ + STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << STANDARD_SHIFT, + + /* + * Primaries: x y + * green 0.21 0.71 + * blue 0.14 0.08 + * red 0.67 0.33 + * white (C) 0.310 0.316 + * + * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation + * for RGB conversion. + */ + STANDARD_BT470M = 8 << STANDARD_SHIFT, + + /* + * Primaries: x y + * green 0.243 0.692 + * blue 0.145 0.049 + * red 0.681 0.319 + * white (C) 0.310 0.316 + * + * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation + * for RGB conversion. + */ + STANDARD_FILM = 9 << STANDARD_SHIFT, + + /* + * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3) + * Primaries: x y + * green 0.265 0.690 + * blue 0.150 0.060 + * red 0.680 0.320 + * white (D65) 0.3127 0.3290 + */ + STANDARD_DCI_P3 = 10 << STANDARD_SHIFT, + + /* + * Adobe RGB + * Primaries: x y + * green 0.210 0.710 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + */ + STANDARD_ADOBE_RGB = 11 << STANDARD_SHIFT, + + + + TRANSFER_SHIFT = 22, + + /* + * Transfer aspect + * + * Transfer characteristics are the opto-electronic transfer characteristic + * at the source as a function of linear optical intensity (luminance). + * + * For digital signals, E corresponds to the recorded value. Normally, the + * transfer function is applied in RGB space to each of the R, G and B + * components independently. This may result in color shift that can be + * minized by applying the transfer function in Lab space only for the L + * component. Implementation may apply the transfer function in RGB space + * for all pixel formats if desired. + */ + + TRANSFER_MASK = 31 << TRANSFER_SHIFT, // 0x1F + + /* + * Transfer characteristics are unknown or are determined by the + * application. + * + * Implementations should use the following transfer functions: + * + * For YCbCr formats: use TRANSFER_SMPTE_170M + * For RGB formats: use TRANSFER_SRGB + * + * For all other formats transfer function is undefined, and implementations + * should use an appropriate standard for the data represented. + */ + TRANSFER_UNSPECIFIED = 0 << TRANSFER_SHIFT, + + /* + * Transfer characteristic curve: + * E = L + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_LINEAR = 1 << TRANSFER_SHIFT, + + /* + * Transfer characteristic curve: + * + * E = 1.055 * L^(1/2.4) - 0.055 for 0.0031308 <= L <= 1 + * = 12.92 * L for 0 <= L < 0.0031308 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_SRGB = 2 << TRANSFER_SHIFT, + + /* + * BT.601 525, BT.601 625, BT.709, BT.2020 + * + * Transfer characteristic curve: + * E = 1.099 * L ^ 0.45 - 0.099 for 0.018 <= L <= 1 + * = 4.500 * L for 0 <= L < 0.018 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_SMPTE_170M = 3 << TRANSFER_SHIFT, + + /* + * Assumed display gamma 2.2. + * + * Transfer characteristic curve: + * E = L ^ (1/2.2) + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_GAMMA2_2 = 4 << TRANSFER_SHIFT, + + /* + * display gamma 2.6. + * + * Transfer characteristic curve: + * E = L ^ (1/2.6) + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_GAMMA2_6 = 5 << TRANSFER_SHIFT, + + /* + * display gamma 2.8. + * + * Transfer characteristic curve: + * E = L ^ (1/2.8) + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + */ + TRANSFER_GAMMA2_8 = 6 << TRANSFER_SHIFT, + + /* + * SMPTE ST 2084 (Dolby Perceptual Quantizer) + * + * Transfer characteristic curve: + * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m + * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375 + * c2 = 32 * 2413 / 4096 = 18.8515625 + * c3 = 32 * 2392 / 4096 = 18.6875 + * m = 128 * 2523 / 4096 = 78.84375 + * n = 0.25 * 2610 / 4096 = 0.1593017578125 + * L - luminance of image 0 <= L <= 1 for HDR colorimetry. + * L = 1 corresponds to 10000 cd/m2 + * E - corresponding electrical signal + */ + TRANSFER_ST2084 = 7 << TRANSFER_SHIFT, + + /* + * ARIB STD-B67 Hybrid Log Gamma + * + * Transfer characteristic curve: + * E = r * L^0.5 for 0 <= L <= 1 + * = a * ln(L - b) + c for 1 < L + * a = 0.17883277 + * b = 0.28466892 + * c = 0.55991073 + * r = 0.5 + * L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds + * to reference white level of 100 cd/m2 + * E - corresponding electrical signal + */ + TRANSFER_HLG = 8 << TRANSFER_SHIFT, + + RANGE_SHIFT = 27, + + /* + * Range aspect + * + * Defines the range of values corresponding to the unit range of 0-1. + * This is defined for YCbCr only, but can be expanded to RGB space. + */ + RANGE_MASK = 7 << RANGE_SHIFT, // 0x7 + + /* + * Range is unknown or are determined by the application. Implementations + * shall use the following suggested ranges: + * + * All YCbCr formats: limited range. + * All RGB or RGBA formats (including RAW and Bayer): full range. + * All Y formats: full range + * + * For all other formats range is undefined, and implementations should use + * an appropriate range for the data represented. + */ + RANGE_UNSPECIFIED = 0 << RANGE_SHIFT, + + /* + * Full range uses all values for Y, Cb and Cr from + * 0 to 2^b-1, where b is the bit depth of the color format. + */ + RANGE_FULL = 1 << RANGE_SHIFT, + + /* + * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and + * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of + * the color format. + * + * E.g. For 8-bit-depth formats: + * Luma (Y) samples should range from 16 to 235, inclusive + * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive + * + * For 10-bit-depth formats: + * Luma (Y) samples should range from 64 to 940, inclusive + * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive + */ + RANGE_LIMITED = 2 << RANGE_SHIFT, + + /* + * Extended range is used for scRGB. Intended for use with + * floating point pixel formats. [0.0 - 1.0] is the standard + * sRGB space. Values outside the range 0.0 - 1.0 can encode + * color outside the sRGB gamut. + * Used to blend / merge multiple dataspaces on a single display. + */ + RANGE_EXTENDED = 3 << RANGE_SHIFT, + + /* + * Legacy dataspaces + */ + + /* + * sRGB linear encoding: + * + * The red, green, and blue components are stored in sRGB space, but + * are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are encoded using the full range ([0,255] for 8-bit) for all + * components. + */ + SRGB_LINEAR = 0x200, // deprecated, use V0_SRGB_LINEAR + + V0_SRGB_LINEAR = STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL, + + + /* + * scRGB linear encoding: + * + * The red, green, and blue components are stored in extended sRGB space, + * but are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are floating point. + * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits. + * Values beyond the range [0.0 - 1.0] would correspond to other colors + * spaces and/or HDR content. + */ + V0_SCRGB_LINEAR = STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED, + + + /* + * sRGB gamma encoding: + * + * The red, green and blue components are stored in sRGB space, and + * converted to linear space when read, using the SRGB transfer function + * for each of the R, G and B components. When written, the inverse + * transformation is performed. + * + * The alpha component, if present, is always stored in linear space and + * is left unmodified when read or written. + * + * Use full range and BT.709 standard. + */ + SRGB = 0x201, // deprecated, use V0_SRGB + + V0_SRGB = STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL, + + + /* + * scRGB: + * + * The red, green, and blue components are stored in extended sRGB space, + * but are linear, not gamma-encoded. + * The RGB primaries and the white point are the same as BT.709. + * + * The values are floating point. + * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits. + * Values beyond the range [0.0 - 1.0] would correspond to other colors + * spaces and/or HDR content. + */ + V0_SCRGB = STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED, + + /* + * YCbCr Colorspaces + * ----------------- + * + * Primaries are given using (x,y) coordinates in the CIE 1931 definition + * of x and y specified by ISO 11664-1. + * + * Transfer characteristics are the opto-electronic transfer characteristic + * at the source as a function of linear optical intensity (luminance). + */ + + /* + * JPEG File Interchange Format (JFIF) + * + * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255 + * + * Use full range, BT.601 transfer and BT.601_625 standard. + */ + JFIF = 0x101, // deprecated, use V0_JFIF + + V0_JFIF = STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL, + + /* + * ITU-R Recommendation 601 (BT.601) - 625-line + * + * Standard-definition television, 625 Lines (PAL) + * + * Use limited range, BT.601 transfer and BT.601_625 standard. + */ + BT601_625 = 0x102, // deprecated, use V0_BT601_625 + + V0_BT601_625 = STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED, + + + /* + * ITU-R Recommendation 601 (BT.601) - 525-line + * + * Standard-definition television, 525 Lines (NTSC) + * + * Use limited range, BT.601 transfer and BT.601_525 standard. + */ + BT601_525 = 0x103, // deprecated, use V0_BT601_525 + + V0_BT601_525 = STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED, + + /* + * ITU-R Recommendation 709 (BT.709) + * + * High-definition television + * + * Use limited range, BT.709 transfer and BT.709 standard. + */ + BT709 = 0x104, // deprecated, use V0_BT709 + + V0_BT709 = STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED, + + + /* + * SMPTE EG 432-1 and SMPTE RP 431-2. + * + * Digital Cinema DCI-P3 + * + * Use full range, linear transfer and D65 DCI-P3 standard + */ + DCI_P3_LINEAR = STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL, + + + /* + * SMPTE EG 432-1 and SMPTE RP 431-2. + * + * Digital Cinema DCI-P3 + * + * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard + * Note: Application is responsible for gamma encoding the data as + * a 2.6 gamma encoding is not supported in HW. + */ + DCI_P3 = STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL, + + + /* + * Display P3 + * + * Display P3 uses same primaries and white-point as DCI-P3 + * linear transfer function makes this the same as DCI_P3_LINEAR. + */ + DISPLAY_P3_LINEAR = STANDARD_DCI_P3 | TRANSFER_LINEAR | RANGE_FULL, + + + /* + * Display P3 + * + * Use same primaries and white-point as DCI-P3 + * but sRGB transfer function. + */ + DISPLAY_P3 = STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL, + + + /* + * Adobe RGB + * + * Use full range, gamma 2.2 transfer and Adobe RGB primaries + * Note: Application is responsible for gamma encoding the data as + * a 2.2 gamma encoding is not supported in HW. + */ + ADOBE_RGB = STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL, + + + /* + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use full range, linear transfer and BT2020 standard + */ + BT2020_LINEAR = STANDARD_BT2020 | TRANSFER_LINEAR | RANGE_FULL, + + + /* + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use full range, BT.709 transfer and BT2020 standard + */ + BT2020 = STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL, + + /* + * ITU-R Recommendation 2020 (BT.2020) + * + * Ultra High-definition television + * + * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard + */ + BT2020_PQ = STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL, + + + /* + * Data spaces for non-color formats + */ + + /* + * The buffer contains depth ranging measurements from a depth camera. + * This value is valid with formats: + * HAL_PIXEL_FORMAT_Y16: 16-bit samples, consisting of a depth measurement + * and an associated confidence value. The 3 MSBs of the sample make + * up the confidence value, and the low 13 LSBs of the sample make up + * the depth measurement. + * For the confidence section, 0 means 100% confidence, 1 means 0% + * confidence. The mapping to a linear float confidence value between + * 0.f and 1.f can be obtained with + * float confidence = (((depthSample >> 13) - 1) & 0x7) / 7.0f; + * The depth measurement can be extracted simply with + * uint16_t range = (depthSample & 0x1FFF); + * HAL_PIXEL_FORMAT_BLOB: A depth point cloud, as + * a variable-length float (x,y,z, confidence) coordinate point list. + * The point cloud will be represented with the android_depth_points + * structure. + */ + DEPTH = 0x1000, + + + /* + * The buffer contains sensor events from sensor direct report. + * This value is valid with formats: + * HAL_PIXEL_FORMAT_BLOB: an array of sensor event structure that forms + * a lock free queue. Format of sensor event structure is specified + * in Sensors HAL. + */ + SENSOR = 0x1001 +}; + +/* + * Color modes that may be supported by a display. + * + * Definitions: + * Rendering intent generally defines the goal in mapping a source (input) + * color to a destination device color for a given color mode. + * + * It is important to keep in mind three cases where mapping may be applied: + * 1. The source gamut is much smaller than the destination (display) gamut + * 2. The source gamut is much larger than the destination gamut (this will + * ordinarily be handled using colorimetric rendering, below) + * 3. The source and destination gamuts are roughly equal, although not + * completely overlapping + * Also, a common requirement for mappings is that skin tones should be + * preserved, or at least remain natural in appearance. + * + * Colorimetric Rendering Intent (All cases): + * Colorimetric indicates that colors should be preserved. In the case + * that the source gamut lies wholly within the destination gamut or is + * about the same (#1, #3), this will simply mean that no manipulations + * (no saturation boost, for example) are applied. In the case where some + * source colors lie outside the destination gamut (#2, #3), those will + * need to be mapped to colors that are within the destination gamut, + * while the already in-gamut colors remain unchanged. + * + * Non-colorimetric transforms can take many forms. There are no hard + * rules and it's left to the implementation to define. + * Two common intents are described below. + * + * Stretched-Gamut Enhancement Intent (Source < Destination): + * When the destination gamut is much larger than the source gamut (#1), the + * source primaries may be redefined to reflect the full extent of the + * destination space, or to reflect an intermediate gamut. + * Skin-tone preservation would likely be applied. An example might be sRGB + * input displayed on a DCI-P3 capable device, with skin-tone preservation. + * + * Within-Gamut Enhancement Intent (Source >= Destination): + * When the device (destination) gamut is not larger than the source gamut + * (#2 or #3), but the appearance of a larger gamut is desired, techniques + * such as saturation boost may be applied to the source colors. Skin-tone + * preservation may be applied. There is no unique method for within-gamut + * enhancement; it would be defined within a flexible color mode. + * + */ +@export(name="android_color_mode_t", value_prefix="HAL_COLOR_MODE_") +enum ColorMode : int32_t { + /* + * DEFAULT is the "native" gamut of the display. + * White Point: Vendor/OEM defined + * Panel Gamma: Vendor/OEM defined (typically 2.2) + * Rendering Intent: Vendor/OEM defined (typically 'enhanced') + */ + NATIVE = 0, + + /* + * STANDARD_BT601_625 corresponds with display + * settings that implement the ITU-R Recommendation BT.601 + * or Rec 601. Using 625 line version + * Rendering Intent: Colorimetric + * Primaries: + * x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation + * for RGB conversion from the one purely determined by the primaries + * to minimize the color shift into RGB space that uses BT.709 + * primaries. + * + * Gamma Correction (GC): + * + * if Vlinear < 0.018 + * Vnonlinear = 4.500 * Vlinear + * else + * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099 + */ + STANDARD_BT601_625 = 1, + + /* + * Primaries: + * x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation + * for RGB conversion. + * + * Gamma Correction (GC): + * + * if Vlinear < 0.018 + * Vnonlinear = 4.500 * Vlinear + * else + * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099 + */ + STANDARD_BT601_625_UNADJUSTED = 2, + + /* + * Primaries: + * x y + * green 0.310 0.595 + * blue 0.155 0.070 + * red 0.630 0.340 + * white (D65) 0.3127 0.3290 + * + * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation + * for RGB conversion from the one purely determined by the primaries + * to minimize the color shift into RGB space that uses BT.709 + * primaries. + * + * Gamma Correction (GC): + * + * if Vlinear < 0.018 + * Vnonlinear = 4.500 * Vlinear + * else + * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099 + */ + STANDARD_BT601_525 = 3, + + /* + * Primaries: + * x y + * green 0.310 0.595 + * blue 0.155 0.070 + * red 0.630 0.340 + * white (D65) 0.3127 0.3290 + * + * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation + * for RGB conversion (as in SMPTE 240M). + * + * Gamma Correction (GC): + * + * if Vlinear < 0.018 + * Vnonlinear = 4.500 * Vlinear + * else + * Vnonlinear = 1.099 * (Vlinear)^(0.45) – 0.099 + */ + STANDARD_BT601_525_UNADJUSTED = 4, + + /* + * REC709 corresponds with display settings that implement + * the ITU-R Recommendation BT.709 / Rec. 709 for high-definition television. + * Rendering Intent: Colorimetric + * Primaries: + * x y + * green 0.300 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * HDTV REC709 Inverse Gamma Correction (IGC): V represents normalized + * (with [0 to 1] range) value of R, G, or B. + * + * if Vnonlinear < 0.081 + * Vlinear = Vnonlinear / 4.5 + * else + * Vlinear = ((Vnonlinear + 0.099) / 1.099) ^ (1/0.45) + * + * HDTV REC709 Gamma Correction (GC): + * + * if Vlinear < 0.018 + * Vnonlinear = 4.5 * Vlinear + * else + * Vnonlinear = 1.099 * (Vlinear) ^ 0.45 – 0.099 + */ + STANDARD_BT709 = 5, + + /* + * DCI_P3 corresponds with display settings that implement + * SMPTE EG 432-1 and SMPTE RP 431-2 + * Rendering Intent: Colorimetric + * Primaries: + * x y + * green 0.265 0.690 + * blue 0.150 0.060 + * red 0.680 0.320 + * white (D65) 0.3127 0.3290 + * + * Gamma: 2.6 + */ + DCI_P3 = 6, + + /* + * SRGB corresponds with display settings that implement + * the sRGB color space. Uses the same primaries as ITU-R Recommendation + * BT.709 + * Rendering Intent: Colorimetric + * Primaries: + * x y + * green 0.300 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * PC/Internet (sRGB) Inverse Gamma Correction (IGC): + * + * if Vnonlinear ≤ 0.03928 + * Vlinear = Vnonlinear / 12.92 + * else + * Vlinear = ((Vnonlinear + 0.055)/1.055) ^ 2.4 + * + * PC/Internet (sRGB) Gamma Correction (GC): + * + * if Vlinear ≤ 0.0031308 + * Vnonlinear = 12.92 * Vlinear + * else + * Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055 + */ + SRGB = 7, + + /* + * ADOBE_RGB corresponds with the RGB color space developed + * by Adobe Systems, Inc. in 1998. + * Rendering Intent: Colorimetric + * Primaries: + * x y + * green 0.210 0.710 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + * + * Gamma: 2.2 + */ + ADOBE_RGB = 8, + + /* + * DISPLAY_P3 is a color space that uses the DCI_P3 primaries, + * the D65 white point and the SRGB transfer functions. + * Rendering Intent: Colorimetric + * Primaries: + * x y + * green 0.265 0.690 + * blue 0.150 0.060 + * red 0.680 0.320 + * white (D65) 0.3127 0.3290 + * + * PC/Internet (sRGB) Gamma Correction (GC): + * + * if Vlinear ≤ 0.0030186 + * Vnonlinear = 12.92 * Vlinear + * else + * Vnonlinear = 1.055 * (Vlinear)^(1/2.4) – 0.055 + * + * Note: In most cases sRGB transfer function will be fine. + */ + DISPLAY_P3 = 9 +}; + +/* + * Color transforms that may be applied by hardware composer to the whole + * display. + */ +@export(name="android_color_transform_t", value_prefix="HAL_COLOR_TRANSFORM_") +enum ColorTransform : int32_t { + /* Applies no transform to the output color */ + IDENTITY = 0, + + /* Applies an arbitrary transform defined by a 4x4 affine matrix */ + ARBITRARY_MATRIX = 1, + + /* Applies a transform that inverts the value or luminance of the color, but + * does not modify hue or saturation */ + VALUE_INVERSE = 2, + + /* Applies a transform that maps all colors to shades of gray */ + GRAYSCALE = 3, + + /* Applies a transform which corrects for protanopic color blindness */ + CORRECT_PROTANOPIA = 4, + + /* Applies a transform which corrects for deuteranopic color blindness */ + CORRECT_DEUTERANOPIA = 5, + + /* Applies a transform which corrects for tritanopic color blindness */ + CORRECT_TRITANOPIA = 6 +}; + +/* + * Supported HDR formats. Must be kept in sync with equivalents in Display.java. + */ +@export(name="android_hdr_t", value_prefix="HAL_HDR_") +enum Hdr : int32_t { + /* Device supports Dolby Vision HDR */ + DOLBY_VISION = 1, + + /* Device supports HDR10 */ + HDR10 = 2, + + /* Device supports hybrid log-gamma HDR */ + HLG = 3 +};
diff --git a/graphics/composer/2.1/Android.bp b/graphics/composer/2.1/Android.bp new file mode 100644 index 0000000..f309439 --- /dev/null +++ b/graphics/composer/2.1/Android.bp
@@ -0,0 +1,78 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.graphics.composer@2.1_hal", + srcs: [ + "types.hal", + "IComposer.hal", + "IComposerCallback.hal", + "IComposerClient.hal", + ], +} + +genrule { + name: "android.hardware.graphics.composer@2.1_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.composer@2.1", + srcs: [ + ":android.hardware.graphics.composer@2.1_hal", + ], + out: [ + "android/hardware/graphics/composer/2.1/types.cpp", + "android/hardware/graphics/composer/2.1/ComposerAll.cpp", + "android/hardware/graphics/composer/2.1/ComposerCallbackAll.cpp", + "android/hardware/graphics/composer/2.1/ComposerClientAll.cpp", + ], +} + +genrule { + name: "android.hardware.graphics.composer@2.1_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.composer@2.1", + srcs: [ + ":android.hardware.graphics.composer@2.1_hal", + ], + out: [ + "android/hardware/graphics/composer/2.1/types.h", + "android/hardware/graphics/composer/2.1/IComposer.h", + "android/hardware/graphics/composer/2.1/IHwComposer.h", + "android/hardware/graphics/composer/2.1/BnHwComposer.h", + "android/hardware/graphics/composer/2.1/BpHwComposer.h", + "android/hardware/graphics/composer/2.1/BsComposer.h", + "android/hardware/graphics/composer/2.1/IComposerCallback.h", + "android/hardware/graphics/composer/2.1/IHwComposerCallback.h", + "android/hardware/graphics/composer/2.1/BnHwComposerCallback.h", + "android/hardware/graphics/composer/2.1/BpHwComposerCallback.h", + "android/hardware/graphics/composer/2.1/BsComposerCallback.h", + "android/hardware/graphics/composer/2.1/IComposerClient.h", + "android/hardware/graphics/composer/2.1/IHwComposerClient.h", + "android/hardware/graphics/composer/2.1/BnHwComposerClient.h", + "android/hardware/graphics/composer/2.1/BpHwComposerClient.h", + "android/hardware/graphics/composer/2.1/BsComposerClient.h", + ], +} + +cc_library_shared { + name: "android.hardware.graphics.composer@2.1", + generated_sources: ["android.hardware.graphics.composer@2.1_genc++"], + generated_headers: ["android.hardware.graphics.composer@2.1_genc++_headers"], + export_generated_headers: ["android.hardware.graphics.composer@2.1_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], +}
diff --git a/graphics/composer/2.1/Android.mk b/graphics/composer/2.1/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/graphics/composer/2.1/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/graphics/composer/2.1/IComposer.hal b/graphics/composer/2.1/IComposer.hal new file mode 100644 index 0000000..553a537 --- /dev/null +++ b/graphics/composer/2.1/IComposer.hal
@@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 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.graphics.composer@2.1; + +import IComposerClient; + +interface IComposer { + /* + * Optional capabilities which may be supported by some devices. The + * particular set of supported capabilities for a given device may be + * retrieved using getCapabilities. + */ + enum Capability : int32_t { + INVALID = 0, + + /* + * Specifies that the device supports sideband stream layers, for + * which buffer content updates and other synchronization will not be + * provided through the usual validate/present cycle and must be + * handled by an external implementation-defined mechanism. Only + * changes to layer state (such as position, size, etc.) need to be + * performed through the validate/present cycle. + */ + SIDEBAND_STREAM = 1, + + /* + * Specifies that the device will apply a color transform even when + * either the client or the device has chosen that all layers should + * be composed by the client. This will prevent the client from + * applying the color transform during its composition step. + */ + SKIP_CLIENT_COLOR_TRANSFORM = 2, + }; + + /* + * Provides a list of supported capabilities (as described in the + * definition of Capability above). This list must not change after + * initialization. + * + * @return capabilities is a list of supported capabilities. + */ + @entry + @exit + @callflow(next="*") + getCapabilities() generates (vec<Capability> capabilities); + + /* + * Retrieves implementation-defined debug information, which will be + * displayed during, for example, `dumpsys SurfaceFlinger`. + * + * @return debugInfo is a string of debug information. + */ + @entry + @exit + @callflow(next="*") + dumpDebugInfo() generates (string debugInfo); + + /* + * Creates a client of the composer. All resources created by the client + * are owned by the client and are only visible to the client. + * + * There can only be one client at any time. + * + * @return error is NONE upon success. Otherwise, + * NO_RESOURCES when no more client can be created currently. + * @return client is the newly created client. + */ + @entry + @callflow(next="*") + createClient() generates (Error error, IComposerClient client); +};
diff --git a/graphics/composer/2.1/IComposerCallback.hal b/graphics/composer/2.1/IComposerCallback.hal new file mode 100644 index 0000000..541d7eb --- /dev/null +++ b/graphics/composer/2.1/IComposerCallback.hal
@@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 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.graphics.composer@2.1; + +interface IComposerCallback { + enum Connection : int32_t { + INVALID = 0, + + /* The display has been connected */ + CONNECTED = 1, + /* The display has been disconnected */ + DISCONNECTED = 2, + }; + + /* + * Notifies the client that the given display has either been connected or + * disconnected. Every active display (even a built-in physical display) + * must trigger at least one hotplug notification, even if it only occurs + * immediately after callback registration. + * + * Displays which have been connected are assumed to be in PowerMode::OFF, + * and the onVsync callback should not be called for a display until vsync + * has been enabled with setVsyncEnabled. + * + * The client may call back into the device while the callback is in + * progress. The device must serialize calls to this callback such that + * only one thread is calling it at a time. + * + * @param display is the display that triggers the hotplug event. + * @param connected indicates whether the display is connected or + * disconnected. + */ + @callflow(next="*") + onHotplug(Display display, Connection connected); + + /* + * Notifies the client to trigger a screen refresh. This forces all layer + * state for this display to be resent, and the display to be validated + * and presented, even if there have been no changes. + + * This refresh will occur some time after the callback is initiated, but + * not necessarily before it returns. It is safe to trigger this callback + * from other functions which call into the device. + * + * @param display is the display to refresh. + */ + @callflow(next="*") + oneway onRefresh(Display display); + + /* + * Notifies the client that a vsync event has occurred. This callback must + * only be triggered when vsync is enabled for this display (through + * setVsyncEnabled). + * + * @param display is the display which has received a vsync event + * @param timestamp is the CLOCK_MONOTONIC time at which the vsync event + * occurred, in nanoseconds. + */ + @callflow(next="*") + oneway onVsync(Display display, int64_t timestamp); +};
diff --git a/graphics/composer/2.1/IComposerClient.hal b/graphics/composer/2.1/IComposerClient.hal new file mode 100644 index 0000000..107ac5e --- /dev/null +++ b/graphics/composer/2.1/IComposerClient.hal
@@ -0,0 +1,1142 @@ +/* + * Copyright (C) 2016 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.graphics.composer@2.1; + +import android.hardware.graphics.common@1.0; +import IComposerCallback; + +interface IComposerClient { + /* Display attributes queryable through getDisplayAttribute. */ + enum Attribute : int32_t { + INVALID = 0, + + /* Dimensions in pixels */ + WIDTH = 1, + HEIGHT = 2, + + /* Vsync period in nanoseconds */ + VSYNC_PERIOD = 3, + + /* + * Dots per thousand inches (DPI * 1000). Scaling by 1000 allows these + * numbers to be stored in an int32_t without losing too much + * precision. If the DPI for a configuration is unavailable or is + * considered unreliable, the device may return UNSUPPORTED instead. + */ + DPI_X = 4, + DPI_Y = 5, + }; + + /* Display requests returned by getDisplayRequests. */ + enum DisplayRequest : uint32_t { + /* + * Instructs the client to provide a new client target buffer, even if + * no layers are marked for client composition. + */ + FLIP_CLIENT_TARGET = 1 << 0, + + /* + * Instructs the client to write the result of client composition + * directly into the virtual display output buffer. If any of the + * layers are not marked as Composition::CLIENT or the given display + * is not a virtual display, this request has no effect. + */ + WRITE_CLIENT_TARGET_TO_OUTPUT = 1 << 1, + }; + + /* Layer requests returned from getDisplayRequests. */ + enum LayerRequest : uint32_t { + /* + * The client must clear its target with transparent pixels where + * this layer would be. The client may ignore this request if the + * layer must be blended. + */ + CLEAR_CLIENT_TARGET = 1 << 0, + }; + + /* Power modes for use with setPowerMode. */ + enum PowerMode : int32_t { + /* The display is fully off (blanked). */ + OFF = 0, + + /* + * These are optional low power modes. getDozeSupport may be called to + * determine whether a given display supports these modes. + */ + + /* + * The display is turned on and configured in a low power state that + * is suitable for presenting ambient information to the user, + * possibly with lower fidelity than ON, but with greater efficiency. + */ + DOZE = 1, + + /* + * The display is configured as in DOZE but may stop applying display + * updates from the client. This is effectively a hint to the device + * that drawing to the display has been suspended and that the the + * device must remain on in a low power state and continue + * displaying its current contents indefinitely until the power mode + * changes. + * + * This mode may also be used as a signal to enable hardware-based + * doze functionality. In this case, the device is free to take over + * the display and manage it autonomously to implement a low power + * always-on display. + */ + DOZE_SUSPEND = 3, + + /* The display is fully on. */ + ON = 2, + }; + + /* Vsync values passed to setVsyncEnabled. */ + enum Vsync : int32_t { + INVALID = 0, + + /* Enable vsync. */ + ENABLE = 1, + + /* Disable vsync. */ + DISABLE = 2, + }; + + /* Blend modes, settable per layer. */ + enum BlendMode : int32_t { + INVALID = 0, + + /* colorOut = colorSrc */ + NONE = 1, + + /* colorOut = colorSrc + colorDst * (1 - alphaSrc) */ + PREMULTIPLIED = 2, + + /* colorOut = colorSrc * alphaSrc + colorDst * (1 - alphaSrc) */ + COVERAGE = 3, + }; + + /* Possible composition types for a given layer. */ + enum Composition : int32_t { + INVALID = 0, + + /* + * The client must composite this layer into the client target buffer + * (provided to the device through setClientTarget). + * + * The device must not request any composition type changes for layers + * of this type. + */ + CLIENT = 1, + + /* + * The device must handle the composition of this layer through a + * hardware overlay or other similar means. + * + * Upon validateDisplay, the device may request a change from this + * type to CLIENT. + */ + DEVICE = 2, + + /* + * The device must render this layer using the color set through + * setLayerColor. If this functionality is not supported on a layer + * that the client sets to SOLID_COLOR, the device must request that + * the composition type of that layer is changed to CLIENT upon the + * next call to validateDisplay. + * + * Upon validateDisplay, the device may request a change from this + * type to CLIENT. + */ + SOLID_COLOR = 3, + + /* + * Similar to DEVICE, but the position of this layer may also be set + * asynchronously through setCursorPosition. If this functionality is + * not supported on a layer that the client sets to CURSOR, the device + * must request that the composition type of that layer is changed to + * CLIENT upon the next call to validateDisplay. + * + * Upon validateDisplay, the device may request a change from this + * type to either DEVICE or CLIENT. Changing to DEVICE will prevent + * the use of setCursorPosition but still permit the device to + * composite the layer. + */ + CURSOR = 4, + + /* + * The device must handle the composition of this layer, as well as + * its buffer updates and content synchronization. Only supported on + * devices which provide Capability::SIDEBAND_STREAM. + * + * Upon validateDisplay, the device may request a change from this + * type to either DEVICE or CLIENT, but it is unlikely that content + * will display correctly in these cases. + */ + SIDEBAND = 5, + }; + + /* Display types returned by getDisplayType. */ + enum DisplayType : int32_t { + INVALID = 0, + + /* + * All physical displays, including both internal displays and + * hotpluggable external displays. + */ + PHYSICAL = 1, + + /* Virtual displays created by createVirtualDisplay. */ + VIRTUAL = 2, + }; + + /* Special index values (always negative) for command queue commands. */ + enum HandleIndex : int32_t { + /* No handle */ + EMPTY = -1, + + /* Use cached handle */ + CACHED = -2, + }; + + struct Rect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; + }; + + struct FRect { + float left; + float top; + float right; + float bottom; + }; + + struct Color { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + + /* + * Provides a IComposerCallback object for the device to call. + * + * This function must be called only once. + * + * @param callback is the IComposerCallback object. + */ + @entry + @callflow(next="*") + registerCallback(IComposerCallback callback); + + /* + * Returns the maximum number of virtual displays supported by this device + * (which may be 0). The client must not attempt to create more than this + * many virtual displays on this device. This number must not change for + * the lifetime of the device. + * + * @return count is the maximum number of virtual displays supported. + */ + @callflow(next="*") + getMaxVirtualDisplayCount() generates (uint32_t count); + + /* + * Creates a new virtual display with the given width and height. The + * format passed into this function is the default format requested by the + * consumer of the virtual display output buffers. + * + * The display must be assumed to be on from the time the first frame is + * presented until the display is destroyed. + * + * @param width is the width in pixels. + * @param height is the height in pixels. + * @param formatHint is the default output buffer format selected by + * the consumer. + * @param outputBufferSlotCount is the number of output buffer slots to be + * reserved. + * @return error is NONE upon success. Otherwise, + * UNSUPPORTED when the width or height is too large for the + * device to be able to create a virtual display. + * NO_RESOURCES when the device is unable to create a new virtual + * display at this time. + * @return display is the newly-created virtual display. + * @return format is the format of the buffer the device will produce. + */ + @callflow(next="*") + createVirtualDisplay(uint32_t width, + uint32_t height, + PixelFormat formatHint, + uint32_t outputBufferSlotCount) + generates (Error error, + Display display, + PixelFormat format); + + /* + * Destroys a virtual display. After this call all resources consumed by + * this display may be freed by the device and any operations performed on + * this display must fail. + * + * @param display is the virtual display to destroy. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_PARAMETER when the display handle which was passed in does + * not refer to a virtual display. + */ + @callflow(next="*") + destroyVirtualDisplay(Display display) generates (Error error); + + /* + * Creates a new layer on the given display. + * + * @param display is the display on which to create the layer. + * @param bufferSlotCount is the number of buffer slot to be reserved. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * NO_RESOURCES when the device was unable to create a layer this + * time. + * @return layer is the handle of the new layer. + */ + @callflow(next="*") + createLayer(Display display, + uint32_t bufferSlotCount) + generates (Error error, + Layer layer); + + /* + * Destroys the given layer. + * + * @param display is the display on which the layer was created. + * @param layer is the layer to destroy. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_LAYER when an invalid layer handle was passed in. + */ + @callflow(next="*") + destroyLayer(Display display, Layer layer) generates (Error error); + + /* + * Retrieves which display configuration is currently active. + * + * If no display configuration is currently active, this function must + * return BAD_CONFIG. It is the responsibility of the client to call + * setActiveConfig with a valid configuration before attempting to present + * anything on the display. + * + * @param display is the display to which the active config is queried. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_CONFIG when no configuration is currently active. + * @return config is the currently active display configuration. + */ + @callflow(next="*") + getActiveConfig(Display display) generates (Error error, Config config); + + /* + * Returns whether a client target with the given properties can be + * handled by the device. + * + * This function must return true for a client target with width and + * height equal to the active display configuration dimensions, + * PixelFormat::RGBA_8888, and Dataspace::UNKNOWN. It is not required to + * return true for any other configuration. + * + * @param display is the display to query. + * @param width is the client target width in pixels. + * @param height is the client target height in pixels. + * @param format is the client target format. + * @param dataspace is the client target dataspace, as described in + * setLayerDataspace. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * UNSUPPORTED when the given configuration is not supported. + */ + @callflow(next="*") + getClientTargetSupport(Display display, + uint32_t width, + uint32_t height, + PixelFormat format, + Dataspace dataspace) + generates (Error error); + + /* + * Returns the color modes supported on this display. + * + * All devices must support at least ColorMode::NATIVE. + * + * @param display is the display to query. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return modes is an array of color modes. + */ + @callflow(next="*") + getColorModes(Display display) + generates (Error error, + vec<ColorMode> modes); + + /* + * Returns a display attribute value for a particular display + * configuration. + * + * @param display is the display to query. + * @param config is the display configuration for which to return + * attribute values. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_CONFIG when config does not name a valid configuration for + * this display. + * BAD_PARAMETER when attribute is unrecognized. + * UNSUPPORTED when attribute cannot be queried for the config. + * @return value is the value of the attribute. + */ + @callflow(next="*") + getDisplayAttribute(Display display, + Config config, + Attribute attribute) + generates (Error error, + int32_t value); + + /* + * Returns handles for all of the valid display configurations on this + * display. + * + * @param display is the display to query. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return configs is an array of configuration handles. + */ + @callflow(next="*") + getDisplayConfigs(Display display) + generates (Error error, + vec<Config> configs); + + /* + * Returns a human-readable version of the display's name. + * + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return name is the name of the display. + */ + @callflow(next="*") + getDisplayName(Display display) generates (Error error, string name); + + /* + * Returns whether the given display is a physical or virtual display. + * + * @param display is the display to query. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return type is the type of the display. + */ + @callflow(next="*") + getDisplayType(Display display) generates (Error error, DisplayType type); + + /* + * Returns whether the given display supports PowerMode::DOZE and + * PowerMode::DOZE_SUSPEND. DOZE_SUSPEND may not provide any benefit over + * DOZE (see the definition of PowerMode for more information), but if + * both DOZE and DOZE_SUSPEND are no different from PowerMode::ON, the + * device must not claim support. + * + * @param display is the display to query. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return support is true only when the display supports doze modes. + */ + @callflow(next="*") + getDozeSupport(Display display) generates (Error error, bool support); + + /* + * Returns the high dynamic range (HDR) capabilities of the given display, + * which are invariant with regard to the active configuration. + * + * Displays which are not HDR-capable must return no types. + * + * @param display is the display to query. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * @return types is an array of HDR types, may have 0 elements if the + * display is not HDR-capable. + * @return maxLuminance is the desired content maximum luminance for this + * display in cd/m^2. + * @return maxAverageLuminance - the desired content maximum frame-average + * luminance for this display in cd/m^2. + * @return minLuminance is the desired content minimum luminance for this + * display in cd/m^2. + */ + @callflow(next="*") + getHdrCapabilities(Display display) + generates (Error error, + vec<Hdr> types, + float maxLuminance, + float maxAverageLuminance, + float minLuminance); + + /* + * Set the number of client target slots to be reserved. + * + * @param display is the display to which the slots are reserved. + * @param clientTargetSlotCount is the slot count for client targets. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * NO_RESOURCES when unable to reserve the slots. + */ + @callflow(next="*") + setClientTargetSlotCount(Display display, + uint32_t clientTargetSlotCount) + generates (Error error); + + /* + * Sets the active configuration for this display. Upon returning, the + * given display configuration must be active and remain so until either + * this function is called again or the display is disconnected. + * + * @param display is the display to which the active config is set. + * @param config is the new display configuration. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_CONFIG when the configuration handle passed in is not valid + * for this display. + */ + @callflow(next="*") + setActiveConfig(Display display, Config config) generates (Error error); + + /* + * Sets the color mode of the given display. + * + * Upon returning from this function, the color mode change must have + * fully taken effect. + * + * All devices must support at least ColorMode::NATIVE, and displays are + * assumed to be in this mode upon hotplug. + * + * @param display is the display to which the color mode is set. + * @param mode is the mode to set to. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_PARAMETER when mode is not a valid color mode. + * UNSUPPORTED when mode is not supported on this display. + */ + @callflow(next="*") + setColorMode(Display display, ColorMode mode) generates (Error error); + + /* + * Sets the power mode of the given display. The transition must be + * complete when this function returns. It is valid to call this function + * multiple times with the same power mode. + * + * All displays must support PowerMode::ON and PowerMode::OFF. Whether a + * display supports PowerMode::DOZE or PowerMode::DOZE_SUSPEND may be + * queried using getDozeSupport. + * + * @param display is the display to which the power mode is set. + * @param mode is the new power mode. + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_PARAMETER when mode was not a valid power mode. + * UNSUPPORTED when mode is not supported on this display. + */ + @callflow(next="*") + setPowerMode(Display display, PowerMode mode) generates (Error error); + + /* + * Enables or disables the vsync signal for the given display. Virtual + * displays never generate vsync callbacks, and any attempt to enable + * vsync for a virtual display though this function must succeed and have + * no other effect. + * + * @param display is the display to which the vsync mode is set. + * @param enabled indicates whether to enable or disable vsync + * @return error is NONE upon success. Otherwise, + * BAD_DISPLAY when an invalid display handle was passed in. + * BAD_PARAMETER when enabled was an invalid value. + */ + @callflow(next="*") + setVsyncEnabled(Display display, Vsync enabled) generates (Error error); + + /* + * Sets the input command message queue. + * + * @param descriptor is the descriptor of the input command message queue. + * @return error is NONE upon success. Otherwise, + * NO_RESOURCES when failed to set the queue temporarily. + */ + @callflow(next="*") + setInputCommandQueue(fmq_sync<uint32_t> descriptor) + generates (Error error); + + /* + * Gets the output command message queue. + * + * This function must only be called inside executeCommands closure. + * + * @return error is NONE upon success. Otherwise, + * NO_RESOURCES when failed to get the queue temporarily. + * @return descriptor is the descriptor of the output command queue. + */ + @callflow(next="*") + getOutputCommandQueue() + generates (Error error, + fmq_sync<uint32_t> descriptor); + + /* + * Executes commands from the input command message queue. Return values + * generated by the input commands are written to the output command + * message queue in the form of value commands. + * + * @param inLength is the length of input commands. + * @param inHandles is an array of handles referenced by the input + * commands. + * @return error is NONE upon success. Otherwise, + * BAD_PARAMETER when inLength is not equal to the length of + * commands in the input command message queue. + * NO_RESOURCES when the output command message queue was not + * properly drained. + * @param outQueueChanged indicates whether the output command message + * queue has changed. + * @param outLength is the length of output commands. + * @param outHandles is an array of handles referenced by the output + * commands. + */ + @callflow(next="*") + executeCommands(uint32_t inLength, + vec<handle> inHandles) + generates (Error error, + bool outQueueChanged, + uint32_t outLength, + vec<handle> outHandles); + + /* + * SELECT_DISPLAY has this pseudo prototype + * + * selectDisplay(Display display); + * + * Selects the current display implied by all other commands. + * + * @param display is the newly selected display. + * + * + * SELECT_LAYER has this pseudo prototype + * + * selectLayer(Layer layer); + * + * Selects the current layer implied by all implicit layer commands. + * + * @param layer is the newly selected layer. + * + * + * SET_ERROR has this pseudo prototype + * + * setError(uint32_t location, Error error); + * + * Indicates an error generated by a command. + * + * @param location is the offset of the command in the input command + * message queue. + * @param error is the error generated by the command. + * + * + * SET_CHANGED_COMPOSITION_TYPES has this pseudo prototype + * + * setChangedCompositionTypes(vec<Layer> layers, + * vec<Composition> types); + * + * Sets the layers for which the device requires a different composition + * type than had been set prior to the last call to VALIDATE_DISPLAY. The + * client must either update its state with these types and call + * ACCEPT_DISPLAY_CHANGES, or must set new types and attempt to validate + * the display again. + * + * @param layers is an array of layer handles. + * @param types is an array of composition types, each corresponding to + * an element of layers. + * + * + * SET_DISPLAY_REQUESTS has this pseudo prototype + * + * setDisplayRequests(uint32_t displayRequestMask, + * vec<Layer> layers, + * vec<uint32_t> layerRequestMasks); + * + * Sets the display requests and the layer requests required for the last + * validated configuration. + * + * Display requests provide information about how the client must handle + * the client target. Layer requests provide information about how the + * client must handle an individual layer. + * + * @param displayRequestMask is the display requests for the current + * validated state. + * @param layers is an array of layers which all have at least one + * request. + * @param layerRequestMasks is the requests corresponding to each element + * of layers. + * + * + * SET_PRESENT_FENCE has this pseudo prototype + * + * setPresentFence(int32_t presentFenceIndex); + * + * Sets the present fence as a result of PRESENT_DISPLAY. For physical + * displays, this fence must be signaled at the vsync when the result + * of composition of this frame starts to appear (for video-mode panels) + * or starts to transfer to panel memory (for command-mode panels). For + * virtual displays, this fence must be signaled when writes to the output + * buffer have completed and it is safe to read from it. + * + * @param presentFenceIndex is an index into outHandles array. + * + * + * SET_RELEASE_FENCES has this pseudo prototype + * + * setReleaseFences(vec<Layer> layers, + * vec<int32_t> releaseFenceIndices); + * + * Sets the release fences for device layers on this display which will + * receive new buffer contents this frame. + * + * A release fence is a file descriptor referring to a sync fence object + * which must be signaled after the device has finished reading from the + * buffer presented in the prior frame. This indicates that it is safe to + * start writing to the buffer again. If a given layer's fence is not + * returned from this function, it must be assumed that the buffer + * presented on the previous frame is ready to be written. + * + * The fences returned by this function must be unique for each layer + * (even if they point to the same underlying sync object). + * + * @param layers is an array of layer handles. + * @param releaseFenceIndices are indices into outHandles array, each + * corresponding to an element of layers. + * + * + * SET_COLOR_TRANSFORM has this pseudo prototype + * + * setColorTransform(float[16] matrix, + * ColorTransform hint); + * + * Sets a color transform which will be applied after composition. + * + * If hint is not ColorTransform::ARBITRARY, then the device may use the + * hint to apply the desired color transform instead of using the color + * matrix directly. + * + * If the device is not capable of either using the hint or the matrix to + * apply the desired color transform, it must force all layers to client + * composition during VALIDATE_DISPLAY. + * + * If IComposer::Capability::SKIP_CLIENT_COLOR_TRANSFORM is present, then + * the client must never apply the color transform during client + * composition, even if all layers are being composed by the client. + * + * The matrix provided is an affine color transformation of the following + * form: + * + * |r.r r.g r.b 0| + * |g.r g.g g.b 0| + * |b.r b.g b.b 0| + * |Tr Tg Tb 1| + * + * This matrix must be provided in row-major form: + * + * {r.r, r.g, r.b, 0, g.r, ...}. + * + * Given a matrix of this form and an input color [R_in, G_in, B_in], the + * output color [R_out, G_out, B_out] will be: + * + * R_out = R_in * r.r + G_in * g.r + B_in * b.r + Tr + * G_out = R_in * r.g + G_in * g.g + B_in * b.g + Tg + * B_out = R_in * r.b + G_in * g.b + B_in * b.b + Tb + * + * @param matrix is a 4x4 transform matrix (16 floats) as described above. + * @param hint is a hint value which may be used instead of the given + * matrix unless it is ColorTransform::ARBITRARY. + * + * + * SET_CLIENT_TARGET has this pseudo prototype + * + * setClientTarget(uint32_t targetSlot, + * int32_t targetIndex, + * int32_t acquireFenceIndex, + * Dataspace dataspace, + * vec<Rect> damage); + * + * Sets the buffer handle which will receive the output of client + * composition. Layers marked as Composition::CLIENT must be composited + * into this buffer prior to the call to PRESENT_DISPLAY, and layers not + * marked as Composition::CLIENT must be composited with this buffer by + * the device. + * + * The buffer handle provided may be empty if no layers are being + * composited by the client. This must not result in an error (unless an + * invalid display handle is also provided). + * + * Also provides a file descriptor referring to an acquire sync fence + * object, which must be signaled when it is safe to read from the client + * target buffer. If it is already safe to read from this buffer, an + * empty handle may be passed instead. + * + * For more about dataspaces, see SET_LAYER_DATASPACE. + * + * The damage parameter describes a surface damage region as defined in + * the description of SET_LAYER_SURFACE_DAMAGE. + * + * Will be called before PRESENT_DISPLAY if any of the layers are marked + * as Composition::CLIENT. If no layers are so marked, then it is not + * necessary to call this function. It is not necessary to call + * validateDisplay after changing the target through this function. + * + * @param targetSlot is the client target buffer slot to use. + * @param targetIndex is an index into inHandles for the new target + * buffer. + * @param acquireFenceIndex is an index into inHandles for a sync fence + * file descriptor as described above. + * @param dataspace is the dataspace of the buffer, as described in + * setLayerDataspace. + * @param damage is the surface damage region. + * + * + * SET_OUTPUT_BUFFER has this pseudo prototype + * + * setOutputBuffer(uint32_t bufferSlot, + * int32_t bufferIndex, + * int32_t releaseFenceIndex); + * + * Sets the output buffer for a virtual display. That is, the buffer to + * which the composition result will be written. + * + * Also provides a file descriptor referring to a release sync fence + * object, which must be signaled when it is safe to write to the output + * buffer. If it is already safe to write to the output buffer, an empty + * handle may be passed instead. + * + * Must be called at least once before PRESENT_DISPLAY, but does not have + * any interaction with layer state or display validation. + * + * @param bufferSlot is the new output buffer. + * @param bufferIndex is the new output buffer. + * @param releaseFenceIndex is a sync fence file descriptor as described + * above. + * + * + * VALIDATE_DISPLAY has this pseudo prototype + * + * validateDisplay(); + * + * Instructs the device to inspect all of the layer state and determine if + * there are any composition type changes necessary before presenting the + * display. Permitted changes are described in the definition of + * Composition above. + * + * + * ACCEPT_DISPLAY_CHANGES has this pseudo prototype + * + * acceptDisplayChanges(); + * + * Accepts the changes required by the device from the previous + * validateDisplay call (which may be queried using + * getChangedCompositionTypes) and revalidates the display. This function + * is equivalent to requesting the changed types from + * getChangedCompositionTypes, setting those types on the corresponding + * layers, and then calling validateDisplay again. + * + * After this call it must be valid to present this display. Calling this + * after validateDisplay returns 0 changes must succeed with NONE, but + * must have no other effect. + * + * + * PRESENT_DISPLAY has this pseudo prototype + * + * presentDisplay(); + * + * Presents the current display contents on the screen (or in the case of + * virtual displays, into the output buffer). + * + * Prior to calling this function, the display must be successfully + * validated with validateDisplay. Note that setLayerBuffer and + * setLayerSurfaceDamage specifically do not count as layer state, so if + * there are no other changes to the layer state (or to the buffer's + * properties as described in setLayerBuffer), then it is safe to call + * this function without first validating the display. + * + * + * SET_LAYER_CURSOR_POSITION has this pseudo prototype + * + * setLayerCursorPosition(int32_t x, int32_t y); + * + * Asynchronously sets the position of a cursor layer. + * + * Prior to validateDisplay, a layer may be marked as Composition::CURSOR. + * If validation succeeds (i.e., the device does not request a composition + * change for that layer), then once a buffer has been set for the layer + * and it has been presented, its position may be set by this function at + * any time between presentDisplay and any subsequent validateDisplay + * calls for this display. + * + * Once validateDisplay is called, this function must not be called again + * until the validate/present sequence is completed. + * + * May be called from any thread so long as it is not interleaved with the + * validate/present sequence as described above. + * + * @param layer is the layer to which the position is set. + * @param x is the new x coordinate (in pixels from the left of the + * screen). + * @param y is the new y coordinate (in pixels from the top of the + * screen). + * + * + * SET_LAYER_BUFFER has this pseudo prototype + * + * setLayerBuffer(uint32_t bufferSlot, + * int32_t bufferIndex, + * int32_t acquireFenceIndex); + * + * Sets the buffer handle to be displayed for this layer. If the buffer + * properties set at allocation time (width, height, format, and usage) + * have not changed since the previous frame, it is not necessary to call + * validateDisplay before calling presentDisplay unless new state needs to + * be validated in the interim. + * + * Also provides a file descriptor referring to an acquire sync fence + * object, which must be signaled when it is safe to read from the given + * buffer. If it is already safe to read from the buffer, an empty handle + * may be passed instead. + * + * This function must return NONE and have no other effect if called for a + * layer with a composition type of Composition::SOLID_COLOR (because it + * has no buffer) or Composition::SIDEBAND or Composition::CLIENT (because + * synchronization and buffer updates for these layers are handled + * elsewhere). + * + * @param layer is the layer to which the buffer is set. + * @param bufferSlot is the buffer slot to use. + * @param bufferIndex is the buffer handle to set. + * @param acquireFenceIndex is a sync fence file descriptor as described above. + * + * + * SET_LAYER_SURFACE_DAMAGE has this pseudo prototype + * + * setLayerSurfaceDamage(vec<Rect> damage); + * + * Provides the region of the source buffer which has been modified since + * the last frame. This region does not need to be validated before + * calling presentDisplay. + * + * Once set through this function, the damage region remains the same + * until a subsequent call to this function. + * + * If damage is non-empty, then it may be assumed that any portion of the + * source buffer not covered by one of the rects has not been modified + * this frame. If damage is empty, then the whole source buffer must be + * treated as if it has been modified. + * + * If the layer's contents are not modified relative to the prior frame, + * damage must contain exactly one empty rect([0, 0, 0, 0]). + * + * The damage rects are relative to the pre-transformed buffer, and their + * origin is the top-left corner. They must not exceed the dimensions of + * the latched buffer. + * + * @param layer is the layer to which the damage region is set. + * @param damage is the new surface damage region. + * + * + * SET_LAYER_BLEND_MODE has this pseudo prototype + * + * setLayerBlendMode(BlendMode mode) + * + * Sets the blend mode of the given layer. + * + * @param mode is the new blend mode. + * + * + * SET_LAYER_COLOR has this pseudo prototype + * + * setLayerColor(Color color); + * + * Sets the color of the given layer. If the composition type of the layer + * is not Composition::SOLID_COLOR, this call must succeed and have no + * other effect. + * + * @param color is the new color. + * + * + * SET_LAYER_COMPOSITION_TYPE has this pseudo prototype + * + * setLayerCompositionType(Composition type); + * + * Sets the desired composition type of the given layer. During + * validateDisplay, the device may request changes to the composition + * types of any of the layers as described in the definition of + * Composition above. + * + * @param type is the new composition type. + * + * + * SET_LAYER_DATASPACE has this pseudo prototype + * + * setLayerDataspace(Dataspace dataspace); + * + * Sets the dataspace that the current buffer on this layer is in. + * + * The dataspace provides more information about how to interpret the + * buffer contents, such as the encoding standard and color transform. + * + * See the values of Dataspace for more information. + * + * @param dataspace is the new dataspace. + * + * + * SET_LAYER_DISPLAY_FRAME has this pseudo prototype + * + * setLayerDisplayFrame(Rect frame); + * + * Sets the display frame (the portion of the display covered by a layer) + * of the given layer. This frame must not exceed the display dimensions. + * + * @param frame is the new display frame. + * + * + * SET_LAYER_PLANE_ALPHA has this pseudo prototype + * + * setLayerPlaneAlpha(float alpha); + * + * Sets an alpha value (a floating point value in the range [0.0, 1.0]) + * which will be applied to the whole layer. It can be conceptualized as a + * preprocessing step which applies the following function: + * if (blendMode == BlendMode::PREMULTIPLIED) + * out.rgb = in.rgb * planeAlpha + * out.a = in.a * planeAlpha + * + * If the device does not support this operation on a layer which is + * marked Composition::DEVICE, it must request a composition type change + * to Composition::CLIENT upon the next validateDisplay call. + * + * @param alpha is the plane alpha value to apply. + * + * + * SET_LAYER_SIDEBAND_STREAM has this pseudo prototype + * + * setLayerSidebandStream(int32_t streamIndex) + * + * Sets the sideband stream for this layer. If the composition type of the + * given layer is not Composition::SIDEBAND, this call must succeed and + * have no other effect. + * + * @param streamIndex is the new sideband stream. + * + * + * SET_LAYER_SOURCE_CROP has this pseudo prototype + * + * setLayerSourceCrop(FRect crop); + * + * Sets the source crop (the portion of the source buffer which will fill + * the display frame) of the given layer. This crop rectangle must not + * exceed the dimensions of the latched buffer. + * + * If the device is not capable of supporting a true float source crop + * (i.e., it will truncate or round the floats to integers), it must set + * this layer to Composition::CLIENT when crop is non-integral for the + * most accurate rendering. + * + * If the device cannot support float source crops, but still wants to + * handle the layer, it must use the following code (or similar) to + * convert to an integer crop: + * intCrop.left = (int) ceilf(crop.left); + * intCrop.top = (int) ceilf(crop.top); + * intCrop.right = (int) floorf(crop.right); + * intCrop.bottom = (int) floorf(crop.bottom); + * + * @param crop is the new source crop. + * + * + * SET_LAYER_TRANSFORM has this pseudo prototype + * + * Sets the transform (rotation/flip) of the given layer. + * + * setLayerTransform(Transform transform); + * + * @param transform is the new transform. + * + * + * SET_LAYER_VISIBLE_REGION has this pseudo prototype + * + * setLayerVisibleRegion(vec<Rect> visible); + * + * Specifies the portion of the layer that is visible, including portions + * under translucent areas of other layers. The region is in screen space, + * and must not exceed the dimensions of the screen. + * + * @param visible is the new visible region, in screen space. + * + * + * SET_LAYER_Z_ORDER has this pseudo prototype + * + * setLayerZOrder(uint32_t z); + * + * Sets the desired Z order (height) of the given layer. A layer with a + * greater Z value occludes a layer with a lesser Z value. + * + * @param z is the new Z order. + */ + enum Command : int32_t { + LENGTH_MASK = 0xffff, + OPCODE_SHIFT = 16, + OPCODE_MASK = 0xffff << OPCODE_SHIFT, + + /* special commands */ + SELECT_DISPLAY = 0x000 << OPCODE_SHIFT, + SELECT_LAYER = 0x001 << OPCODE_SHIFT, + + /* value commands (for return values) */ + SET_ERROR = 0x100 << OPCODE_SHIFT, + SET_CHANGED_COMPOSITION_TYPES = 0x101 << OPCODE_SHIFT, + SET_DISPLAY_REQUESTS = 0x102 << OPCODE_SHIFT, + SET_PRESENT_FENCE = 0x103 << OPCODE_SHIFT, + SET_RELEASE_FENCES = 0x104 << OPCODE_SHIFT, + + /* display commands */ + SET_COLOR_TRANSFORM = 0x200 << OPCODE_SHIFT, + SET_CLIENT_TARGET = 0x201 << OPCODE_SHIFT, + SET_OUTPUT_BUFFER = 0x202 << OPCODE_SHIFT, + VALIDATE_DISPLAY = 0x203 << OPCODE_SHIFT, + ACCEPT_DISPLAY_CHANGES = 0x204 << OPCODE_SHIFT, + PRESENT_DISPLAY = 0x205 << OPCODE_SHIFT, + + /* layer commands (VALIDATE_DISPLAY not required) */ + SET_LAYER_CURSOR_POSITION = 0x300 << OPCODE_SHIFT, + SET_LAYER_BUFFER = 0x301 << OPCODE_SHIFT, + SET_LAYER_SURFACE_DAMAGE = 0x302 << OPCODE_SHIFT, + + /* layer state commands (VALIDATE_DISPLAY required) */ + SET_LAYER_BLEND_MODE = 0x400 << OPCODE_SHIFT, + SET_LAYER_COLOR = 0x401 << OPCODE_SHIFT, + SET_LAYER_COMPOSITION_TYPE = 0x402 << OPCODE_SHIFT, + SET_LAYER_DATASPACE = 0x403 << OPCODE_SHIFT, + SET_LAYER_DISPLAY_FRAME = 0x404 << OPCODE_SHIFT, + SET_LAYER_PLANE_ALPHA = 0x405 << OPCODE_SHIFT, + SET_LAYER_SIDEBAND_STREAM = 0x406 << OPCODE_SHIFT, + SET_LAYER_SOURCE_CROP = 0x407 << OPCODE_SHIFT, + SET_LAYER_TRANSFORM = 0x408 << OPCODE_SHIFT, + SET_LAYER_VISIBLE_REGION = 0x409 << OPCODE_SHIFT, + SET_LAYER_Z_ORDER = 0x40a << OPCODE_SHIFT, + + /* 0x800 - 0xfff are reserved for vendor extensions */ + /* 0x1000 - 0xffff are reserved */ + }; +};
diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp new file mode 100644 index 0000000..d5da943 --- /dev/null +++ b/graphics/composer/2.1/default/Android.bp
@@ -0,0 +1,72 @@ +cc_library_static { + name: "libhwcomposer-client", + defaults: ["hidl_defaults"], + export_include_dirs: ["."], + srcs: ["ComposerClient.cpp"], + shared_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.composer@2.1", + "libbase", + "libcutils", + "libfmq", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libsync", + "libutils", + ], +} + +cc_library_shared { + name: "android.hardware.graphics.composer@2.1-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["Hwc.cpp"], + static_libs: ["libhwcomposer-client"], + shared_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.composer@2.1", + "libbase", + "libcutils", + "libfmq", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libsync", + "libutils", + ], +} + +cc_binary { + name: "android.hardware.graphics.composer@2.1-service", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["service.cpp"], + init_rc: ["android.hardware.graphics.composer@2.1-service.rc"], + static_libs: ["libhwcomposer-client"], + shared_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.composer@2.1", + "libbase", + "libbinder", + "libcutils", + "libfmq", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libsync", + "libutils", + ], +} + +cc_library_static { + name: "libhwcomposer-command-buffer", + defaults: ["hidl_defaults"], + shared_libs: ["android.hardware.graphics.composer@2.1"], + export_include_dirs: ["."], +}
diff --git a/graphics/composer/2.1/default/ComposerBase.h b/graphics/composer/2.1/default/ComposerBase.h new file mode 100644 index 0000000..85b1a4d --- /dev/null +++ b/graphics/composer/2.1/default/ComposerBase.h
@@ -0,0 +1,130 @@ +/* + * Copyright 2017 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. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_BASE_H +#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_BASE_H + +#include <android/hardware/graphics/composer/2.1/IComposer.h> +#include <hardware/hwcomposer2.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace implementation { + +using android::hardware::graphics::common::V1_0::PixelFormat; +using android::hardware::graphics::common::V1_0::Transform; +using android::hardware::graphics::common::V1_0::Dataspace; +using android::hardware::graphics::common::V1_0::ColorMode; +using android::hardware::graphics::common::V1_0::ColorTransform; +using android::hardware::graphics::common::V1_0::Hdr; + +class ComposerBase { +public: + virtual ~ComposerBase() {}; + + virtual void removeClient() = 0; + virtual void enableCallback(bool enable) = 0; + virtual uint32_t getMaxVirtualDisplayCount() = 0; + virtual Error createVirtualDisplay(uint32_t width, uint32_t height, + PixelFormat* format, Display* outDisplay) = 0; + virtual Error destroyVirtualDisplay(Display display) = 0; + virtual Error createLayer(Display display, Layer* outLayer) = 0; + virtual Error destroyLayer(Display display, Layer layer) = 0; + + virtual Error getActiveConfig(Display display, Config* outConfig) = 0; + virtual Error getClientTargetSupport(Display display, + uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) = 0; + virtual Error getColorModes(Display display, + hidl_vec<ColorMode>* outModes) = 0; + virtual Error getDisplayAttribute(Display display, Config config, + IComposerClient::Attribute attribute, int32_t* outValue) = 0; + virtual Error getDisplayConfigs(Display display, + hidl_vec<Config>* outConfigs) = 0; + virtual Error getDisplayName(Display display, hidl_string* outName) = 0; + virtual Error getDisplayType(Display display, + IComposerClient::DisplayType* outType) = 0; + virtual Error getDozeSupport(Display display, bool* outSupport) = 0; + virtual Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, + float* outMaxLuminance, float* outMaxAverageLuminance, + float* outMinLuminance) = 0; + + virtual Error setActiveConfig(Display display, Config config) = 0; + virtual Error setColorMode(Display display, ColorMode mode) = 0; + virtual Error setPowerMode(Display display, + IComposerClient::PowerMode mode) = 0; + virtual Error setVsyncEnabled(Display display, + IComposerClient::Vsync enabled) = 0; + + virtual Error setColorTransform(Display display, const float* matrix, + int32_t hint) = 0; + virtual Error setClientTarget(Display display, buffer_handle_t target, + int32_t acquireFence, int32_t dataspace, + const std::vector<hwc_rect_t>& damage) = 0; + virtual Error setOutputBuffer(Display display, buffer_handle_t buffer, + int32_t releaseFence) = 0; + virtual Error validateDisplay(Display display, + std::vector<Layer>* outChangedLayers, + std::vector<IComposerClient::Composition>* outCompositionTypes, + uint32_t* outDisplayRequestMask, + std::vector<Layer>* outRequestedLayers, + std::vector<uint32_t>* outRequestMasks) = 0; + virtual Error acceptDisplayChanges(Display display) = 0; + virtual Error presentDisplay(Display display, int32_t* outPresentFence, + std::vector<Layer>* outLayers, + std::vector<int32_t>* outReleaseFences) = 0; + + virtual Error setLayerCursorPosition(Display display, Layer layer, + int32_t x, int32_t y) = 0; + virtual Error setLayerBuffer(Display display, Layer layer, + buffer_handle_t buffer, int32_t acquireFence) = 0; + virtual Error setLayerSurfaceDamage(Display display, Layer layer, + const std::vector<hwc_rect_t>& damage) = 0; + virtual Error setLayerBlendMode(Display display, Layer layer, + int32_t mode) = 0; + virtual Error setLayerColor(Display display, Layer layer, + IComposerClient::Color color) = 0; + virtual Error setLayerCompositionType(Display display, Layer layer, + int32_t type) = 0; + virtual Error setLayerDataspace(Display display, Layer layer, + int32_t dataspace) = 0; + virtual Error setLayerDisplayFrame(Display display, Layer layer, + const hwc_rect_t& frame) = 0; + virtual Error setLayerPlaneAlpha(Display display, Layer layer, + float alpha) = 0; + virtual Error setLayerSidebandStream(Display display, Layer layer, + buffer_handle_t stream) = 0; + virtual Error setLayerSourceCrop(Display display, Layer layer, + const hwc_frect_t& crop) = 0; + virtual Error setLayerTransform(Display display, Layer layer, + int32_t transform) = 0; + virtual Error setLayerVisibleRegion(Display display, Layer layer, + const std::vector<hwc_rect_t>& visible) = 0; + virtual Error setLayerZOrder(Display display, Layer layer, + uint32_t z) = 0; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_BASE_H
diff --git a/graphics/composer/2.1/default/ComposerClient.cpp b/graphics/composer/2.1/default/ComposerClient.cpp new file mode 100644 index 0000000..a2d5d4b --- /dev/null +++ b/graphics/composer/2.1/default/ComposerClient.cpp
@@ -0,0 +1,1210 @@ +/* + * Copyright 2016 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. + */ + +#define LOG_TAG "HwcPassthrough" + +#include <hardware/gralloc.h> +#include <hardware/gralloc1.h> +#include <log/log.h> + +#include "ComposerClient.h" +#include "Hwc.h" +#include "IComposerCommandBuffer.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace implementation { + +namespace { + +class HandleImporter { +public: + HandleImporter() : mInitialized(false) {} + + bool initialize() + { + // allow only one client + if (mInitialized) { + return false; + } + + if (!openGralloc()) { + return false; + } + + mInitialized = true; + return true; + } + + void cleanup() + { + if (!mInitialized) { + return; + } + + closeGralloc(); + mInitialized = false; + } + + // In IComposer, any buffer_handle_t is owned by the caller and we need to + // make a clone for hwcomposer2. We also need to translate empty handle + // to nullptr. This function does that, in-place. + bool importBuffer(buffer_handle_t& handle) + { + if (!handle) { + return true; + } + + if (!handle->numFds && !handle->numInts) { + handle = nullptr; + return true; + } + + buffer_handle_t clone = cloneBuffer(handle); + if (!clone) { + return false; + } + + handle = clone; + return true; + } + + void freeBuffer(buffer_handle_t handle) + { + if (!handle) { + return; + } + + releaseBuffer(handle); + } + +private: + bool mInitialized; + + // Some existing gralloc drivers do not support retaining more than once, + // when we are in passthrough mode. + bool openGralloc() + { + const hw_module_t* module = nullptr; + int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); + if (err) { + ALOGE("failed to get gralloc module"); + return false; + } + + uint8_t major = (module->module_api_version >> 8) & 0xff; + if (major > 1) { + ALOGE("unknown gralloc module major version %d", major); + return false; + } + + if (major == 1) { + err = gralloc1_open(module, &mDevice); + if (err) { + ALOGE("failed to open gralloc1 device"); + return false; + } + + mRetain = reinterpret_cast<GRALLOC1_PFN_RETAIN>( + mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RETAIN)); + mRelease = reinterpret_cast<GRALLOC1_PFN_RELEASE>( + mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RELEASE)); + if (!mRetain || !mRelease) { + ALOGE("invalid gralloc1 device"); + gralloc1_close(mDevice); + return false; + } + } else { + mModule = reinterpret_cast<const gralloc_module_t*>(module); + } + + return true; + } + + void closeGralloc() + { + if (mDevice) { + gralloc1_close(mDevice); + } + } + + buffer_handle_t cloneBuffer(buffer_handle_t handle) + { + native_handle_t* clone = native_handle_clone(handle); + if (!clone) { + ALOGE("failed to clone buffer %p", handle); + return nullptr; + } + + bool err; + if (mDevice) { + err = (mRetain(mDevice, clone) != GRALLOC1_ERROR_NONE); + } else { + err = (mModule->registerBuffer(mModule, clone) != 0); + } + + if (err) { + ALOGE("failed to retain/register buffer %p", clone); + native_handle_close(clone); + native_handle_delete(clone); + return nullptr; + } + + return clone; + } + + void releaseBuffer(buffer_handle_t handle) + { + if (mDevice) { + mRelease(mDevice, handle); + } else { + mModule->unregisterBuffer(mModule, handle); + } + native_handle_close(handle); + native_handle_delete(const_cast<native_handle_t*>(handle)); + } + + // gralloc1 + gralloc1_device_t* mDevice; + GRALLOC1_PFN_RETAIN mRetain; + GRALLOC1_PFN_RELEASE mRelease; + + // gralloc0 + const gralloc_module_t* mModule; +}; + +HandleImporter sHandleImporter; + +} // anonymous namespace + +BufferCacheEntry::BufferCacheEntry() + : mHandle(nullptr) +{ +} + +BufferCacheEntry::BufferCacheEntry(BufferCacheEntry&& other) +{ + mHandle = other.mHandle; + other.mHandle = nullptr; +} + +BufferCacheEntry& BufferCacheEntry::operator=(buffer_handle_t handle) +{ + clear(); + mHandle = handle; + return *this; +} + +BufferCacheEntry::~BufferCacheEntry() +{ + clear(); +} + +void BufferCacheEntry::clear() +{ + if (mHandle) { + sHandleImporter.freeBuffer(mHandle); + } +} + +ComposerClient::ComposerClient(ComposerBase& hal) + : mHal(hal), mWriter(kWriterInitialSize) +{ +} + +ComposerClient::~ComposerClient() +{ + // We want to call hwc2_close here (and move hwc2_open to the + // constructor), with the assumption that hwc2_close would + // + // - clean up all resources owned by the client + // - make sure all displays are blank (since there is no layer) + // + // But since SF used to crash at this point, different hwcomposer2 + // implementations behave differently on hwc2_close. Our only portable + // choice really is to abort(). But that is not an option anymore + // because we might also have VTS or VR as clients that can come and go. + // + // Below we manually clean all resources (layers and virtual + // displays), and perform a presentDisplay afterwards. + ALOGW("destroying composer client"); + + mHal.enableCallback(false); + + // no need to grab the mutex as any in-flight hwbinder call would have + // kept the client alive + for (const auto& dpy : mDisplayData) { + ALOGW("destroying client resources for display %" PRIu64, dpy.first); + + for (const auto& ly : dpy.second.Layers) { + mHal.destroyLayer(dpy.first, ly.first); + } + + if (dpy.second.IsVirtual) { + mHal.destroyVirtualDisplay(dpy.first); + } else { + ALOGW("performing a final presentDisplay"); + + std::vector<Layer> changedLayers; + std::vector<IComposerClient::Composition> compositionTypes; + uint32_t displayRequestMask = 0; + std::vector<Layer> requestedLayers; + std::vector<uint32_t> requestMasks; + mHal.validateDisplay(dpy.first, &changedLayers, &compositionTypes, + &displayRequestMask, &requestedLayers, &requestMasks); + + mHal.acceptDisplayChanges(dpy.first); + + int32_t presentFence = -1; + std::vector<Layer> releasedLayers; + std::vector<int32_t> releaseFences; + mHal.presentDisplay(dpy.first, &presentFence, &releasedLayers, &releaseFences); + if (presentFence >= 0) { + close(presentFence); + } + for (auto fence : releaseFences) { + if (fence >= 0) { + close(fence); + } + } + } + } + + mDisplayData.clear(); + + sHandleImporter.cleanup(); + + mHal.removeClient(); + + ALOGW("removed composer client"); +} + +void ComposerClient::initialize() +{ + mReader = createCommandReader(); + if (!sHandleImporter.initialize()) { + LOG_ALWAYS_FATAL("failed to initialize handle importer"); + } +} + +void ComposerClient::onHotplug(Display display, + IComposerCallback::Connection connected) +{ + { + std::lock_guard<std::mutex> lock(mDisplayDataMutex); + + if (connected == IComposerCallback::Connection::CONNECTED) { + mDisplayData.emplace(display, DisplayData(false)); + } else if (connected == IComposerCallback::Connection::DISCONNECTED) { + mDisplayData.erase(display); + } + } + + auto ret = mCallback->onHotplug(display, connected); + ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", + ret.description().c_str()); +} + +void ComposerClient::onRefresh(Display display) +{ + auto ret = mCallback->onRefresh(display); + ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", + ret.description().c_str()); +} + +void ComposerClient::onVsync(Display display, int64_t timestamp) +{ + auto ret = mCallback->onVsync(display, timestamp); + ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", + ret.description().c_str()); +} + +Return<void> ComposerClient::registerCallback( + const sp<IComposerCallback>& callback) +{ + // no locking as we require this function to be called only once + mCallback = callback; + mHal.enableCallback(callback != nullptr); + + return Void(); +} + +Return<uint32_t> ComposerClient::getMaxVirtualDisplayCount() +{ + return mHal.getMaxVirtualDisplayCount(); +} + +Return<void> ComposerClient::createVirtualDisplay(uint32_t width, + uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount, + createVirtualDisplay_cb hidl_cb) +{ + Display display = 0; + Error err = mHal.createVirtualDisplay(width, height, + &formatHint, &display); + if (err == Error::NONE) { + std::lock_guard<std::mutex> lock(mDisplayDataMutex); + + auto dpy = mDisplayData.emplace(display, DisplayData(true)).first; + dpy->second.OutputBuffers.resize(outputBufferSlotCount); + } + + hidl_cb(err, display, formatHint); + return Void(); +} + +Return<Error> ComposerClient::destroyVirtualDisplay(Display display) +{ + Error err = mHal.destroyVirtualDisplay(display); + if (err == Error::NONE) { + std::lock_guard<std::mutex> lock(mDisplayDataMutex); + + mDisplayData.erase(display); + } + + return err; +} + +Return<void> ComposerClient::createLayer(Display display, + uint32_t bufferSlotCount, createLayer_cb hidl_cb) +{ + Layer layer = 0; + Error err = mHal.createLayer(display, &layer); + if (err == Error::NONE) { + std::lock_guard<std::mutex> lock(mDisplayDataMutex); + + auto dpy = mDisplayData.find(display); + auto ly = dpy->second.Layers.emplace(layer, LayerBuffers()).first; + ly->second.Buffers.resize(bufferSlotCount); + } + + hidl_cb(err, layer); + return Void(); +} + +Return<Error> ComposerClient::destroyLayer(Display display, Layer layer) +{ + Error err = mHal.destroyLayer(display, layer); + if (err == Error::NONE) { + std::lock_guard<std::mutex> lock(mDisplayDataMutex); + + auto dpy = mDisplayData.find(display); + dpy->second.Layers.erase(layer); + } + + return err; +} + +Return<void> ComposerClient::getActiveConfig(Display display, + getActiveConfig_cb hidl_cb) +{ + Config config = 0; + Error err = mHal.getActiveConfig(display, &config); + + hidl_cb(err, config); + return Void(); +} + +Return<Error> ComposerClient::getClientTargetSupport(Display display, + uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) +{ + Error err = mHal.getClientTargetSupport(display, + width, height, format, dataspace); + return err; +} + +Return<void> ComposerClient::getColorModes(Display display, + getColorModes_cb hidl_cb) +{ + hidl_vec<ColorMode> modes; + Error err = mHal.getColorModes(display, &modes); + + hidl_cb(err, modes); + return Void(); +} + +Return<void> ComposerClient::getDisplayAttribute(Display display, + Config config, Attribute attribute, + getDisplayAttribute_cb hidl_cb) +{ + int32_t value = 0; + Error err = mHal.getDisplayAttribute(display, config, attribute, &value); + + hidl_cb(err, value); + return Void(); +} + +Return<void> ComposerClient::getDisplayConfigs(Display display, + getDisplayConfigs_cb hidl_cb) +{ + hidl_vec<Config> configs; + Error err = mHal.getDisplayConfigs(display, &configs); + + hidl_cb(err, configs); + return Void(); +} + +Return<void> ComposerClient::getDisplayName(Display display, + getDisplayName_cb hidl_cb) +{ + hidl_string name; + Error err = mHal.getDisplayName(display, &name); + + hidl_cb(err, name); + return Void(); +} + +Return<void> ComposerClient::getDisplayType(Display display, + getDisplayType_cb hidl_cb) +{ + DisplayType type = DisplayType::INVALID; + Error err = mHal.getDisplayType(display, &type); + + hidl_cb(err, type); + return Void(); +} + +Return<void> ComposerClient::getDozeSupport(Display display, + getDozeSupport_cb hidl_cb) +{ + bool support = false; + Error err = mHal.getDozeSupport(display, &support); + + hidl_cb(err, support); + return Void(); +} + +Return<void> ComposerClient::getHdrCapabilities(Display display, + getHdrCapabilities_cb hidl_cb) +{ + hidl_vec<Hdr> types; + float max_lumi = 0.0f; + float max_avg_lumi = 0.0f; + float min_lumi = 0.0f; + Error err = mHal.getHdrCapabilities(display, &types, + &max_lumi, &max_avg_lumi, &min_lumi); + + hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi); + return Void(); +} + +Return<Error> ComposerClient::setClientTargetSlotCount(Display display, + uint32_t clientTargetSlotCount) +{ + std::lock_guard<std::mutex> lock(mDisplayDataMutex); + + auto dpy = mDisplayData.find(display); + if (dpy == mDisplayData.end()) { + return Error::BAD_DISPLAY; + } + + dpy->second.ClientTargets.resize(clientTargetSlotCount); + + return Error::NONE; +} + +Return<Error> ComposerClient::setActiveConfig(Display display, Config config) +{ + Error err = mHal.setActiveConfig(display, config); + return err; +} + +Return<Error> ComposerClient::setColorMode(Display display, ColorMode mode) +{ + Error err = mHal.setColorMode(display, mode); + return err; +} + +Return<Error> ComposerClient::setPowerMode(Display display, PowerMode mode) +{ + Error err = mHal.setPowerMode(display, mode); + return err; +} + +Return<Error> ComposerClient::setVsyncEnabled(Display display, Vsync enabled) +{ + Error err = mHal.setVsyncEnabled(display, enabled); + return err; +} + +Return<Error> ComposerClient::setInputCommandQueue( + const MQDescriptorSync<uint32_t>& descriptor) +{ + std::lock_guard<std::mutex> lock(mCommandMutex); + return mReader->setMQDescriptor(descriptor) ? + Error::NONE : Error::NO_RESOURCES; +} + +Return<void> ComposerClient::getOutputCommandQueue( + getOutputCommandQueue_cb hidl_cb) +{ + // no locking as we require this function to be called inside + // executeCommands_cb + + auto outDescriptor = mWriter.getMQDescriptor(); + if (outDescriptor) { + hidl_cb(Error::NONE, *outDescriptor); + } else { + hidl_cb(Error::NO_RESOURCES, CommandQueueType::Descriptor()); + } + + return Void(); +} + +Return<void> ComposerClient::executeCommands(uint32_t inLength, + const hidl_vec<hidl_handle>& inHandles, + executeCommands_cb hidl_cb) +{ + std::lock_guard<std::mutex> lock(mCommandMutex); + + bool outChanged = false; + uint32_t outLength = 0; + hidl_vec<hidl_handle> outHandles; + + if (!mReader->readQueue(inLength, inHandles)) { + hidl_cb(Error::BAD_PARAMETER, outChanged, outLength, outHandles); + return Void(); + } + + Error err = mReader->parse(); + if (err == Error::NONE && + !mWriter.writeQueue(&outChanged, &outLength, &outHandles)) { + err = Error::NO_RESOURCES; + } + + hidl_cb(err, outChanged, outLength, outHandles); + + mReader->reset(); + mWriter.reset(); + + return Void(); +} + +std::unique_ptr<ComposerClient::CommandReader> +ComposerClient::createCommandReader() +{ + return std::unique_ptr<ComposerClient::CommandReader>( + new CommandReader(*this)); +} + +ComposerClient::CommandReader::CommandReader(ComposerClient& client) + : mClient(client), mHal(client.mHal), mWriter(client.mWriter) +{ +} + +ComposerClient::CommandReader::~CommandReader() +{ +} + +Error ComposerClient::CommandReader::parse() +{ + IComposerClient::Command command; + uint16_t length = 0; + + while (!isEmpty()) { + if (!beginCommand(&command, &length)) { + break; + } + + bool parsed = parseCommand(command, length); + endCommand(); + + if (!parsed) { + ALOGE("failed to parse command 0x%x, length %" PRIu16, + command, length); + break; + } + } + + return (isEmpty()) ? Error::NONE : Error::BAD_PARAMETER; +} + +bool ComposerClient::CommandReader::parseCommand( + IComposerClient::Command command, uint16_t length) { + switch (command) { + case IComposerClient::Command::SELECT_DISPLAY: + return parseSelectDisplay(length); + case IComposerClient::Command::SELECT_LAYER: + return parseSelectLayer(length); + case IComposerClient::Command::SET_COLOR_TRANSFORM: + return parseSetColorTransform(length); + case IComposerClient::Command::SET_CLIENT_TARGET: + return parseSetClientTarget(length); + case IComposerClient::Command::SET_OUTPUT_BUFFER: + return parseSetOutputBuffer(length); + case IComposerClient::Command::VALIDATE_DISPLAY: + return parseValidateDisplay(length); + case IComposerClient::Command::ACCEPT_DISPLAY_CHANGES: + return parseAcceptDisplayChanges(length); + case IComposerClient::Command::PRESENT_DISPLAY: + return parsePresentDisplay(length); + case IComposerClient::Command::SET_LAYER_CURSOR_POSITION: + return parseSetLayerCursorPosition(length); + case IComposerClient::Command::SET_LAYER_BUFFER: + return parseSetLayerBuffer(length); + case IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE: + return parseSetLayerSurfaceDamage(length); + case IComposerClient::Command::SET_LAYER_BLEND_MODE: + return parseSetLayerBlendMode(length); + case IComposerClient::Command::SET_LAYER_COLOR: + return parseSetLayerColor(length); + case IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE: + return parseSetLayerCompositionType(length); + case IComposerClient::Command::SET_LAYER_DATASPACE: + return parseSetLayerDataspace(length); + case IComposerClient::Command::SET_LAYER_DISPLAY_FRAME: + return parseSetLayerDisplayFrame(length); + case IComposerClient::Command::SET_LAYER_PLANE_ALPHA: + return parseSetLayerPlaneAlpha(length); + case IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM: + return parseSetLayerSidebandStream(length); + case IComposerClient::Command::SET_LAYER_SOURCE_CROP: + return parseSetLayerSourceCrop(length); + case IComposerClient::Command::SET_LAYER_TRANSFORM: + return parseSetLayerTransform(length); + case IComposerClient::Command::SET_LAYER_VISIBLE_REGION: + return parseSetLayerVisibleRegion(length); + case IComposerClient::Command::SET_LAYER_Z_ORDER: + return parseSetLayerZOrder(length); + default: + return false; + } +} + +bool ComposerClient::CommandReader::parseSelectDisplay(uint16_t length) +{ + if (length != CommandWriterBase::kSelectDisplayLength) { + return false; + } + + mDisplay = read64(); + mWriter.selectDisplay(mDisplay); + + return true; +} + +bool ComposerClient::CommandReader::parseSelectLayer(uint16_t length) +{ + if (length != CommandWriterBase::kSelectLayerLength) { + return false; + } + + mLayer = read64(); + + return true; +} + +bool ComposerClient::CommandReader::parseSetColorTransform(uint16_t length) +{ + if (length != CommandWriterBase::kSetColorTransformLength) { + return false; + } + + float matrix[16]; + for (int i = 0; i < 16; i++) { + matrix[i] = readFloat(); + } + auto transform = readSigned(); + + auto err = mHal.setColorTransform(mDisplay, matrix, transform); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetClientTarget(uint16_t length) +{ + // 4 parameters followed by N rectangles + if ((length - 4) % 4 != 0) { + return false; + } + + bool useCache = false; + auto slot = read(); + auto clientTarget = readHandle(&useCache); + auto fence = readFence(); + auto dataspace = readSigned(); + auto damage = readRegion((length - 4) / 4); + + auto err = lookupBuffer(BufferCache::CLIENT_TARGETS, + slot, useCache, clientTarget, &clientTarget); + if (err == Error::NONE) { + err = mHal.setClientTarget(mDisplay, clientTarget, fence, + dataspace, damage); + + updateBuffer(BufferCache::CLIENT_TARGETS, slot, useCache, + clientTarget); + } + if (err != Error::NONE) { + close(fence); + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetOutputBuffer(uint16_t length) +{ + if (length != CommandWriterBase::kSetOutputBufferLength) { + return false; + } + + bool useCache = false; + auto slot = read(); + auto outputBuffer = readHandle(&useCache); + auto fence = readFence(); + + auto err = lookupBuffer(BufferCache::OUTPUT_BUFFERS, + slot, useCache, outputBuffer, &outputBuffer); + if (err == Error::NONE) { + err = mHal.setOutputBuffer(mDisplay, outputBuffer, fence); + + updateBuffer(BufferCache::OUTPUT_BUFFERS, + slot, useCache, outputBuffer); + } + if (err != Error::NONE) { + close(fence); + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseValidateDisplay(uint16_t length) +{ + if (length != CommandWriterBase::kValidateDisplayLength) { + return false; + } + + std::vector<Layer> changedLayers; + std::vector<IComposerClient::Composition> compositionTypes; + uint32_t displayRequestMask = 0x0; + std::vector<Layer> requestedLayers; + std::vector<uint32_t> requestMasks; + + auto err = mHal.validateDisplay(mDisplay, &changedLayers, + &compositionTypes, &displayRequestMask, + &requestedLayers, &requestMasks); + if (err == Error::NONE) { + mWriter.setChangedCompositionTypes(changedLayers, + compositionTypes); + mWriter.setDisplayRequests(displayRequestMask, + requestedLayers, requestMasks); + } else { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseAcceptDisplayChanges(uint16_t length) +{ + if (length != CommandWriterBase::kAcceptDisplayChangesLength) { + return false; + } + + auto err = mHal.acceptDisplayChanges(mDisplay); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parsePresentDisplay(uint16_t length) +{ + if (length != CommandWriterBase::kPresentDisplayLength) { + return false; + } + + int presentFence = -1; + std::vector<Layer> layers; + std::vector<int> fences; + auto err = mHal.presentDisplay(mDisplay, &presentFence, &layers, &fences); + if (err == Error::NONE) { + mWriter.setPresentFence(presentFence); + mWriter.setReleaseFences(layers, fences); + } else { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerCursorPosition(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerCursorPositionLength) { + return false; + } + + auto err = mHal.setLayerCursorPosition(mDisplay, mLayer, + readSigned(), readSigned()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerBuffer(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerBufferLength) { + return false; + } + + bool useCache = false; + auto slot = read(); + auto buffer = readHandle(&useCache); + auto fence = readFence(); + + auto err = lookupBuffer(BufferCache::LAYER_BUFFERS, + slot, useCache, buffer, &buffer); + if (err == Error::NONE) { + err = mHal.setLayerBuffer(mDisplay, mLayer, buffer, fence); + + updateBuffer(BufferCache::LAYER_BUFFERS, + slot, useCache, buffer); + } + if (err != Error::NONE) { + close(fence); + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerSurfaceDamage(uint16_t length) +{ + // N rectangles + if (length % 4 != 0) { + return false; + } + + auto damage = readRegion(length / 4); + auto err = mHal.setLayerSurfaceDamage(mDisplay, mLayer, damage); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerBlendMode(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerBlendModeLength) { + return false; + } + + auto err = mHal.setLayerBlendMode(mDisplay, mLayer, readSigned()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerColor(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerColorLength) { + return false; + } + + auto err = mHal.setLayerColor(mDisplay, mLayer, readColor()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerCompositionType( + uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerCompositionTypeLength) { + return false; + } + + auto err = mHal.setLayerCompositionType(mDisplay, mLayer, readSigned()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerDataspace(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerDataspaceLength) { + return false; + } + + auto err = mHal.setLayerDataspace(mDisplay, mLayer, readSigned()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerDisplayFrame(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerDisplayFrameLength) { + return false; + } + + auto err = mHal.setLayerDisplayFrame(mDisplay, mLayer, readRect()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerPlaneAlpha(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerPlaneAlphaLength) { + return false; + } + + auto err = mHal.setLayerPlaneAlpha(mDisplay, mLayer, readFloat()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerSidebandStream(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerSidebandStreamLength) { + return false; + } + + auto stream = readHandle(); + + auto err = lookupLayerSidebandStream(stream, &stream); + if (err == Error::NONE) { + err = mHal.setLayerSidebandStream(mDisplay, mLayer, stream); + + updateLayerSidebandStream(stream); + } + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerSourceCrop(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerSourceCropLength) { + return false; + } + + auto err = mHal.setLayerSourceCrop(mDisplay, mLayer, readFRect()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerTransform(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerTransformLength) { + return false; + } + + auto err = mHal.setLayerTransform(mDisplay, mLayer, readSigned()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerVisibleRegion(uint16_t length) +{ + // N rectangles + if (length % 4 != 0) { + return false; + } + + auto region = readRegion(length / 4); + auto err = mHal.setLayerVisibleRegion(mDisplay, mLayer, region); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +bool ComposerClient::CommandReader::parseSetLayerZOrder(uint16_t length) +{ + if (length != CommandWriterBase::kSetLayerZOrderLength) { + return false; + } + + auto err = mHal.setLayerZOrder(mDisplay, mLayer, read()); + if (err != Error::NONE) { + mWriter.setError(getCommandLoc(), err); + } + + return true; +} + +hwc_rect_t ComposerClient::CommandReader::readRect() +{ + return hwc_rect_t{ + readSigned(), + readSigned(), + readSigned(), + readSigned(), + }; +} + +std::vector<hwc_rect_t> ComposerClient::CommandReader::readRegion(size_t count) +{ + std::vector<hwc_rect_t> region; + region.reserve(count); + while (count > 0) { + region.emplace_back(readRect()); + count--; + } + + return region; +} + +hwc_frect_t ComposerClient::CommandReader::readFRect() +{ + return hwc_frect_t{ + readFloat(), + readFloat(), + readFloat(), + readFloat(), + }; +} + +Error ComposerClient::CommandReader::lookupBufferCacheEntryLocked( + BufferCache cache, uint32_t slot, BufferCacheEntry** outEntry) +{ + auto dpy = mClient.mDisplayData.find(mDisplay); + if (dpy == mClient.mDisplayData.end()) { + return Error::BAD_DISPLAY; + } + + BufferCacheEntry* entry = nullptr; + switch (cache) { + case BufferCache::CLIENT_TARGETS: + if (slot < dpy->second.ClientTargets.size()) { + entry = &dpy->second.ClientTargets[slot]; + } + break; + case BufferCache::OUTPUT_BUFFERS: + if (slot < dpy->second.OutputBuffers.size()) { + entry = &dpy->second.OutputBuffers[slot]; + } + break; + case BufferCache::LAYER_BUFFERS: + { + auto ly = dpy->second.Layers.find(mLayer); + if (ly == dpy->second.Layers.end()) { + return Error::BAD_LAYER; + } + if (slot < ly->second.Buffers.size()) { + entry = &ly->second.Buffers[slot]; + } + } + break; + case BufferCache::LAYER_SIDEBAND_STREAMS: + { + auto ly = dpy->second.Layers.find(mLayer); + if (ly == dpy->second.Layers.end()) { + return Error::BAD_LAYER; + } + if (slot == 0) { + entry = &ly->second.SidebandStream; + } + } + break; + default: + break; + } + + if (!entry) { + ALOGW("invalid buffer slot %" PRIu32, slot); + return Error::BAD_PARAMETER; + } + + *outEntry = entry; + + return Error::NONE; +} + +Error ComposerClient::CommandReader::lookupBuffer(BufferCache cache, + uint32_t slot, bool useCache, buffer_handle_t handle, + buffer_handle_t* outHandle) +{ + if (useCache) { + std::lock_guard<std::mutex> lock(mClient.mDisplayDataMutex); + + BufferCacheEntry* entry; + Error error = lookupBufferCacheEntryLocked(cache, slot, &entry); + if (error != Error::NONE) { + return error; + } + + // input handle is ignored + *outHandle = entry->getHandle(); + } else { + if (!sHandleImporter.importBuffer(handle)) { + return Error::NO_RESOURCES; + } + + *outHandle = handle; + } + + return Error::NONE; +} + +void ComposerClient::CommandReader::updateBuffer(BufferCache cache, + uint32_t slot, bool useCache, buffer_handle_t handle) +{ + // handle was looked up from cache + if (useCache) { + return; + } + + std::lock_guard<std::mutex> lock(mClient.mDisplayDataMutex); + + BufferCacheEntry* entry = nullptr; + lookupBufferCacheEntryLocked(cache, slot, &entry); + LOG_FATAL_IF(!entry, "failed to find the cache entry to update"); + + *entry = handle; +} + +} // namespace implementation +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android
diff --git a/graphics/composer/2.1/default/ComposerClient.h b/graphics/composer/2.1/default/ComposerClient.h new file mode 100644 index 0000000..14da1f8 --- /dev/null +++ b/graphics/composer/2.1/default/ComposerClient.h
@@ -0,0 +1,222 @@ +/* + * Copyright 2016 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. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_CLIENT_H +#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_CLIENT_H + +#include <mutex> +#include <unordered_map> +#include <vector> + +#include "Hwc.h" +#include "IComposerCommandBuffer.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace implementation { + +class BufferCacheEntry { +public: + BufferCacheEntry(); + BufferCacheEntry(BufferCacheEntry&& other); + + BufferCacheEntry(const BufferCacheEntry& other) = delete; + BufferCacheEntry& operator=(const BufferCacheEntry& other) = delete; + + BufferCacheEntry& operator=(buffer_handle_t handle); + ~BufferCacheEntry(); + + buffer_handle_t getHandle() const { return mHandle; } + +private: + void clear(); + + buffer_handle_t mHandle; +}; + +class ComposerClient : public IComposerClient { +public: + ComposerClient(ComposerBase& hal); + virtual ~ComposerClient(); + + void initialize(); + + void onHotplug(Display display, IComposerCallback::Connection connected); + void onRefresh(Display display); + void onVsync(Display display, int64_t timestamp); + + // IComposerClient interface + Return<void> registerCallback( + const sp<IComposerCallback>& callback) override; + Return<uint32_t> getMaxVirtualDisplayCount() override; + Return<void> createVirtualDisplay(uint32_t width, uint32_t height, + PixelFormat formatHint, uint32_t outputBufferSlotCount, + createVirtualDisplay_cb hidl_cb) override; + Return<Error> destroyVirtualDisplay(Display display) override; + Return<void> createLayer(Display display, uint32_t bufferSlotCount, + createLayer_cb hidl_cb) override; + Return<Error> destroyLayer(Display display, Layer layer) override; + Return<void> getActiveConfig(Display display, + getActiveConfig_cb hidl_cb) override; + Return<Error> getClientTargetSupport(Display display, + uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) override; + Return<void> getColorModes(Display display, + getColorModes_cb hidl_cb) override; + Return<void> getDisplayAttribute(Display display, + Config config, Attribute attribute, + getDisplayAttribute_cb hidl_cb) override; + Return<void> getDisplayConfigs(Display display, + getDisplayConfigs_cb hidl_cb) override; + Return<void> getDisplayName(Display display, + getDisplayName_cb hidl_cb) override; + Return<void> getDisplayType(Display display, + getDisplayType_cb hidl_cb) override; + Return<void> getDozeSupport(Display display, + getDozeSupport_cb hidl_cb) override; + Return<void> getHdrCapabilities(Display display, + getHdrCapabilities_cb hidl_cb) override; + Return<Error> setActiveConfig(Display display, Config config) override; + Return<Error> setColorMode(Display display, ColorMode mode) override; + Return<Error> setPowerMode(Display display, PowerMode mode) override; + Return<Error> setVsyncEnabled(Display display, Vsync enabled) override; + Return<Error> setClientTargetSlotCount(Display display, + uint32_t clientTargetSlotCount) override; + Return<Error> setInputCommandQueue( + const MQDescriptorSync<uint32_t>& descriptor) override; + Return<void> getOutputCommandQueue( + getOutputCommandQueue_cb hidl_cb) override; + Return<void> executeCommands(uint32_t inLength, + const hidl_vec<hidl_handle>& inHandles, + executeCommands_cb hidl_cb) override; + +protected: + struct LayerBuffers { + std::vector<BufferCacheEntry> Buffers; + BufferCacheEntry SidebandStream; + }; + + struct DisplayData { + bool IsVirtual; + + std::vector<BufferCacheEntry> ClientTargets; + std::vector<BufferCacheEntry> OutputBuffers; + + std::unordered_map<Layer, LayerBuffers> Layers; + + DisplayData(bool isVirtual) : IsVirtual(isVirtual) {} + }; + + class CommandReader : public CommandReaderBase { + public: + CommandReader(ComposerClient& client); + virtual ~CommandReader(); + + Error parse(); + + protected: + virtual bool parseCommand(IComposerClient::Command command, + uint16_t length); + + bool parseSelectDisplay(uint16_t length); + bool parseSelectLayer(uint16_t length); + bool parseSetColorTransform(uint16_t length); + bool parseSetClientTarget(uint16_t length); + bool parseSetOutputBuffer(uint16_t length); + bool parseValidateDisplay(uint16_t length); + bool parseAcceptDisplayChanges(uint16_t length); + bool parsePresentDisplay(uint16_t length); + bool parseSetLayerCursorPosition(uint16_t length); + bool parseSetLayerBuffer(uint16_t length); + bool parseSetLayerSurfaceDamage(uint16_t length); + bool parseSetLayerBlendMode(uint16_t length); + bool parseSetLayerColor(uint16_t length); + bool parseSetLayerCompositionType(uint16_t length); + bool parseSetLayerDataspace(uint16_t length); + bool parseSetLayerDisplayFrame(uint16_t length); + bool parseSetLayerPlaneAlpha(uint16_t length); + bool parseSetLayerSidebandStream(uint16_t length); + bool parseSetLayerSourceCrop(uint16_t length); + bool parseSetLayerTransform(uint16_t length); + bool parseSetLayerVisibleRegion(uint16_t length); + bool parseSetLayerZOrder(uint16_t length); + + hwc_rect_t readRect(); + std::vector<hwc_rect_t> readRegion(size_t count); + hwc_frect_t readFRect(); + + enum class BufferCache { + CLIENT_TARGETS, + OUTPUT_BUFFERS, + LAYER_BUFFERS, + LAYER_SIDEBAND_STREAMS, + }; + Error lookupBufferCacheEntryLocked(BufferCache cache, uint32_t slot, + BufferCacheEntry** outEntry); + Error lookupBuffer(BufferCache cache, uint32_t slot, + bool useCache, buffer_handle_t handle, + buffer_handle_t* outHandle); + void updateBuffer(BufferCache cache, uint32_t slot, + bool useCache, buffer_handle_t handle); + + Error lookupLayerSidebandStream(buffer_handle_t handle, + buffer_handle_t* outHandle) + { + return lookupBuffer(BufferCache::LAYER_SIDEBAND_STREAMS, + 0, false, handle, outHandle); + } + void updateLayerSidebandStream(buffer_handle_t handle) + { + updateBuffer(BufferCache::LAYER_SIDEBAND_STREAMS, + 0, false, handle); + } + + ComposerClient& mClient; + ComposerBase& mHal; + CommandWriterBase& mWriter; + + Display mDisplay; + Layer mLayer; + }; + + virtual std::unique_ptr<CommandReader> createCommandReader(); + + ComposerBase& mHal; + + // 64KiB minus a small space for metadata such as read/write pointers + static constexpr size_t kWriterInitialSize = + 64 * 1024 / sizeof(uint32_t) - 16; + std::mutex mCommandMutex; + std::unique_ptr<CommandReader> mReader; + CommandWriterBase mWriter; + + sp<IComposerCallback> mCallback; + + std::mutex mDisplayDataMutex; + std::unordered_map<Display, DisplayData> mDisplayData; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_COMPOSER_CLIENT_H
diff --git a/graphics/composer/2.1/default/Hwc.cpp b/graphics/composer/2.1/default/Hwc.cpp new file mode 100644 index 0000000..cf82967 --- /dev/null +++ b/graphics/composer/2.1/default/Hwc.cpp
@@ -0,0 +1,712 @@ +/* + * Copyright 2016 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. + */ + +#define LOG_TAG "HwcPassthrough" + +#include <type_traits> + +#include <log/log.h> + +#include "ComposerClient.h" +#include "Hwc.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace implementation { + +HwcHal::HwcHal(const hw_module_t* module) + : mDevice(nullptr), mDispatch() +{ + int status = hwc2_open(module, &mDevice); + if (status) { + LOG_ALWAYS_FATAL("failed to open hwcomposer2 device: %s", + strerror(-status)); + } + + initCapabilities(); + initDispatch(); +} + +HwcHal::~HwcHal() +{ + hwc2_close(mDevice); +} + +void HwcHal::initCapabilities() +{ + uint32_t count = 0; + mDevice->getCapabilities(mDevice, &count, nullptr); + + std::vector<Capability> caps(count); + mDevice->getCapabilities(mDevice, &count, reinterpret_cast< + std::underlying_type<Capability>::type*>(caps.data())); + caps.resize(count); + + mCapabilities.insert(caps.cbegin(), caps.cend()); +} + +template<typename T> +void HwcHal::initDispatch(hwc2_function_descriptor_t desc, T* outPfn) +{ + auto pfn = mDevice->getFunction(mDevice, desc); + if (!pfn) { + LOG_ALWAYS_FATAL("failed to get hwcomposer2 function %d", desc); + } + + *outPfn = reinterpret_cast<T>(pfn); +} + +void HwcHal::initDispatch() +{ + initDispatch(HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES, + &mDispatch.acceptDisplayChanges); + initDispatch(HWC2_FUNCTION_CREATE_LAYER, &mDispatch.createLayer); + initDispatch(HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY, + &mDispatch.createVirtualDisplay); + initDispatch(HWC2_FUNCTION_DESTROY_LAYER, &mDispatch.destroyLayer); + initDispatch(HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY, + &mDispatch.destroyVirtualDisplay); + initDispatch(HWC2_FUNCTION_DUMP, &mDispatch.dump); + initDispatch(HWC2_FUNCTION_GET_ACTIVE_CONFIG, &mDispatch.getActiveConfig); + initDispatch(HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES, + &mDispatch.getChangedCompositionTypes); + initDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT, + &mDispatch.getClientTargetSupport); + initDispatch(HWC2_FUNCTION_GET_COLOR_MODES, &mDispatch.getColorModes); + initDispatch(HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE, + &mDispatch.getDisplayAttribute); + initDispatch(HWC2_FUNCTION_GET_DISPLAY_CONFIGS, + &mDispatch.getDisplayConfigs); + initDispatch(HWC2_FUNCTION_GET_DISPLAY_NAME, &mDispatch.getDisplayName); + initDispatch(HWC2_FUNCTION_GET_DISPLAY_REQUESTS, + &mDispatch.getDisplayRequests); + initDispatch(HWC2_FUNCTION_GET_DISPLAY_TYPE, &mDispatch.getDisplayType); + initDispatch(HWC2_FUNCTION_GET_DOZE_SUPPORT, &mDispatch.getDozeSupport); + initDispatch(HWC2_FUNCTION_GET_HDR_CAPABILITIES, + &mDispatch.getHdrCapabilities); + initDispatch(HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT, + &mDispatch.getMaxVirtualDisplayCount); + initDispatch(HWC2_FUNCTION_GET_RELEASE_FENCES, + &mDispatch.getReleaseFences); + initDispatch(HWC2_FUNCTION_PRESENT_DISPLAY, &mDispatch.presentDisplay); + initDispatch(HWC2_FUNCTION_REGISTER_CALLBACK, + &mDispatch.registerCallback); + initDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG, &mDispatch.setActiveConfig); + initDispatch(HWC2_FUNCTION_SET_CLIENT_TARGET, &mDispatch.setClientTarget); + initDispatch(HWC2_FUNCTION_SET_COLOR_MODE, &mDispatch.setColorMode); + initDispatch(HWC2_FUNCTION_SET_COLOR_TRANSFORM, + &mDispatch.setColorTransform); + initDispatch(HWC2_FUNCTION_SET_CURSOR_POSITION, + &mDispatch.setCursorPosition); + initDispatch(HWC2_FUNCTION_SET_LAYER_BLEND_MODE, + &mDispatch.setLayerBlendMode); + initDispatch(HWC2_FUNCTION_SET_LAYER_BUFFER, &mDispatch.setLayerBuffer); + initDispatch(HWC2_FUNCTION_SET_LAYER_COLOR, &mDispatch.setLayerColor); + initDispatch(HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE, + &mDispatch.setLayerCompositionType); + initDispatch(HWC2_FUNCTION_SET_LAYER_DATASPACE, + &mDispatch.setLayerDataspace); + initDispatch(HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME, + &mDispatch.setLayerDisplayFrame); + initDispatch(HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA, + &mDispatch.setLayerPlaneAlpha); + + if (hasCapability(Capability::SIDEBAND_STREAM)) { + initDispatch(HWC2_FUNCTION_SET_LAYER_SIDEBAND_STREAM, + &mDispatch.setLayerSidebandStream); + } + + initDispatch(HWC2_FUNCTION_SET_LAYER_SOURCE_CROP, + &mDispatch.setLayerSourceCrop); + initDispatch(HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE, + &mDispatch.setLayerSurfaceDamage); + initDispatch(HWC2_FUNCTION_SET_LAYER_TRANSFORM, + &mDispatch.setLayerTransform); + initDispatch(HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION, + &mDispatch.setLayerVisibleRegion); + initDispatch(HWC2_FUNCTION_SET_LAYER_Z_ORDER, &mDispatch.setLayerZOrder); + initDispatch(HWC2_FUNCTION_SET_OUTPUT_BUFFER, &mDispatch.setOutputBuffer); + initDispatch(HWC2_FUNCTION_SET_POWER_MODE, &mDispatch.setPowerMode); + initDispatch(HWC2_FUNCTION_SET_VSYNC_ENABLED, &mDispatch.setVsyncEnabled); + initDispatch(HWC2_FUNCTION_VALIDATE_DISPLAY, &mDispatch.validateDisplay); +} + +bool HwcHal::hasCapability(Capability capability) const +{ + return (mCapabilities.count(capability) > 0); +} + +Return<void> HwcHal::getCapabilities(getCapabilities_cb hidl_cb) +{ + std::vector<Capability> caps( + mCapabilities.cbegin(), mCapabilities.cend()); + + hidl_vec<Capability> caps_reply; + caps_reply.setToExternal(caps.data(), caps.size()); + hidl_cb(caps_reply); + + return Void(); +} + +Return<void> HwcHal::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) +{ + uint32_t len = 0; + mDispatch.dump(mDevice, &len, nullptr); + + std::vector<char> buf(len + 1); + mDispatch.dump(mDevice, &len, buf.data()); + buf.resize(len + 1); + buf[len] = '\0'; + + hidl_string buf_reply; + buf_reply.setToExternal(buf.data(), len); + hidl_cb(buf_reply); + + return Void(); +} + +Return<void> HwcHal::createClient(createClient_cb hidl_cb) +{ + Error err = Error::NONE; + sp<ComposerClient> client; + + { + std::lock_guard<std::mutex> lock(mClientMutex); + + // only one client is allowed + if (mClient == nullptr) { + client = new ComposerClient(*this); + client->initialize(); + mClient = client; + } else { + err = Error::NO_RESOURCES; + } + } + + hidl_cb(err, client); + + return Void(); +} + +sp<ComposerClient> HwcHal::getClient() +{ + std::lock_guard<std::mutex> lock(mClientMutex); + return (mClient != nullptr) ? mClient.promote() : nullptr; +} + +void HwcHal::removeClient() +{ + std::lock_guard<std::mutex> lock(mClientMutex); + mClient = nullptr; +} + +void HwcHal::hotplugHook(hwc2_callback_data_t callbackData, + hwc2_display_t display, int32_t connected) +{ + auto hal = reinterpret_cast<HwcHal*>(callbackData); + auto client = hal->getClient(); + if (client != nullptr) { + client->onHotplug(display, + static_cast<IComposerCallback::Connection>(connected)); + } +} + +void HwcHal::refreshHook(hwc2_callback_data_t callbackData, + hwc2_display_t display) +{ + auto hal = reinterpret_cast<HwcHal*>(callbackData); + auto client = hal->getClient(); + if (client != nullptr) { + client->onRefresh(display); + } +} + +void HwcHal::vsyncHook(hwc2_callback_data_t callbackData, + hwc2_display_t display, int64_t timestamp) +{ + auto hal = reinterpret_cast<HwcHal*>(callbackData); + auto client = hal->getClient(); + if (client != nullptr) { + client->onVsync(display, timestamp); + } +} + +void HwcHal::enableCallback(bool enable) +{ + if (enable) { + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, + reinterpret_cast<hwc2_function_pointer_t>(hotplugHook)); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, + reinterpret_cast<hwc2_function_pointer_t>(refreshHook)); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, + reinterpret_cast<hwc2_function_pointer_t>(vsyncHook)); + } else { + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, + nullptr); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, + nullptr); + mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, + nullptr); + } +} + +uint32_t HwcHal::getMaxVirtualDisplayCount() +{ + return mDispatch.getMaxVirtualDisplayCount(mDevice); +} + +Error HwcHal::createVirtualDisplay(uint32_t width, uint32_t height, + PixelFormat* format, Display* outDisplay) +{ + int32_t hwc_format = static_cast<int32_t>(*format); + int32_t err = mDispatch.createVirtualDisplay(mDevice, width, height, + &hwc_format, outDisplay); + *format = static_cast<PixelFormat>(hwc_format); + + return static_cast<Error>(err); +} + +Error HwcHal::destroyVirtualDisplay(Display display) +{ + int32_t err = mDispatch.destroyVirtualDisplay(mDevice, display); + return static_cast<Error>(err); +} + +Error HwcHal::createLayer(Display display, Layer* outLayer) +{ + int32_t err = mDispatch.createLayer(mDevice, display, outLayer); + return static_cast<Error>(err); +} + +Error HwcHal::destroyLayer(Display display, Layer layer) +{ + int32_t err = mDispatch.destroyLayer(mDevice, display, layer); + return static_cast<Error>(err); +} + +Error HwcHal::getActiveConfig(Display display, Config* outConfig) +{ + int32_t err = mDispatch.getActiveConfig(mDevice, display, outConfig); + return static_cast<Error>(err); +} + +Error HwcHal::getClientTargetSupport(Display display, + uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) +{ + int32_t err = mDispatch.getClientTargetSupport(mDevice, display, + width, height, static_cast<int32_t>(format), + static_cast<int32_t>(dataspace)); + return static_cast<Error>(err); +} + +Error HwcHal::getColorModes(Display display, hidl_vec<ColorMode>* outModes) +{ + uint32_t count = 0; + int32_t err = mDispatch.getColorModes(mDevice, display, &count, nullptr); + if (err != HWC2_ERROR_NONE) { + return static_cast<Error>(err); + } + + outModes->resize(count); + err = mDispatch.getColorModes(mDevice, display, &count, + reinterpret_cast<std::underlying_type<ColorMode>::type*>( + outModes->data())); + if (err != HWC2_ERROR_NONE) { + *outModes = hidl_vec<ColorMode>(); + return static_cast<Error>(err); + } + + return Error::NONE; +} + +Error HwcHal::getDisplayAttribute(Display display, Config config, + IComposerClient::Attribute attribute, int32_t* outValue) +{ + int32_t err = mDispatch.getDisplayAttribute(mDevice, display, config, + static_cast<int32_t>(attribute), outValue); + return static_cast<Error>(err); +} + +Error HwcHal::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) +{ + uint32_t count = 0; + int32_t err = mDispatch.getDisplayConfigs(mDevice, display, + &count, nullptr); + if (err != HWC2_ERROR_NONE) { + return static_cast<Error>(err); + } + + outConfigs->resize(count); + err = mDispatch.getDisplayConfigs(mDevice, display, + &count, outConfigs->data()); + if (err != HWC2_ERROR_NONE) { + *outConfigs = hidl_vec<Config>(); + return static_cast<Error>(err); + } + + return Error::NONE; +} + +Error HwcHal::getDisplayName(Display display, hidl_string* outName) +{ + uint32_t count = 0; + int32_t err = mDispatch.getDisplayName(mDevice, display, &count, nullptr); + if (err != HWC2_ERROR_NONE) { + return static_cast<Error>(err); + } + + std::vector<char> buf(count + 1); + err = mDispatch.getDisplayName(mDevice, display, &count, buf.data()); + if (err != HWC2_ERROR_NONE) { + return static_cast<Error>(err); + } + buf.resize(count + 1); + buf[count] = '\0'; + + *outName = buf.data(); + + return Error::NONE; +} + +Error HwcHal::getDisplayType(Display display, + IComposerClient::DisplayType* outType) +{ + int32_t hwc_type = HWC2_DISPLAY_TYPE_INVALID; + int32_t err = mDispatch.getDisplayType(mDevice, display, &hwc_type); + *outType = static_cast<IComposerClient::DisplayType>(hwc_type); + + return static_cast<Error>(err); +} + +Error HwcHal::getDozeSupport(Display display, bool* outSupport) +{ + int32_t hwc_support = 0; + int32_t err = mDispatch.getDozeSupport(mDevice, display, &hwc_support); + *outSupport = hwc_support; + + return static_cast<Error>(err); +} + +Error HwcHal::getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, + float* outMaxLuminance, float* outMaxAverageLuminance, + float* outMinLuminance) +{ + uint32_t count = 0; + int32_t err = mDispatch.getHdrCapabilities(mDevice, display, &count, + nullptr, outMaxLuminance, outMaxAverageLuminance, + outMinLuminance); + if (err != HWC2_ERROR_NONE) { + return static_cast<Error>(err); + } + + outTypes->resize(count); + err = mDispatch.getHdrCapabilities(mDevice, display, &count, + reinterpret_cast<std::underlying_type<Hdr>::type*>( + outTypes->data()), outMaxLuminance, + outMaxAverageLuminance, outMinLuminance); + if (err != HWC2_ERROR_NONE) { + *outTypes = hidl_vec<Hdr>(); + return static_cast<Error>(err); + } + + return Error::NONE; +} + +Error HwcHal::setActiveConfig(Display display, Config config) +{ + int32_t err = mDispatch.setActiveConfig(mDevice, display, config); + return static_cast<Error>(err); +} + +Error HwcHal::setColorMode(Display display, ColorMode mode) +{ + int32_t err = mDispatch.setColorMode(mDevice, display, + static_cast<int32_t>(mode)); + return static_cast<Error>(err); +} + +Error HwcHal::setPowerMode(Display display, IComposerClient::PowerMode mode) +{ + int32_t err = mDispatch.setPowerMode(mDevice, display, + static_cast<int32_t>(mode)); + return static_cast<Error>(err); +} + +Error HwcHal::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) +{ + int32_t err = mDispatch.setVsyncEnabled(mDevice, display, + static_cast<int32_t>(enabled)); + return static_cast<Error>(err); +} + +Error HwcHal::setColorTransform(Display display, const float* matrix, + int32_t hint) +{ + int32_t err = mDispatch.setColorTransform(mDevice, display, matrix, hint); + return static_cast<Error>(err); +} + +Error HwcHal::setClientTarget(Display display, buffer_handle_t target, + int32_t acquireFence, int32_t dataspace, + const std::vector<hwc_rect_t>& damage) +{ + hwc_region region = { damage.size(), damage.data() }; + int32_t err = mDispatch.setClientTarget(mDevice, display, target, + acquireFence, dataspace, region); + return static_cast<Error>(err); +} + +Error HwcHal::setOutputBuffer(Display display, buffer_handle_t buffer, + int32_t releaseFence) +{ + int32_t err = mDispatch.setOutputBuffer(mDevice, display, buffer, + releaseFence); + // unlike in setClientTarget, releaseFence is owned by us + if (err == HWC2_ERROR_NONE && releaseFence >= 0) { + close(releaseFence); + } + + return static_cast<Error>(err); +} + +Error HwcHal::validateDisplay(Display display, + std::vector<Layer>* outChangedLayers, + std::vector<IComposerClient::Composition>* outCompositionTypes, + uint32_t* outDisplayRequestMask, + std::vector<Layer>* outRequestedLayers, + std::vector<uint32_t>* outRequestMasks) +{ + uint32_t types_count = 0; + uint32_t reqs_count = 0; + int32_t err = mDispatch.validateDisplay(mDevice, display, + &types_count, &reqs_count); + if (err != HWC2_ERROR_NONE && err != HWC2_ERROR_HAS_CHANGES) { + return static_cast<Error>(err); + } + + err = mDispatch.getChangedCompositionTypes(mDevice, display, + &types_count, nullptr, nullptr); + if (err != HWC2_ERROR_NONE) { + return static_cast<Error>(err); + } + + outChangedLayers->resize(types_count); + outCompositionTypes->resize(types_count); + err = mDispatch.getChangedCompositionTypes(mDevice, display, + &types_count, outChangedLayers->data(), + reinterpret_cast< + std::underlying_type<IComposerClient::Composition>::type*>( + outCompositionTypes->data())); + if (err != HWC2_ERROR_NONE) { + outChangedLayers->clear(); + outCompositionTypes->clear(); + return static_cast<Error>(err); + } + + int32_t display_reqs = 0; + err = mDispatch.getDisplayRequests(mDevice, display, &display_reqs, + &reqs_count, nullptr, nullptr); + if (err != HWC2_ERROR_NONE) { + outChangedLayers->clear(); + outCompositionTypes->clear(); + return static_cast<Error>(err); + } + + outRequestedLayers->resize(reqs_count); + outRequestMasks->resize(reqs_count); + err = mDispatch.getDisplayRequests(mDevice, display, &display_reqs, + &reqs_count, outRequestedLayers->data(), + reinterpret_cast<int32_t*>(outRequestMasks->data())); + if (err != HWC2_ERROR_NONE) { + outChangedLayers->clear(); + outCompositionTypes->clear(); + + outRequestedLayers->clear(); + outRequestMasks->clear(); + return static_cast<Error>(err); + } + + *outDisplayRequestMask = display_reqs; + + return static_cast<Error>(err); +} + +Error HwcHal::acceptDisplayChanges(Display display) +{ + int32_t err = mDispatch.acceptDisplayChanges(mDevice, display); + return static_cast<Error>(err); +} + +Error HwcHal::presentDisplay(Display display, int32_t* outPresentFence, + std::vector<Layer>* outLayers, std::vector<int32_t>* outReleaseFences) +{ + *outPresentFence = -1; + int32_t err = mDispatch.presentDisplay(mDevice, display, outPresentFence); + if (err != HWC2_ERROR_NONE) { + return static_cast<Error>(err); + } + + uint32_t count = 0; + err = mDispatch.getReleaseFences(mDevice, display, &count, + nullptr, nullptr); + if (err != HWC2_ERROR_NONE) { + ALOGW("failed to get release fences"); + return Error::NONE; + } + + outLayers->resize(count); + outReleaseFences->resize(count); + err = mDispatch.getReleaseFences(mDevice, display, &count, + outLayers->data(), outReleaseFences->data()); + if (err != HWC2_ERROR_NONE) { + ALOGW("failed to get release fences"); + outLayers->clear(); + outReleaseFences->clear(); + return Error::NONE; + } + + return static_cast<Error>(err); +} + +Error HwcHal::setLayerCursorPosition(Display display, Layer layer, + int32_t x, int32_t y) +{ + int32_t err = mDispatch.setCursorPosition(mDevice, display, layer, x, y); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerBuffer(Display display, Layer layer, + buffer_handle_t buffer, int32_t acquireFence) +{ + int32_t err = mDispatch.setLayerBuffer(mDevice, display, layer, + buffer, acquireFence); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerSurfaceDamage(Display display, Layer layer, + const std::vector<hwc_rect_t>& damage) +{ + hwc_region region = { damage.size(), damage.data() }; + int32_t err = mDispatch.setLayerSurfaceDamage(mDevice, display, layer, + region); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerBlendMode(Display display, Layer layer, int32_t mode) +{ + int32_t err = mDispatch.setLayerBlendMode(mDevice, display, layer, mode); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerColor(Display display, Layer layer, + IComposerClient::Color color) +{ + hwc_color_t hwc_color{color.r, color.g, color.b, color.a}; + int32_t err = mDispatch.setLayerColor(mDevice, display, layer, hwc_color); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerCompositionType(Display display, Layer layer, + int32_t type) +{ + int32_t err = mDispatch.setLayerCompositionType(mDevice, display, layer, + type); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerDataspace(Display display, Layer layer, + int32_t dataspace) +{ + int32_t err = mDispatch.setLayerDataspace(mDevice, display, layer, + dataspace); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerDisplayFrame(Display display, Layer layer, + const hwc_rect_t& frame) +{ + int32_t err = mDispatch.setLayerDisplayFrame(mDevice, display, layer, + frame); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerPlaneAlpha(Display display, Layer layer, float alpha) +{ + int32_t err = mDispatch.setLayerPlaneAlpha(mDevice, display, layer, + alpha); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerSidebandStream(Display display, Layer layer, + buffer_handle_t stream) +{ + int32_t err = mDispatch.setLayerSidebandStream(mDevice, display, layer, + stream); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerSourceCrop(Display display, Layer layer, + const hwc_frect_t& crop) +{ + int32_t err = mDispatch.setLayerSourceCrop(mDevice, display, layer, crop); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerTransform(Display display, Layer layer, + int32_t transform) +{ + int32_t err = mDispatch.setLayerTransform(mDevice, display, layer, + transform); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerVisibleRegion(Display display, Layer layer, + const std::vector<hwc_rect_t>& visible) +{ + hwc_region_t region = { visible.size(), visible.data() }; + int32_t err = mDispatch.setLayerVisibleRegion(mDevice, display, layer, + region); + return static_cast<Error>(err); +} + +Error HwcHal::setLayerZOrder(Display display, Layer layer, uint32_t z) +{ + int32_t err = mDispatch.setLayerZOrder(mDevice, display, layer, z); + return static_cast<Error>(err); +} + +IComposer* HIDL_FETCH_IComposer(const char*) +{ + const hw_module_t* module = nullptr; + int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &module); + if (err) { + ALOGE("failed to get hwcomposer module"); + return nullptr; + } + + return new HwcHal(module); +} + +} // namespace implementation +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android
diff --git a/graphics/composer/2.1/default/Hwc.h b/graphics/composer/2.1/default/Hwc.h new file mode 100644 index 0000000..ca08cf0 --- /dev/null +++ b/graphics/composer/2.1/default/Hwc.h
@@ -0,0 +1,218 @@ +/* + * Copyright 2016 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. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H +#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H + +#include <mutex> +#include <unordered_set> +#include <vector> + +#include <android/hardware/graphics/composer/2.1/IComposer.h> +#include <hardware/hwcomposer2.h> + +#include "ComposerBase.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace implementation { + +using android::hardware::graphics::common::V1_0::PixelFormat; +using android::hardware::graphics::common::V1_0::Transform; +using android::hardware::graphics::common::V1_0::Dataspace; +using android::hardware::graphics::common::V1_0::ColorMode; +using android::hardware::graphics::common::V1_0::ColorTransform; +using android::hardware::graphics::common::V1_0::Hdr; + +class ComposerClient; + +class HwcHal : public IComposer, public ComposerBase { +public: + HwcHal(const hw_module_t* module); + virtual ~HwcHal(); + + bool hasCapability(Capability capability) const; + + // IComposer interface + Return<void> getCapabilities(getCapabilities_cb hidl_cb) override; + Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; + Return<void> createClient(createClient_cb hidl_cb) override; + + // ComposerBase interface + void removeClient() override; + void enableCallback(bool enable) override; + uint32_t getMaxVirtualDisplayCount() override; + Error createVirtualDisplay(uint32_t width, uint32_t height, + PixelFormat* format, Display* outDisplay) override; + Error destroyVirtualDisplay(Display display) override; + + Error createLayer(Display display, Layer* outLayer) override; + Error destroyLayer(Display display, Layer layer) override; + + Error getActiveConfig(Display display, Config* outConfig) override; + Error getClientTargetSupport(Display display, + uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace) override; + Error getColorModes(Display display, + hidl_vec<ColorMode>* outModes) override; + Error getDisplayAttribute(Display display, Config config, + IComposerClient::Attribute attribute, int32_t* outValue) override; + Error getDisplayConfigs(Display display, + hidl_vec<Config>* outConfigs) override; + Error getDisplayName(Display display, hidl_string* outName) override; + Error getDisplayType(Display display, + IComposerClient::DisplayType* outType) override; + Error getDozeSupport(Display display, bool* outSupport) override; + Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, + float* outMaxLuminance, float* outMaxAverageLuminance, + float* outMinLuminance) override; + + Error setActiveConfig(Display display, Config config) override; + Error setColorMode(Display display, ColorMode mode) override; + Error setPowerMode(Display display, + IComposerClient::PowerMode mode) override; + Error setVsyncEnabled(Display display, + IComposerClient::Vsync enabled) override; + + Error setColorTransform(Display display, const float* matrix, + int32_t hint) override; + Error setClientTarget(Display display, buffer_handle_t target, + int32_t acquireFence, int32_t dataspace, + const std::vector<hwc_rect_t>& damage) override; + Error setOutputBuffer(Display display, buffer_handle_t buffer, + int32_t releaseFence) override; + Error validateDisplay(Display display, + std::vector<Layer>* outChangedLayers, + std::vector<IComposerClient::Composition>* outCompositionTypes, + uint32_t* outDisplayRequestMask, + std::vector<Layer>* outRequestedLayers, + std::vector<uint32_t>* outRequestMasks) override; + Error acceptDisplayChanges(Display display) override; + Error presentDisplay(Display display, int32_t* outPresentFence, + std::vector<Layer>* outLayers, + std::vector<int32_t>* outReleaseFences) override; + + Error setLayerCursorPosition(Display display, Layer layer, + int32_t x, int32_t y) override; + Error setLayerBuffer(Display display, Layer layer, + buffer_handle_t buffer, int32_t acquireFence) override; + Error setLayerSurfaceDamage(Display display, Layer layer, + const std::vector<hwc_rect_t>& damage) override; + Error setLayerBlendMode(Display display, Layer layer, + int32_t mode) override; + Error setLayerColor(Display display, Layer layer, + IComposerClient::Color color) override; + Error setLayerCompositionType(Display display, Layer layer, + int32_t type) override; + Error setLayerDataspace(Display display, Layer layer, + int32_t dataspace) override; + Error setLayerDisplayFrame(Display display, Layer layer, + const hwc_rect_t& frame) override; + Error setLayerPlaneAlpha(Display display, Layer layer, + float alpha) override; + Error setLayerSidebandStream(Display display, Layer layer, + buffer_handle_t stream) override; + Error setLayerSourceCrop(Display display, Layer layer, + const hwc_frect_t& crop) override; + Error setLayerTransform(Display display, Layer layer, + int32_t transform) override; + Error setLayerVisibleRegion(Display display, Layer layer, + const std::vector<hwc_rect_t>& visible) override; + Error setLayerZOrder(Display display, Layer layer, uint32_t z) override; + +private: + void initCapabilities(); + + template<typename T> + void initDispatch(hwc2_function_descriptor_t desc, T* outPfn); + void initDispatch(); + + sp<ComposerClient> getClient(); + + static void hotplugHook(hwc2_callback_data_t callbackData, + hwc2_display_t display, int32_t connected); + static void refreshHook(hwc2_callback_data_t callbackData, + hwc2_display_t display); + static void vsyncHook(hwc2_callback_data_t callbackData, + hwc2_display_t display, int64_t timestamp); + + hwc2_device_t* mDevice; + + std::unordered_set<Capability> mCapabilities; + + struct { + HWC2_PFN_ACCEPT_DISPLAY_CHANGES acceptDisplayChanges; + HWC2_PFN_CREATE_LAYER createLayer; + HWC2_PFN_CREATE_VIRTUAL_DISPLAY createVirtualDisplay; + HWC2_PFN_DESTROY_LAYER destroyLayer; + HWC2_PFN_DESTROY_VIRTUAL_DISPLAY destroyVirtualDisplay; + HWC2_PFN_DUMP dump; + HWC2_PFN_GET_ACTIVE_CONFIG getActiveConfig; + HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES getChangedCompositionTypes; + HWC2_PFN_GET_CLIENT_TARGET_SUPPORT getClientTargetSupport; + HWC2_PFN_GET_COLOR_MODES getColorModes; + HWC2_PFN_GET_DISPLAY_ATTRIBUTE getDisplayAttribute; + HWC2_PFN_GET_DISPLAY_CONFIGS getDisplayConfigs; + HWC2_PFN_GET_DISPLAY_NAME getDisplayName; + HWC2_PFN_GET_DISPLAY_REQUESTS getDisplayRequests; + HWC2_PFN_GET_DISPLAY_TYPE getDisplayType; + HWC2_PFN_GET_DOZE_SUPPORT getDozeSupport; + HWC2_PFN_GET_HDR_CAPABILITIES getHdrCapabilities; + HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT getMaxVirtualDisplayCount; + HWC2_PFN_GET_RELEASE_FENCES getReleaseFences; + HWC2_PFN_PRESENT_DISPLAY presentDisplay; + HWC2_PFN_REGISTER_CALLBACK registerCallback; + HWC2_PFN_SET_ACTIVE_CONFIG setActiveConfig; + HWC2_PFN_SET_CLIENT_TARGET setClientTarget; + HWC2_PFN_SET_COLOR_MODE setColorMode; + HWC2_PFN_SET_COLOR_TRANSFORM setColorTransform; + HWC2_PFN_SET_CURSOR_POSITION setCursorPosition; + HWC2_PFN_SET_LAYER_BLEND_MODE setLayerBlendMode; + HWC2_PFN_SET_LAYER_BUFFER setLayerBuffer; + HWC2_PFN_SET_LAYER_COLOR setLayerColor; + HWC2_PFN_SET_LAYER_COMPOSITION_TYPE setLayerCompositionType; + HWC2_PFN_SET_LAYER_DATASPACE setLayerDataspace; + HWC2_PFN_SET_LAYER_DISPLAY_FRAME setLayerDisplayFrame; + HWC2_PFN_SET_LAYER_PLANE_ALPHA setLayerPlaneAlpha; + HWC2_PFN_SET_LAYER_SIDEBAND_STREAM setLayerSidebandStream; + HWC2_PFN_SET_LAYER_SOURCE_CROP setLayerSourceCrop; + HWC2_PFN_SET_LAYER_SURFACE_DAMAGE setLayerSurfaceDamage; + HWC2_PFN_SET_LAYER_TRANSFORM setLayerTransform; + HWC2_PFN_SET_LAYER_VISIBLE_REGION setLayerVisibleRegion; + HWC2_PFN_SET_LAYER_Z_ORDER setLayerZOrder; + HWC2_PFN_SET_OUTPUT_BUFFER setOutputBuffer; + HWC2_PFN_SET_POWER_MODE setPowerMode; + HWC2_PFN_SET_VSYNC_ENABLED setVsyncEnabled; + HWC2_PFN_VALIDATE_DISPLAY validateDisplay; + } mDispatch; + + std::mutex mClientMutex; + wp<ComposerClient> mClient; +}; + +extern "C" IComposer* HIDL_FETCH_IComposer(const char* name); + +} // namespace implementation +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_V2_1_HWC_H
diff --git a/graphics/composer/2.1/default/IComposerCommandBuffer.h b/graphics/composer/2.1/default/IComposerCommandBuffer.h new file mode 100644 index 0000000..fb78ef8 --- /dev/null +++ b/graphics/composer/2.1/default/IComposerCommandBuffer.h
@@ -0,0 +1,849 @@ +/* + * Copyright 2016 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. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H +#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H + +#ifndef LOG_TAG +#warn "IComposerCommandBuffer.h included without LOG_TAG" +#endif + +#undef LOG_NDEBUG +#define LOG_NDEBUG 0 + +#include <algorithm> +#include <limits> +#include <memory> +#include <vector> + +#include <inttypes.h> +#include <string.h> + +#include <android/hardware/graphics/composer/2.1/IComposer.h> +#include <log/log.h> +#include <sync/sync.h> +#include <fmq/MessageQueue.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { + +using android::hardware::graphics::common::V1_0::ColorTransform; +using android::hardware::graphics::common::V1_0::Dataspace; +using android::hardware::graphics::common::V1_0::Transform; +using android::hardware::MessageQueue; + +using CommandQueueType = MessageQueue<uint32_t, kSynchronizedReadWrite>; + +// This class helps build a command queue. Note that all sizes/lengths are in +// units of uint32_t's. +class CommandWriterBase { +public: + CommandWriterBase(uint32_t initialMaxSize) + : mDataMaxSize(initialMaxSize) + { + mData = std::make_unique<uint32_t[]>(mDataMaxSize); + reset(); + } + + virtual ~CommandWriterBase() + { + reset(); + } + + void reset() + { + mDataWritten = 0; + mCommandEnd = 0; + + // handles in mDataHandles are owned by the caller + mDataHandles.clear(); + + // handles in mTemporaryHandles are owned by the writer + for (auto handle : mTemporaryHandles) { + native_handle_close(handle); + native_handle_delete(handle); + } + mTemporaryHandles.clear(); + } + + IComposerClient::Command getCommand(uint32_t offset) + { + uint32_t val = (offset < mDataWritten) ? mData[offset] : 0; + return static_cast<IComposerClient::Command>(val & + static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK)); + } + + bool writeQueue(bool* outQueueChanged, uint32_t* outCommandLength, + hidl_vec<hidl_handle>* outCommandHandles) + { + // write data to queue, optionally resizing it + if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) { + if (!mQueue->write(mData.get(), mDataWritten)) { + ALOGE("failed to write commands to message queue"); + return false; + } + + *outQueueChanged = false; + } else { + auto newQueue = std::make_unique<CommandQueueType>(mDataMaxSize); + if (!newQueue->isValid() || + !newQueue->write(mData.get(), mDataWritten)) { + ALOGE("failed to prepare a new message queue "); + return false; + } + + mQueue = std::move(newQueue); + *outQueueChanged = true; + } + + *outCommandLength = mDataWritten; + outCommandHandles->setToExternal( + const_cast<hidl_handle*>(mDataHandles.data()), + mDataHandles.size()); + + return true; + } + + const MQDescriptorSync<uint32_t>* getMQDescriptor() const + { + return (mQueue) ? mQueue->getDesc() : nullptr; + } + + static constexpr uint16_t kSelectDisplayLength = 2; + void selectDisplay(Display display) + { + beginCommand(IComposerClient::Command::SELECT_DISPLAY, + kSelectDisplayLength); + write64(display); + endCommand(); + } + + static constexpr uint16_t kSelectLayerLength = 2; + void selectLayer(Layer layer) + { + beginCommand(IComposerClient::Command::SELECT_LAYER, + kSelectLayerLength); + write64(layer); + endCommand(); + } + + static constexpr uint16_t kSetErrorLength = 2; + void setError(uint32_t location, Error error) + { + beginCommand(IComposerClient::Command::SET_ERROR, kSetErrorLength); + write(location); + writeSigned(static_cast<int32_t>(error)); + endCommand(); + } + + void setChangedCompositionTypes(const std::vector<Layer>& layers, + const std::vector<IComposerClient::Composition>& types) + { + size_t totalLayers = std::min(layers.size(), types.size()); + size_t currentLayer = 0; + + while (currentLayer < totalLayers) { + size_t count = std::min(totalLayers - currentLayer, + static_cast<size_t>(kMaxLength) / 3); + + beginCommand( + IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES, + count * 3); + for (size_t i = 0; i < count; i++) { + write64(layers[currentLayer + i]); + writeSigned(static_cast<int32_t>(types[currentLayer + i])); + } + endCommand(); + + currentLayer += count; + } + } + + void setDisplayRequests(uint32_t displayRequestMask, + const std::vector<Layer>& layers, + const std::vector<uint32_t>& layerRequestMasks) + { + size_t totalLayers = std::min(layers.size(), + layerRequestMasks.size()); + size_t currentLayer = 0; + + while (currentLayer < totalLayers) { + size_t count = std::min(totalLayers - currentLayer, + static_cast<size_t>(kMaxLength - 1) / 3); + + beginCommand(IComposerClient::Command::SET_DISPLAY_REQUESTS, + 1 + count * 3); + write(displayRequestMask); + for (size_t i = 0; i < count; i++) { + write64(layers[currentLayer + i]); + write(static_cast<int32_t>(layerRequestMasks[currentLayer + i])); + } + endCommand(); + + currentLayer += count; + } + } + + static constexpr uint16_t kSetPresentFenceLength = 1; + void setPresentFence(int presentFence) + { + beginCommand(IComposerClient::Command::SET_PRESENT_FENCE, + kSetPresentFenceLength); + writeFence(presentFence); + endCommand(); + } + + void setReleaseFences(const std::vector<Layer>& layers, + const std::vector<int>& releaseFences) + { + size_t totalLayers = std::min(layers.size(), releaseFences.size()); + size_t currentLayer = 0; + + while (currentLayer < totalLayers) { + size_t count = std::min(totalLayers - currentLayer, + static_cast<size_t>(kMaxLength) / 3); + + beginCommand(IComposerClient::Command::SET_RELEASE_FENCES, + count * 3); + for (size_t i = 0; i < count; i++) { + write64(layers[currentLayer + i]); + writeFence(releaseFences[currentLayer + i]); + } + endCommand(); + + currentLayer += count; + } + } + + static constexpr uint16_t kSetColorTransformLength = 17; + void setColorTransform(const float* matrix, ColorTransform hint) + { + beginCommand(IComposerClient::Command::SET_COLOR_TRANSFORM, + kSetColorTransformLength); + for (int i = 0; i < 16; i++) { + writeFloat(matrix[i]); + } + writeSigned(static_cast<int32_t>(hint)); + endCommand(); + } + + void setClientTarget(uint32_t slot, const native_handle_t* target, + int acquireFence, Dataspace dataspace, + const std::vector<IComposerClient::Rect>& damage) + { + bool doWrite = (damage.size() <= (kMaxLength - 4) / 4); + size_t length = 4 + ((doWrite) ? damage.size() * 4 : 0); + + beginCommand(IComposerClient::Command::SET_CLIENT_TARGET, length); + write(slot); + writeHandle(target, true); + writeFence(acquireFence); + writeSigned(static_cast<int32_t>(dataspace)); + // When there are too many rectangles in the damage region and doWrite + // is false, we write no rectangle at all which means the entire + // client target is damaged. + if (doWrite) { + writeRegion(damage); + } + endCommand(); + } + + static constexpr uint16_t kSetOutputBufferLength = 3; + void setOutputBuffer(uint32_t slot, const native_handle_t* buffer, + int releaseFence) + { + beginCommand(IComposerClient::Command::SET_OUTPUT_BUFFER, + kSetOutputBufferLength); + write(slot); + writeHandle(buffer, true); + writeFence(releaseFence); + endCommand(); + } + + static constexpr uint16_t kValidateDisplayLength = 0; + void validateDisplay() + { + beginCommand(IComposerClient::Command::VALIDATE_DISPLAY, + kValidateDisplayLength); + endCommand(); + } + + static constexpr uint16_t kAcceptDisplayChangesLength = 0; + void acceptDisplayChanges() + { + beginCommand(IComposerClient::Command::ACCEPT_DISPLAY_CHANGES, + kAcceptDisplayChangesLength); + endCommand(); + } + + static constexpr uint16_t kPresentDisplayLength = 0; + void presentDisplay() + { + beginCommand(IComposerClient::Command::PRESENT_DISPLAY, + kPresentDisplayLength); + endCommand(); + } + + static constexpr uint16_t kSetLayerCursorPositionLength = 2; + void setLayerCursorPosition(int32_t x, int32_t y) + { + beginCommand(IComposerClient::Command::SET_LAYER_CURSOR_POSITION, + kSetLayerCursorPositionLength); + writeSigned(x); + writeSigned(y); + endCommand(); + } + + static constexpr uint16_t kSetLayerBufferLength = 3; + void setLayerBuffer(uint32_t slot, const native_handle_t* buffer, + int acquireFence) + { + beginCommand(IComposerClient::Command::SET_LAYER_BUFFER, + kSetLayerBufferLength); + write(slot); + writeHandle(buffer, true); + writeFence(acquireFence); + endCommand(); + } + + void setLayerSurfaceDamage( + const std::vector<IComposerClient::Rect>& damage) + { + bool doWrite = (damage.size() <= kMaxLength / 4); + size_t length = (doWrite) ? damage.size() * 4 : 0; + + beginCommand(IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE, + length); + // When there are too many rectangles in the damage region and doWrite + // is false, we write no rectangle at all which means the entire + // layer is damaged. + if (doWrite) { + writeRegion(damage); + } + endCommand(); + } + + static constexpr uint16_t kSetLayerBlendModeLength = 1; + void setLayerBlendMode(IComposerClient::BlendMode mode) + { + beginCommand(IComposerClient::Command::SET_LAYER_BLEND_MODE, + kSetLayerBlendModeLength); + writeSigned(static_cast<int32_t>(mode)); + endCommand(); + } + + static constexpr uint16_t kSetLayerColorLength = 1; + void setLayerColor(IComposerClient::Color color) + { + beginCommand(IComposerClient::Command::SET_LAYER_COLOR, + kSetLayerColorLength); + writeColor(color); + endCommand(); + } + + static constexpr uint16_t kSetLayerCompositionTypeLength = 1; + void setLayerCompositionType(IComposerClient::Composition type) + { + beginCommand(IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE, + kSetLayerCompositionTypeLength); + writeSigned(static_cast<int32_t>(type)); + endCommand(); + } + + static constexpr uint16_t kSetLayerDataspaceLength = 1; + void setLayerDataspace(Dataspace dataspace) + { + beginCommand(IComposerClient::Command::SET_LAYER_DATASPACE, + kSetLayerDataspaceLength); + writeSigned(static_cast<int32_t>(dataspace)); + endCommand(); + } + + static constexpr uint16_t kSetLayerDisplayFrameLength = 4; + void setLayerDisplayFrame(const IComposerClient::Rect& frame) + { + beginCommand(IComposerClient::Command::SET_LAYER_DISPLAY_FRAME, + kSetLayerDisplayFrameLength); + writeRect(frame); + endCommand(); + } + + static constexpr uint16_t kSetLayerPlaneAlphaLength = 1; + void setLayerPlaneAlpha(float alpha) + { + beginCommand(IComposerClient::Command::SET_LAYER_PLANE_ALPHA, + kSetLayerPlaneAlphaLength); + writeFloat(alpha); + endCommand(); + } + + static constexpr uint16_t kSetLayerSidebandStreamLength = 1; + void setLayerSidebandStream(const native_handle_t* stream) + { + beginCommand(IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM, + kSetLayerSidebandStreamLength); + writeHandle(stream); + endCommand(); + } + + static constexpr uint16_t kSetLayerSourceCropLength = 4; + void setLayerSourceCrop(const IComposerClient::FRect& crop) + { + beginCommand(IComposerClient::Command::SET_LAYER_SOURCE_CROP, + kSetLayerSourceCropLength); + writeFRect(crop); + endCommand(); + } + + static constexpr uint16_t kSetLayerTransformLength = 1; + void setLayerTransform(Transform transform) + { + beginCommand(IComposerClient::Command::SET_LAYER_TRANSFORM, + kSetLayerTransformLength); + writeSigned(static_cast<int32_t>(transform)); + endCommand(); + } + + void setLayerVisibleRegion( + const std::vector<IComposerClient::Rect>& visible) + { + bool doWrite = (visible.size() <= kMaxLength / 4); + size_t length = (doWrite) ? visible.size() * 4 : 0; + + beginCommand(IComposerClient::Command::SET_LAYER_VISIBLE_REGION, + length); + // When there are too many rectangles in the visible region and + // doWrite is false, we write no rectangle at all which means the + // entire layer is visible. + if (doWrite) { + writeRegion(visible); + } + endCommand(); + } + + static constexpr uint16_t kSetLayerZOrderLength = 1; + void setLayerZOrder(uint32_t z) + { + beginCommand(IComposerClient::Command::SET_LAYER_Z_ORDER, + kSetLayerZOrderLength); + write(z); + endCommand(); + } + +protected: + void beginCommand(IComposerClient::Command command, uint16_t length) + { + if (mCommandEnd) { + LOG_FATAL("endCommand was not called before command 0x%x", + command); + } + + growData(1 + length); + write(static_cast<uint32_t>(command) | length); + + mCommandEnd = mDataWritten + length; + } + + void endCommand() + { + if (!mCommandEnd) { + LOG_FATAL("beginCommand was not called"); + } else if (mDataWritten > mCommandEnd) { + LOG_FATAL("too much data written"); + mDataWritten = mCommandEnd; + } else if (mDataWritten < mCommandEnd) { + LOG_FATAL("too little data written"); + while (mDataWritten < mCommandEnd) { + write(0); + } + } + + mCommandEnd = 0; + } + + void write(uint32_t val) + { + mData[mDataWritten++] = val; + } + + void writeSigned(int32_t val) + { + memcpy(&mData[mDataWritten++], &val, sizeof(val)); + } + + void writeFloat(float val) + { + memcpy(&mData[mDataWritten++], &val, sizeof(val)); + } + + void write64(uint64_t val) + { + uint32_t lo = static_cast<uint32_t>(val & 0xffffffff); + uint32_t hi = static_cast<uint32_t>(val >> 32); + write(lo); + write(hi); + } + + void writeRect(const IComposerClient::Rect& rect) + { + writeSigned(rect.left); + writeSigned(rect.top); + writeSigned(rect.right); + writeSigned(rect.bottom); + } + + void writeRegion(const std::vector<IComposerClient::Rect>& region) + { + for (const auto& rect : region) { + writeRect(rect); + } + } + + void writeFRect(const IComposerClient::FRect& rect) + { + writeFloat(rect.left); + writeFloat(rect.top); + writeFloat(rect.right); + writeFloat(rect.bottom); + } + + void writeColor(const IComposerClient::Color& color) + { + write((color.r << 0) | + (color.g << 8) | + (color.b << 16) | + (color.a << 24)); + } + + // ownership of handle is not transferred + void writeHandle(const native_handle_t* handle, bool useCache) + { + if (!handle) { + writeSigned(static_cast<int32_t>((useCache) ? + IComposerClient::HandleIndex::CACHED : + IComposerClient::HandleIndex::EMPTY)); + return; + } + + mDataHandles.push_back(handle); + writeSigned(mDataHandles.size() - 1); + } + + void writeHandle(const native_handle_t* handle) + { + writeHandle(handle, false); + } + + // ownership of fence is transferred + void writeFence(int fence) + { + native_handle_t* handle = nullptr; + if (fence >= 0) { + handle = getTemporaryHandle(1, 0); + if (handle) { + handle->data[0] = fence; + } else { + ALOGW("failed to get temporary handle for fence %d", fence); + sync_wait(fence, -1); + close(fence); + } + } + + writeHandle(handle); + } + + native_handle_t* getTemporaryHandle(int numFds, int numInts) + { + native_handle_t* handle = native_handle_create(numFds, numInts); + if (handle) { + mTemporaryHandles.push_back(handle); + } + return handle; + } + + static constexpr uint16_t kMaxLength = + std::numeric_limits<uint16_t>::max(); + +private: + void growData(uint32_t grow) + { + uint32_t newWritten = mDataWritten + grow; + if (newWritten < mDataWritten) { + LOG_ALWAYS_FATAL("buffer overflowed; data written %" PRIu32 + ", growing by %" PRIu32, mDataWritten, grow); + } + + if (newWritten <= mDataMaxSize) { + return; + } + + uint32_t newMaxSize = mDataMaxSize << 1; + if (newMaxSize < newWritten) { + newMaxSize = newWritten; + } + + auto newData = std::make_unique<uint32_t[]>(newMaxSize); + std::copy_n(mData.get(), mDataWritten, newData.get()); + mDataMaxSize = newMaxSize; + mData = std::move(newData); + } + + uint32_t mDataMaxSize; + std::unique_ptr<uint32_t[]> mData; + + uint32_t mDataWritten; + // end offset of the current command + uint32_t mCommandEnd; + + std::vector<hidl_handle> mDataHandles; + std::vector<native_handle_t *> mTemporaryHandles; + + std::unique_ptr<CommandQueueType> mQueue; +}; + +// This class helps parse a command queue. Note that all sizes/lengths are in +// units of uint32_t's. +class CommandReaderBase { +public: + CommandReaderBase() : mDataMaxSize(0) + { + reset(); + } + + bool setMQDescriptor(const MQDescriptorSync<uint32_t>& descriptor) + { + mQueue = std::make_unique<CommandQueueType>(descriptor, false); + if (mQueue->isValid()) { + return true; + } else { + mQueue = nullptr; + return false; + } + } + + bool readQueue(uint32_t commandLength, + const hidl_vec<hidl_handle>& commandHandles) + { + if (!mQueue) { + return false; + } + + auto quantumCount = mQueue->getQuantumCount(); + if (mDataMaxSize < quantumCount) { + mDataMaxSize = quantumCount; + mData = std::make_unique<uint32_t[]>(mDataMaxSize); + } + + if (commandLength > mDataMaxSize || + !mQueue->read(mData.get(), commandLength)) { + ALOGE("failed to read commands from message queue"); + return false; + } + + mDataSize = commandLength; + mDataRead = 0; + mCommandBegin = 0; + mCommandEnd = 0; + mDataHandles.setToExternal( + const_cast<hidl_handle*>(commandHandles.data()), + commandHandles.size()); + + return true; + } + + void reset() + { + mDataSize = 0; + mDataRead = 0; + mCommandBegin = 0; + mCommandEnd = 0; + mDataHandles.setToExternal(nullptr, 0); + } + +protected: + bool isEmpty() const + { + return (mDataRead >= mDataSize); + } + + bool beginCommand(IComposerClient::Command* outCommand, + uint16_t* outLength) + { + if (mCommandEnd) { + LOG_FATAL("endCommand was not called for last command"); + } + + constexpr uint32_t opcode_mask = + static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK); + constexpr uint32_t length_mask = + static_cast<uint32_t>(IComposerClient::Command::LENGTH_MASK); + + uint32_t val = read(); + *outCommand = static_cast<IComposerClient::Command>( + val & opcode_mask); + *outLength = static_cast<uint16_t>(val & length_mask); + + if (mDataRead + *outLength > mDataSize) { + ALOGE("command 0x%x has invalid command length %" PRIu16, + *outCommand, *outLength); + // undo the read() above + mDataRead--; + return false; + } + + mCommandEnd = mDataRead + *outLength; + + return true; + } + + void endCommand() + { + if (!mCommandEnd) { + LOG_FATAL("beginCommand was not called"); + } else if (mDataRead > mCommandEnd) { + LOG_FATAL("too much data read"); + mDataRead = mCommandEnd; + } else if (mDataRead < mCommandEnd) { + LOG_FATAL("too little data read"); + mDataRead = mCommandEnd; + } + + mCommandBegin = mCommandEnd; + mCommandEnd = 0; + } + + uint32_t getCommandLoc() const + { + return mCommandBegin; + } + + uint32_t read() + { + return mData[mDataRead++]; + } + + int32_t readSigned() + { + int32_t val; + memcpy(&val, &mData[mDataRead++], sizeof(val)); + return val; + } + + float readFloat() + { + float val; + memcpy(&val, &mData[mDataRead++], sizeof(val)); + return val; + } + + uint64_t read64() + { + uint32_t lo = read(); + uint32_t hi = read(); + return (static_cast<uint64_t>(hi) << 32) | lo; + } + + IComposerClient::Color readColor() + { + uint32_t val = read(); + return IComposerClient::Color{ + static_cast<uint8_t>((val >> 0) & 0xff), + static_cast<uint8_t>((val >> 8) & 0xff), + static_cast<uint8_t>((val >> 16) & 0xff), + static_cast<uint8_t>((val >> 24) & 0xff), + }; + } + + // ownership of handle is not transferred + const native_handle_t* readHandle(bool* outUseCache) + { + const native_handle_t* handle = nullptr; + + int32_t index = readSigned(); + switch (index) { + case static_cast<int32_t>(IComposerClient::HandleIndex::EMPTY): + *outUseCache = false; + break; + case static_cast<int32_t>(IComposerClient::HandleIndex::CACHED): + *outUseCache = true; + break; + default: + if (static_cast<size_t>(index) < mDataHandles.size()) { + handle = mDataHandles[index].getNativeHandle(); + } else { + ALOGE("invalid handle index %zu", static_cast<size_t>(index)); + } + *outUseCache = false; + break; + } + + return handle; + } + + const native_handle_t* readHandle() + { + bool useCache; + return readHandle(&useCache); + } + + // ownership of fence is transferred + int readFence() + { + auto handle = readHandle(); + if (!handle || handle->numFds == 0) { + return -1; + } + + if (handle->numFds != 1) { + ALOGE("invalid fence handle with %d fds", handle->numFds); + return -1; + } + + int fd = dup(handle->data[0]); + if (fd < 0) { + ALOGW("failed to dup fence %d", handle->data[0]); + sync_wait(handle->data[0], -1); + fd = -1; + } + + return fd; + } + +private: + std::unique_ptr<CommandQueueType> mQueue; + uint32_t mDataMaxSize; + std::unique_ptr<uint32_t[]> mData; + + uint32_t mDataSize; + uint32_t mDataRead; + + // begin/end offsets of the current command + uint32_t mCommandBegin; + uint32_t mCommandEnd; + + hidl_vec<hidl_handle> mDataHandles; +}; + +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
diff --git a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc new file mode 100644 index 0000000..4f01bd9 --- /dev/null +++ b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
@@ -0,0 +1,6 @@ +service hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service + class hal + user system + group graphics drmrpc readproc + capabilities SYS_NICE + onrestart restart surfaceflinger
diff --git a/graphics/composer/2.1/default/service.cpp b/graphics/composer/2.1/default/service.cpp new file mode 100644 index 0000000..712dac1 --- /dev/null +++ b/graphics/composer/2.1/default/service.cpp
@@ -0,0 +1,43 @@ +/* + * Copyright 2016 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. + */ + +#define LOG_TAG "android.hardware.graphics.composer@2.1-service" + +#include <sched.h> + +#include <android/hardware/graphics/composer/2.1/IComposer.h> + +#include <binder/ProcessState.h> +#include <hidl/LegacySupport.h> + +using android::hardware::graphics::composer::V2_1::IComposer; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + // the conventional HAL might start binder services + android::ProcessState::self()->setThreadPoolMaxThreadCount(4); + android::ProcessState::self()->startThreadPool(); + + // same as SF main thread + struct sched_param param = {0}; + param.sched_priority = 2; + if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, + ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO: %d", errno); + } + + return defaultPassthroughServiceImplementation<IComposer>(); +}
diff --git a/graphics/composer/2.1/types.hal b/graphics/composer/2.1/types.hal new file mode 100644 index 0000000..e54031e --- /dev/null +++ b/graphics/composer/2.1/types.hal
@@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016 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.graphics.composer@2.1; + +/* Return codes from all functions. */ +enum Error : int32_t { + NONE = 0, /* no error */ + BAD_CONFIG = 1, /* invalid Config */ + BAD_DISPLAY = 2, /* invalid Display */ + BAD_LAYER = 3, /* invalid Layer */ + BAD_PARAMETER = 4, /* invalid width, height, etc. */ + /* 5 is reserved */ + NO_RESOURCES = 6, /* temporary failure due to resource contention */ + NOT_VALIDATED = 7, /* validateDisplay has not been called */ + UNSUPPORTED = 8, /* permanent failure */ +}; + +typedef uint32_t Config; +typedef uint64_t Display; +typedef uint64_t Layer;
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp new file mode 100644 index 0000000..8e1f925 --- /dev/null +++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -0,0 +1,67 @@ +// +// Copyright (C) 2016 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. +// + +cc_library_static { + name: "libVtsHalGraphicsComposerTestUtils", + defaults: ["hidl_defaults"], + srcs: ["VtsHalGraphicsComposerTestUtils.cpp"], + shared_libs: ["android.hardware.graphics.composer@2.1"], + static_libs: [ + "VtsHalHidlTargetTestBase", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-O0", + "-g", + ], + export_include_dirs: ["."], +} + +cc_test { + name: "VtsHalGraphicsComposerV2_1TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"], + shared_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.mapper@2.0", + "libbase", + "libcutils", + "libfmq", + "libhidlbase", + "libhidltransport", + "liblog", + "libnativehelper", + "libsync", + "libutils", + ], + static_libs: [ + "libhwcomposer-command-buffer", + "libVtsHalGraphicsAllocatorTestUtils", + "libVtsHalGraphicsComposerTestUtils", + "libVtsHalGraphicsMapperTestUtils", + "VtsHalHidlTargetTestBase", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-O0", + "-g", + ] +}
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp new file mode 100644 index 0000000..33cf84c --- /dev/null +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
@@ -0,0 +1,300 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <VtsHalHidlTargetTestBase.h> + +#include "VtsHalGraphicsComposerTestUtils.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace tests { + +Composer::Composer() { init(); } + +void Composer::init() { + mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>(); + ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service"; + + std::vector<IComposer::Capability> capabilities = getCapabilities(); + mCapabilities.insert(capabilities.begin(), capabilities.end()); +} + +sp<IComposer> Composer::getRaw() const { return mComposer; } + +bool Composer::hasCapability(IComposer::Capability capability) const { + return mCapabilities.count(capability) > 0; +} + +std::vector<IComposer::Capability> Composer::getCapabilities() { + std::vector<IComposer::Capability> capabilities; + mComposer->getCapabilities( + [&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; }); + + return capabilities; +} + +std::string Composer::dumpDebugInfo() { + std::string debugInfo; + mComposer->dumpDebugInfo( + [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); }); + + return debugInfo; +} + +std::unique_ptr<ComposerClient> Composer::createClient() { + std::unique_ptr<ComposerClient> client; + mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to create client"; + client = std::make_unique<ComposerClient>(tmpClient); + }); + + return client; +} + +ComposerClient::ComposerClient(const sp<IComposerClient>& client) + : mClient(client) {} + +ComposerClient::~ComposerClient() { + for (auto it : mDisplayResources) { + Display display = it.first; + DisplayResource& resource = it.second; + + for (auto layer : resource.layers) { + EXPECT_EQ(Error::NONE, mClient->destroyLayer(display, layer)) + << "failed to destroy layer " << layer; + } + + if (resource.isVirtual) { + EXPECT_EQ(Error::NONE, mClient->destroyVirtualDisplay(display)) + << "failed to destroy virtual display " << display; + } + } + mDisplayResources.clear(); +} + +sp<IComposerClient> ComposerClient::getRaw() const { return mClient; } + +void ComposerClient::registerCallback(const sp<IComposerCallback>& callback) { + mClient->registerCallback(callback); +} + +uint32_t ComposerClient::getMaxVirtualDisplayCount() { + return mClient->getMaxVirtualDisplayCount(); +} + +Display ComposerClient::createVirtualDisplay(uint32_t width, uint32_t height, + PixelFormat formatHint, + uint32_t outputBufferSlotCount, + PixelFormat* outFormat) { + Display display = 0; + mClient->createVirtualDisplay( + width, height, formatHint, outputBufferSlotCount, + [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to create virtual display"; + display = tmpDisplay; + *outFormat = tmpFormat; + + ASSERT_TRUE( + mDisplayResources.insert({display, DisplayResource(true)}).second) + << "duplicated virtual display id " << display; + }); + + return display; +} + +void ComposerClient::destroyVirtualDisplay(Display display) { + Error error = mClient->destroyVirtualDisplay(display); + ASSERT_EQ(Error::NONE, error) + << "failed to destroy virtual display " << display; + + mDisplayResources.erase(display); +} + +Layer ComposerClient::createLayer(Display display, uint32_t bufferSlotCount) { + Layer layer = 0; + mClient->createLayer( + display, bufferSlotCount, + [&](const auto& tmpError, const auto& tmpLayer) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to create layer"; + layer = tmpLayer; + + auto resourceIt = mDisplayResources.find(display); + if (resourceIt == mDisplayResources.end()) { + resourceIt = + mDisplayResources.insert({display, DisplayResource(false)}).first; + } + + ASSERT_TRUE(resourceIt->second.layers.insert(layer).second) + << "duplicated layer id " << layer; + }); + + return layer; +} + +void ComposerClient::destroyLayer(Display display, Layer layer) { + Error error = mClient->destroyLayer(display, layer); + ASSERT_EQ(Error::NONE, error) << "failed to destroy layer " << layer; + + auto resourceIt = mDisplayResources.find(display); + ASSERT_NE(mDisplayResources.end(), resourceIt); + resourceIt->second.layers.erase(layer); +} + +Config ComposerClient::getActiveConfig(Display display) { + Config config = 0; + mClient->getActiveConfig( + display, [&](const auto& tmpError, const auto& tmpConfig) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get active config"; + config = tmpConfig; + }); + + return config; +} + +bool ComposerClient::getClientTargetSupport(Display display, uint32_t width, + uint32_t height, PixelFormat format, + Dataspace dataspace) { + Error error = mClient->getClientTargetSupport(display, width, height, format, + dataspace); + return error == Error::NONE; +} + +std::vector<ColorMode> ComposerClient::getColorModes(Display display) { + std::vector<ColorMode> modes; + mClient->getColorModes( + display, [&](const auto& tmpError, const auto& tmpMode) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get color mode"; + modes = tmpMode; + }); + + return modes; +} + +int32_t ComposerClient::getDisplayAttribute( + Display display, Config config, IComposerClient::Attribute attribute) { + int32_t value = 0; + mClient->getDisplayAttribute(display, config, attribute, + [&](const auto& tmpError, const auto& tmpValue) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to get display attribute"; + value = tmpValue; + }); + + return value; +} + +std::vector<Config> ComposerClient::getDisplayConfigs(Display display) { + std::vector<Config> configs; + mClient->getDisplayConfigs( + display, [&](const auto& tmpError, const auto& tmpConfigs) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get display configs"; + configs = tmpConfigs; + }); + + return configs; +} + +std::string ComposerClient::getDisplayName(Display display) { + std::string name; + mClient->getDisplayName( + display, [&](const auto& tmpError, const auto& tmpName) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get display name"; + name = tmpName.c_str(); + }); + + return name; +} + +IComposerClient::DisplayType ComposerClient::getDisplayType(Display display) { + IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID; + mClient->getDisplayType( + display, [&](const auto& tmpError, const auto& tmpType) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get display type"; + type = tmpType; + }); + + return type; +} + +bool ComposerClient::getDozeSupport(Display display) { + bool support = false; + mClient->getDozeSupport( + display, [&](const auto& tmpError, const auto& tmpSupport) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get doze support"; + support = tmpSupport; + }); + + return support; +} + +std::vector<Hdr> ComposerClient::getHdrCapabilities( + Display display, float* outMaxLuminance, float* outMaxAverageLuminance, + float* outMinLuminance) { + std::vector<Hdr> types; + mClient->getHdrCapabilities( + display, + [&](const auto& tmpError, const auto& tmpTypes, + const auto& tmpMaxLuminance, const auto& tmpMaxAverageLuminance, + const auto& tmpMinLuminance) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR capabilities"; + types = tmpTypes; + *outMaxLuminance = tmpMaxLuminance; + *outMaxAverageLuminance = tmpMaxAverageLuminance; + *outMinLuminance = tmpMinLuminance; + }); + + return types; +} + +void ComposerClient::setClientTargetSlotCount(Display display, + uint32_t clientTargetSlotCount) { + Error error = + mClient->setClientTargetSlotCount(display, clientTargetSlotCount); + ASSERT_EQ(Error::NONE, error) << "failed to set client target slot count"; +} + +void ComposerClient::setActiveConfig(Display display, Config config) { + Error error = mClient->setActiveConfig(display, config); + ASSERT_EQ(Error::NONE, error) << "failed to set active config"; +} + +void ComposerClient::setColorMode(Display display, ColorMode mode) { + Error error = mClient->setColorMode(display, mode); + ASSERT_EQ(Error::NONE, error) << "failed to set color mode"; +} + +void ComposerClient::setPowerMode(Display display, + IComposerClient::PowerMode mode) { + Error error = mClient->setPowerMode(display, mode); + ASSERT_EQ(Error::NONE, error) << "failed to set power mode"; +} + +void ComposerClient::setVsyncEnabled(Display display, bool enabled) { + IComposerClient::Vsync vsync = (enabled) ? IComposerClient::Vsync::ENABLE + : IComposerClient::Vsync::DISABLE; + Error error = mClient->setVsyncEnabled(display, vsync); + ASSERT_EQ(Error::NONE, error) << "failed to set vsync mode"; +} + +} // namespace tests +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h new file mode 100644 index 0000000..4b57264 --- /dev/null +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
@@ -0,0 +1,126 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef VTS_HAL_GRAPHICS_COMPOSER_UTILS +#define VTS_HAL_GRAPHICS_COMPOSER_UTILS + +#include <memory> +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +#include <android/hardware/graphics/composer/2.1/IComposer.h> +#include <utils/StrongPointer.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace tests { + +using android::hardware::graphics::common::V1_0::ColorMode; +using android::hardware::graphics::common::V1_0::Dataspace; +using android::hardware::graphics::common::V1_0::Hdr; +using android::hardware::graphics::common::V1_0::PixelFormat; + +class ComposerClient; + +// A wrapper to IComposer. +class Composer { + public: + Composer(); + + sp<IComposer> getRaw() const; + + // Returns true when the composer supports the specified capability. + bool hasCapability(IComposer::Capability capability) const; + + std::vector<IComposer::Capability> getCapabilities(); + std::string dumpDebugInfo(); + std::unique_ptr<ComposerClient> createClient(); + + private: + void init(); + + sp<IComposer> mComposer; + std::unordered_set<IComposer::Capability> mCapabilities; +}; + +// A wrapper to IComposerClient. +class ComposerClient { + public: + ComposerClient(const sp<IComposerClient>& client); + ~ComposerClient(); + + sp<IComposerClient> getRaw() const; + + void registerCallback(const sp<IComposerCallback>& callback); + uint32_t getMaxVirtualDisplayCount(); + + Display createVirtualDisplay(uint32_t width, uint32_t height, + PixelFormat formatHint, + uint32_t outputBufferSlotCount, + PixelFormat* outFormat); + void destroyVirtualDisplay(Display display); + + Layer createLayer(Display display, uint32_t bufferSlotCount); + void destroyLayer(Display display, Layer layer); + + Config getActiveConfig(Display display); + bool getClientTargetSupport(Display display, uint32_t width, uint32_t height, + PixelFormat format, Dataspace dataspace); + std::vector<ColorMode> getColorModes(Display display); + int32_t getDisplayAttribute(Display display, Config config, + IComposerClient::Attribute attribute); + std::vector<Config> getDisplayConfigs(Display display); + std::string getDisplayName(Display display); + IComposerClient::DisplayType getDisplayType(Display display); + bool getDozeSupport(Display display); + std::vector<Hdr> getHdrCapabilities(Display display, float* outMaxLuminance, + float* outMaxAverageLuminance, + float* outMinLuminance); + + void setClientTargetSlotCount(Display display, + uint32_t clientTargetSlotCount); + void setActiveConfig(Display display, Config config); + void setColorMode(Display display, ColorMode mode); + void setPowerMode(Display display, IComposerClient::PowerMode mode); + void setVsyncEnabled(Display display, bool enabled); + + private: + sp<IComposerClient> mClient; + + // Keep track of all virtual displays and layers. When a test fails with + // ASSERT_*, the destructor will clean up the resources for the test. + struct DisplayResource { + DisplayResource(bool isVirtual_) : isVirtual(isVirtual_) {} + + bool isVirtual; + std::unordered_set<Layer> layers; + }; + std::unordered_map<Display, DisplayResource> mDisplayResources; +}; + +} // namespace tests +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // VTS_HAL_GRAPHICS_COMPOSER_UTILS
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp new file mode 100644 index 0000000..0da3a33 --- /dev/null +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -0,0 +1,845 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "graphics_composer_hidl_hal_test" + +#include <IComposerCommandBuffer.h> +#include <android-base/logging.h> +#include "VtsHalGraphicsAllocatorTestUtils.h" +#include "VtsHalGraphicsComposerTestUtils.h" +#include "VtsHalGraphicsMapperTestUtils.h" + +#include <VtsHalHidlTargetTestBase.h> +#include <unistd.h> + +#include <algorithm> +#include <array> +#include <memory> +#include <mutex> +#include <unordered_set> +#include <vector> + +namespace android { +namespace hardware { +namespace graphics { +namespace composer { +namespace V2_1 { +namespace tests { +namespace { + +using android::hardware::graphics::allocator::V2_0::Buffer; +using android::hardware::graphics::allocator::V2_0::BufferDescriptor; +using android::hardware::graphics::allocator::V2_0::ConsumerUsage; +using android::hardware::graphics::allocator::V2_0::IAllocator; +using android::hardware::graphics::allocator::V2_0::IAllocatorClient; +using android::hardware::graphics::allocator::V2_0::ProducerUsage; +using android::hardware::graphics::allocator::V2_0::tests::Allocator; +using android::hardware::graphics::allocator::V2_0::tests::AllocatorClient; +using android::hardware::graphics::common::V1_0::ColorMode; +using android::hardware::graphics::common::V1_0::ColorTransform; +using android::hardware::graphics::common::V1_0::Dataspace; +using android::hardware::graphics::common::V1_0::PixelFormat; +using android::hardware::graphics::common::V1_0::Transform; +using android::hardware::graphics::mapper::V2_0::IMapper; +using android::hardware::graphics::mapper::V2_0::tests::Mapper; +using GrallocError = android::hardware::graphics::allocator::V2_0::Error; + +// IComposerCallback to be installed with IComposerClient::registerCallback. +class GraphicsComposerCallback : public IComposerCallback { + public: + void setVsyncAllowed(bool allowed) { + std::lock_guard<std::mutex> lock(mMutex); + mVsyncAllowed = allowed; + } + + std::vector<Display> getDisplays() const { + std::lock_guard<std::mutex> lock(mMutex); + return std::vector<Display>(mDisplays.begin(), mDisplays.end()); + } + + int getInvalidHotplugCount() const { + std::lock_guard<std::mutex> lock(mMutex); + return mInvalidHotplugCount; + } + + int getInvalidRefreshCount() const { + std::lock_guard<std::mutex> lock(mMutex); + return mInvalidRefreshCount; + } + + int getInvalidVsyncCount() const { + std::lock_guard<std::mutex> lock(mMutex); + return mInvalidVsyncCount; + } + + private: + Return<void> onHotplug(Display display, Connection connection) override { + std::lock_guard<std::mutex> lock(mMutex); + + if (connection == Connection::CONNECTED) { + if (!mDisplays.insert(display).second) { + mInvalidHotplugCount++; + } + } else if (connection == Connection::DISCONNECTED) { + if (!mDisplays.erase(display)) { + mInvalidHotplugCount++; + } + } + + return Void(); + } + + Return<void> onRefresh(Display display) override { + std::lock_guard<std::mutex> lock(mMutex); + + if (mDisplays.count(display) == 0) { + mInvalidRefreshCount++; + } + + return Void(); + } + + Return<void> onVsync(Display display, int64_t) override { + std::lock_guard<std::mutex> lock(mMutex); + + if (!mVsyncAllowed || mDisplays.count(display) == 0) { + mInvalidVsyncCount++; + } + + return Void(); + } + + mutable std::mutex mMutex; + // the set of all currently connected displays + std::unordered_set<Display> mDisplays; + // true only when vsync is enabled + bool mVsyncAllowed = false; + + // track invalid callbacks + int mInvalidHotplugCount = 0; + int mInvalidRefreshCount = 0; + int mInvalidVsyncCount = 0; +}; + +class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(mComposer = std::make_unique<Composer>()); + ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); + + mComposerCallback = new GraphicsComposerCallback; + mComposerClient->registerCallback(mComposerCallback); + + // assume the first display is primary and is never removed + mPrimaryDisplay = waitForFirstDisplay(); + } + + void TearDown() override { + if (mComposerCallback != nullptr) { + EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); + } + } + + // use the slot count usually set by SF + static constexpr uint32_t kBufferSlotCount = 64; + + std::unique_ptr<Composer> mComposer; + std::unique_ptr<ComposerClient> mComposerClient; + sp<GraphicsComposerCallback> mComposerCallback; + // the first display and is assumed never to be removed + Display mPrimaryDisplay; + + private: + Display waitForFirstDisplay() { + while (true) { + std::vector<Display> displays = mComposerCallback->getDisplays(); + if (displays.empty()) { + usleep(5 * 1000); + continue; + } + + return displays[0]; + } + } +}; + +/** + * Test IComposer::getCapabilities. + * + * Test that IComposer::getCapabilities returns no invalid capabilities. + */ +TEST_F(GraphicsComposerHidlTest, GetCapabilities) { + auto capabilities = mComposer->getCapabilities(); + ASSERT_EQ(capabilities.end(), + std::find(capabilities.begin(), capabilities.end(), + IComposer::Capability::INVALID)); +} + +/** + * Test IComposer::dumpDebugInfo. + */ +TEST_F(GraphicsComposerHidlTest, DumpDebugInfo) { mComposer->dumpDebugInfo(); } + +/** + * Test IComposer::createClient. + * + * Test that IComposerClient is a singleton. + */ +TEST_F(GraphicsComposerHidlTest, CreateClientSingleton) { + mComposer->getRaw()->createClient([&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::NO_RESOURCES, tmpError); + }); +} + +/** + * Test IComposerClient::createVirtualDisplay and + * IComposerClient::destroyVirtualDisplay. + * + * Test that virtual displays can be created and has the correct display type. + */ +TEST_F(GraphicsComposerHidlTest, CreateVirtualDisplay) { + if (mComposerClient->getMaxVirtualDisplayCount() == 0) { + GTEST_SUCCEED() << "no virtual display support"; + return; + } + + Display display; + PixelFormat format; + ASSERT_NO_FATAL_FAILURE(display = mComposerClient->createVirtualDisplay( + 64, 64, PixelFormat::IMPLEMENTATION_DEFINED, + kBufferSlotCount, &format)); + + // test display type + IComposerClient::DisplayType type = mComposerClient->getDisplayType(display); + EXPECT_EQ(IComposerClient::DisplayType::VIRTUAL, type); + + mComposerClient->destroyVirtualDisplay(display); +} + +/** + * Test IComposerClient::createLayer and IComposerClient::destroyLayer. + * + * Test that layers can be created and destroyed. + */ +TEST_F(GraphicsComposerHidlTest, CreateLayer) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mComposerClient->destroyLayer(mPrimaryDisplay, layer); +} + +/** + * Test IComposerClient::getDisplayName. + */ +TEST_F(GraphicsComposerHidlTest, GetDisplayName) { + mComposerClient->getDisplayName(mPrimaryDisplay); +} + +/** + * Test IComposerClient::getDisplayType. + * + * Test that IComposerClient::getDisplayType returns the correct display type + * for the primary display. + */ +TEST_F(GraphicsComposerHidlTest, GetDisplayType) { + ASSERT_EQ(IComposerClient::DisplayType::PHYSICAL, + mComposerClient->getDisplayType(mPrimaryDisplay)); +} + +/** + * Test IComposerClient::getClientTargetSupport. + * + * Test that IComposerClient::getClientTargetSupport returns true for the + * required client targets. + */ +TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport) { + std::vector<Config> configs = + mComposerClient->getDisplayConfigs(mPrimaryDisplay); + for (auto config : configs) { + int32_t width = mComposerClient->getDisplayAttribute( + mPrimaryDisplay, config, IComposerClient::Attribute::WIDTH); + int32_t height = mComposerClient->getDisplayAttribute( + mPrimaryDisplay, config, IComposerClient::Attribute::HEIGHT); + ASSERT_LT(0, width); + ASSERT_LT(0, height); + + mComposerClient->setActiveConfig(mPrimaryDisplay, config); + + ASSERT_TRUE(mComposerClient->getClientTargetSupport( + mPrimaryDisplay, width, height, PixelFormat::RGBA_8888, + Dataspace::UNKNOWN)); + } +} + +/** + * Test IComposerClient::getDisplayAttribute. + * + * Test that IComposerClient::getDisplayAttribute succeeds for the required + * formats, and succeeds or fails correctly for optional attributes. + */ +TEST_F(GraphicsComposerHidlTest, GetDisplayAttribute) { + std::vector<Config> configs = + mComposerClient->getDisplayConfigs(mPrimaryDisplay); + for (auto config : configs) { + const std::array<IComposerClient::Attribute, 3> requiredAttributes = {{ + IComposerClient::Attribute::WIDTH, IComposerClient::Attribute::HEIGHT, + IComposerClient::Attribute::VSYNC_PERIOD, + }}; + for (auto attribute : requiredAttributes) { + mComposerClient->getDisplayAttribute(mPrimaryDisplay, config, attribute); + } + + const std::array<IComposerClient::Attribute, 2> optionalAttributes = {{ + IComposerClient::Attribute::DPI_X, IComposerClient::Attribute::DPI_Y, + }}; + for (auto attribute : optionalAttributes) { + mComposerClient->getRaw()->getDisplayAttribute( + mPrimaryDisplay, config, attribute, + [&](const auto& tmpError, const auto&) { + EXPECT_TRUE(tmpError == Error::NONE || + tmpError == Error::UNSUPPORTED); + }); + } + } +} + +/** + * Test IComposerClient::getHdrCapabilities. + */ +TEST_F(GraphicsComposerHidlTest, GetHdrCapabilities) { + float maxLuminance; + float maxAverageLuminance; + float minLuminance; + mComposerClient->getHdrCapabilities(mPrimaryDisplay, &maxLuminance, + &maxAverageLuminance, &minLuminance); +} + +/** + * Test IComposerClient::setClientTargetSlotCount. + */ +TEST_F(GraphicsComposerHidlTest, SetClientTargetSlotCount) { + mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount); +} + +/** + * Test IComposerClient::setActiveConfig. + * + * Test that IComposerClient::setActiveConfig succeeds for all display + * configs. + */ +TEST_F(GraphicsComposerHidlTest, SetActiveConfig) { + std::vector<Config> configs = + mComposerClient->getDisplayConfigs(mPrimaryDisplay); + for (auto config : configs) { + mComposerClient->setActiveConfig(mPrimaryDisplay, config); + ASSERT_EQ(config, mComposerClient->getActiveConfig(mPrimaryDisplay)); + } +} + +/** + * Test IComposerClient::setColorMode. + * + * Test that IComposerClient::setColorMode succeeds for all color modes. + */ +TEST_F(GraphicsComposerHidlTest, SetColorMode) { + std::vector<ColorMode> modes = + mComposerClient->getColorModes(mPrimaryDisplay); + for (auto mode : modes) { + mComposerClient->setColorMode(mPrimaryDisplay, mode); + } +} + +/** + * Test IComposerClient::setPowerMode. + * + * Test that IComposerClient::setPowerMode succeeds for all power modes. + */ +TEST_F(GraphicsComposerHidlTest, SetPowerMode) { + std::vector<IComposerClient::PowerMode> modes; + modes.push_back(IComposerClient::PowerMode::OFF); + + if (mComposerClient->getDozeSupport(mPrimaryDisplay)) { + modes.push_back(IComposerClient::PowerMode::DOZE); + modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND); + } + + // push ON last + modes.push_back(IComposerClient::PowerMode::ON); + + for (auto mode : modes) { + mComposerClient->setPowerMode(mPrimaryDisplay, mode); + } +} + +/** + * Test IComposerClient::setVsyncEnabled. + * + * Test that IComposerClient::setVsyncEnabled succeeds and there is no + * spurious vsync events. + */ +TEST_F(GraphicsComposerHidlTest, SetVsyncEnabled) { + mComposerCallback->setVsyncAllowed(true); + + mComposerClient->setVsyncEnabled(mPrimaryDisplay, true); + usleep(60 * 1000); + mComposerClient->setVsyncEnabled(mPrimaryDisplay, false); + + mComposerCallback->setVsyncAllowed(false); +} + +// Tests for IComposerClient::Command. +class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp()); + + ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>()); + ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient()); + ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique<Mapper>()); + + mWriter = std::make_unique<CommandWriterBase>(1024); + mReader = std::make_unique<CommandReader>(); + } + + void TearDown() override { + ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); + } + + const native_handle_t* allocate() { + IAllocatorClient::BufferDescriptorInfo info{}; + info.width = 64; + info.height = 64; + info.layerCount = 1; + info.format = PixelFormat::RGBA_8888; + info.producerUsageMask = static_cast<uint64_t>(ProducerUsage::CPU_WRITE); + info.consumerUsageMask = static_cast<uint64_t>(ConsumerUsage::CPU_READ); + + return mMapper->allocate(mAllocatorClient, info); + } + + void execute() { + bool queueChanged = false; + uint32_t commandLength = 0; + hidl_vec<hidl_handle> commandHandles; + ASSERT_TRUE( + mWriter->writeQueue(&queueChanged, &commandLength, &commandHandles)); + + if (queueChanged) { + auto ret = mComposerClient->getRaw()->setInputCommandQueue( + *mWriter->getMQDescriptor()); + ASSERT_EQ(Error::NONE, static_cast<Error>(ret)); + return; + } + + mComposerClient->getRaw()->executeCommands( + commandLength, commandHandles, + [&](const auto& tmpError, const auto& tmpOutQueueChanged, + const auto& tmpOutLength, const auto& tmpOutHandles) { + ASSERT_EQ(Error::NONE, tmpError); + + if (tmpOutQueueChanged) { + mComposerClient->getRaw()->getOutputCommandQueue( + [&](const auto& tmpError, const auto& tmpDescriptor) { + ASSERT_EQ(Error::NONE, tmpError); + mReader->setMQDescriptor(tmpDescriptor); + }); + } + + ASSERT_TRUE(mReader->readQueue(tmpOutLength, tmpOutHandles)); + mReader->parse(); + }); + } + + // A command parser that checks that no error nor unexpected commands are + // returned. + class CommandReader : public CommandReaderBase { + public: + // Parse all commands in the return command queue. Call GTEST_FAIL() for + // unexpected errors or commands. + void parse() { + while (!isEmpty()) { + IComposerClient::Command command; + uint16_t length; + ASSERT_TRUE(beginCommand(&command, &length)); + + switch (command) { + case IComposerClient::Command::SET_ERROR: { + ASSERT_EQ(2, length); + auto loc = read(); + auto err = readSigned(); + GTEST_FAIL() << "unexpected error " << err << " at location " + << loc; + } break; + case IComposerClient::Command::SELECT_DISPLAY: + case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES: + case IComposerClient::Command::SET_DISPLAY_REQUESTS: + case IComposerClient::Command::SET_PRESENT_FENCE: + case IComposerClient::Command::SET_RELEASE_FENCES: + break; + default: + GTEST_FAIL() << "unexpected return command " << std::hex + << static_cast<int>(command); + break; + } + + endCommand(); + } + } + }; + + std::unique_ptr<CommandWriterBase> mWriter; + std::unique_ptr<CommandReader> mReader; + + private: + std::unique_ptr<Allocator> mAllocator; + std::unique_ptr<AllocatorClient> mAllocatorClient; + std::unique_ptr<Mapper> mMapper; +}; + +/** + * Test IComposerClient::Command::SET_COLOR_TRANSFORM. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_COLOR_TRANSFORM) { + const std::array<float, 16> identity = {{ + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }}; + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->setColorTransform(identity.data(), ColorTransform::IDENTITY); + + execute(); +} + +/** + * Test IComposerClient::Command::SET_CLIENT_TARGET. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_CLIENT_TARGET) { + mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->setClientTarget(0, nullptr, -1, Dataspace::UNKNOWN, + std::vector<IComposerClient::Rect>()); + + execute(); +} + +/** + * Test IComposerClient::Command::SET_OUTPUT_BUFFER. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_OUTPUT_BUFFER) { + if (mComposerClient->getMaxVirtualDisplayCount() == 0) { + GTEST_SUCCEED() << "no virtual display support"; + return; + } + + Display display; + PixelFormat format; + ASSERT_NO_FATAL_FAILURE(display = mComposerClient->createVirtualDisplay( + 64, 64, PixelFormat::IMPLEMENTATION_DEFINED, + kBufferSlotCount, &format)); + + const native_handle_t* handle; + ASSERT_NO_FATAL_FAILURE(handle = allocate()); + + mWriter->selectDisplay(display); + mWriter->setOutputBuffer(0, handle, -1); + execute(); +} + +/** + * Test IComposerClient::Command::VALIDATE_DISPLAY. + */ +TEST_F(GraphicsComposerHidlCommandTest, VALIDATE_DISPLAY) { + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->validateDisplay(); + execute(); +} + +/** + * Test IComposerClient::Command::ACCEPT_DISPLAY_CHANGES. + */ +TEST_F(GraphicsComposerHidlCommandTest, ACCEPT_DISPLAY_CHANGES) { + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->validateDisplay(); + mWriter->acceptDisplayChanges(); + execute(); +} + +/** + * Test IComposerClient::Command::PRESENT_DISPLAY. + */ +TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY) { + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->validateDisplay(); + mWriter->presentDisplay(); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerCursorPosition(1, 1); + mWriter->setLayerCursorPosition(0, 0); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_BUFFER. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER) { + auto handle = allocate(); + ASSERT_NE(nullptr, handle); + + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerBuffer(0, handle, -1); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + IComposerClient::Rect empty{0, 0, 0, 0}; + IComposerClient::Rect unit{0, 0, 1, 1}; + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, empty)); + mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, unit)); + mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>()); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_BLEND_MODE. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_BLEND_MODE) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE); + mWriter->setLayerBlendMode(IComposerClient::BlendMode::PREMULTIPLIED); + mWriter->setLayerBlendMode(IComposerClient::BlendMode::COVERAGE); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_COLOR. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COLOR) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerColor(IComposerClient::Color{0xff, 0xff, 0xff, 0xff}); + mWriter->setLayerColor(IComposerClient::Color{0, 0, 0, 0}); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_COMPOSITION_TYPE) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerCompositionType(IComposerClient::Composition::CLIENT); + mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE); + mWriter->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR); + mWriter->setLayerCompositionType(IComposerClient::Composition::CURSOR); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_DATASPACE. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DATASPACE) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerDataspace(Dataspace::UNKNOWN); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_DISPLAY_FRAME. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_DISPLAY_FRAME) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerDisplayFrame(IComposerClient::Rect{0, 0, 1, 1}); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_PLANE_ALPHA. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_PLANE_ALPHA) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerPlaneAlpha(0.0f); + mWriter->setLayerPlaneAlpha(1.0f); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SIDEBAND_STREAM) { + if (!mComposer->hasCapability(IComposer::Capability::SIDEBAND_STREAM)) { + GTEST_SUCCEED() << "no sideband stream support"; + return; + } + + auto handle = allocate(); + ASSERT_NE(nullptr, handle); + + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerSidebandStream(handle); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_SOURCE_CROP. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_SOURCE_CROP) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerSourceCrop(IComposerClient::FRect{0.0f, 0.0f, 1.0f, 1.0f}); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_TRANSFORM. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_TRANSFORM) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerTransform(static_cast<Transform>(0)); + mWriter->setLayerTransform(Transform::FLIP_H); + mWriter->setLayerTransform(Transform::FLIP_V); + mWriter->setLayerTransform(Transform::ROT_90); + mWriter->setLayerTransform(Transform::ROT_180); + mWriter->setLayerTransform(Transform::ROT_270); + mWriter->setLayerTransform( + static_cast<Transform>(Transform::FLIP_H | Transform::ROT_90)); + mWriter->setLayerTransform( + static_cast<Transform>(Transform::FLIP_V | Transform::ROT_90)); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_VISIBLE_REGION. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_VISIBLE_REGION) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + IComposerClient::Rect empty{0, 0, 0, 0}; + IComposerClient::Rect unit{0, 0, 1, 1}; + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, empty)); + mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, unit)); + mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>()); + execute(); +} + +/** + * Test IComposerClient::Command::SET_LAYER_Z_ORDER. + */ +TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_Z_ORDER) { + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + + mWriter->selectDisplay(mPrimaryDisplay); + mWriter->selectLayer(layer); + mWriter->setLayerZOrder(10); + mWriter->setLayerZOrder(0); + execute(); +} + +} // namespace anonymous +} // namespace tests +} // namespace V2_1 +} // namespace composer +} // namespace graphics +} // namespace hardware +} // namespace android + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + + return status; +}
diff --git a/graphics/composer/Android.mk b/graphics/composer/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/graphics/composer/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/graphics/mapper/2.0/Android.bp b/graphics/mapper/2.0/Android.bp new file mode 100644 index 0000000..b835b4a --- /dev/null +++ b/graphics/mapper/2.0/Android.bp
@@ -0,0 +1,66 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.graphics.mapper@2.0_hal", + srcs: [ + "types.hal", + "IMapper.hal", + ], +} + +genrule { + name: "android.hardware.graphics.mapper@2.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.mapper@2.0", + srcs: [ + ":android.hardware.graphics.mapper@2.0_hal", + ], + out: [ + "android/hardware/graphics/mapper/2.0/types.cpp", + "android/hardware/graphics/mapper/2.0/MapperAll.cpp", + ], +} + +genrule { + name: "android.hardware.graphics.mapper@2.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.graphics.mapper@2.0", + srcs: [ + ":android.hardware.graphics.mapper@2.0_hal", + ], + out: [ + "android/hardware/graphics/mapper/2.0/types.h", + "android/hardware/graphics/mapper/2.0/IMapper.h", + "android/hardware/graphics/mapper/2.0/IHwMapper.h", + "android/hardware/graphics/mapper/2.0/BnHwMapper.h", + "android/hardware/graphics/mapper/2.0/BpHwMapper.h", + "android/hardware/graphics/mapper/2.0/BsMapper.h", + ], +} + +cc_library_shared { + name: "android.hardware.graphics.mapper@2.0", + generated_sources: ["android.hardware.graphics.mapper@2.0_genc++"], + generated_headers: ["android.hardware.graphics.mapper@2.0_genc++_headers"], + export_generated_headers: ["android.hardware.graphics.mapper@2.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.common@1.0", + "android.hidl.base@1.0", + ], +}
diff --git a/graphics/mapper/2.0/Android.mk b/graphics/mapper/2.0/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/graphics/mapper/2.0/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/graphics/mapper/2.0/IMapper.hal b/graphics/mapper/2.0/IMapper.hal new file mode 100644 index 0000000..21a6dfa --- /dev/null +++ b/graphics/mapper/2.0/IMapper.hal
@@ -0,0 +1,323 @@ +/* + * Copyright (C) 2016 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.graphics.mapper@2.0; + +import android.hardware.graphics.common@1.0::PixelFormat; +import android.hardware.graphics.allocator@2.0; + +interface IMapper { + struct Rect { + int32_t left; + int32_t top; + int32_t width; + int32_t height; + }; + + /* + * Adds a reference to the given buffer handle. + * + * A buffer handle received from a remote process or exported by + * IAllocator::exportHandle is unknown to the mapper. There is also no + * guarantee that the buffer's backing store will stay alive. This + * function must be called at least once in both cases to intrdouce the + * buffer handle to the mapper and to secure the backing store. It may + * also be called more than once to increase the reference count if two + * components in the same process want to interact with the buffer + * independently. + * + * @param bufferHandle is the buffer to which a reference must be added. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid + * NO_RESOURCES when it is not possible to add a + * reference to this buffer at this time + */ + @entry + @callflow(next="*") + retain(handle bufferHandle) generates (Error error); + + /* + * Removes a reference from the given buffer buffer. + * + * If no references remain, the buffer handle must be freed with + * native_handle_close/native_handle_delete by the mapper. When the last + * buffer handle referring to a particular backing store is freed, that + * backing store must also be freed. + * + * @param bufferHandle is the buffer from which a reference must be + * removed. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + */ + @exit + release(handle bufferHandle) generates (Error error); + + /* + * Gets the width and height of the buffer in pixels. + * + * See IAllocator::BufferDescriptorInfo for more information. + * + * @param bufferHandle is the buffer from which to get the dimensions. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * @return width is the width of the buffer in pixels. + * @return height is the height of the buffer in pixels. + */ + @callflow(next="*") + getDimensions(handle bufferHandle) + generates (Error error, + uint32_t width, + uint32_t height); + + /* + * Gets the format of the buffer. + * + * See IAllocator::BufferDescriptorInfo for more information. + * + * @param bufferHandle is the buffer from which to get format. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * @return format is the format of the buffer. + */ + @callflow(next="*") + getFormat(handle bufferHandle) + generates (Error error, + PixelFormat format); + + /* + * Gets the number of layers of the buffer. + * + * See IAllocator::BufferDescriptorInfo for more information. + * + * @param bufferHandle is the buffer from which to get format. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * @return layerCount is the number of layers of the buffer. + */ + @callflow(next="*") + getLayerCount(handle bufferHandle) + generates (Error error, + uint32_t layerCount); + + /* + * Gets the producer usage flags which were used to allocate this buffer. + * + * See IAllocator::BufferDescriptorInfo for more information. + * + * @param bufferHandle is the buffer from which to get the producer usage + * flags. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * @return usageMask contains the producer usage flags of the buffer. + */ + @callflow(next="*") + getProducerUsageMask(handle bufferHandle) + generates (Error error, + uint64_t usageMask); + + /* + * Gets the consumer usage flags which were used to allocate this buffer. + * + * See IAllocator::BufferDescriptorInfo for more information. + * + * @param bufferHandle is the buffer from which to get the consumer usage + * flags. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * @return usageMask contains the consumer usage flags of the buffer. + */ + @callflow(next="*") + getConsumerUsageMask(handle bufferHandle) + generates (Error error, + uint64_t usageMask); + + /* + * Gets a value that uniquely identifies the backing store of the given + * buffer. + * + * Buffers which share a backing store should return the same value from + * this function. If the buffer is present in more than one process, the + * backing store value for that buffer is not required to be the same in + * every process. + * + * @param device is the mapper device. + * @param bufferHandle is the buffer from which to get the backing store + * identifier. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * @return store is the backing store identifier for this buffer. + */ + @callflow(next="*") + getBackingStore(handle bufferHandle) + generates (Error error, + BackingStore store); + + /* + * Gets the stride of the buffer in pixels. + * + * The stride is the offset in pixel-sized elements between the same + * column in two adjacent rows of pixels. This may not be equal to the + * width of the buffer. + * + * @param device is the mapper device. + * @param bufferHandle is the buffer from which to get the stride. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * UNDEFINED when the notion of a stride is not + * meaningful for the buffer format. + * @return store is the stride in pixels. + */ + @callflow(next="*") + getStride(handle bufferHandle) + generates (Error error, + uint32_t stride); + + /* + * Locks the given buffer for the specified CPU usage. + * + * Exactly one of producerUsageMask and consumerUsageMask must be 0. The + * usage which is not 0 must be one of the *Usage::CPU* values, as + * applicable. Locking a buffer for a non-CPU usage is not supported. + * + * Locking the same buffer simultaneously from multiple threads is + * permitted, but if any of the threads attempt to lock the buffer for + * writing, the behavior is undefined, except that it must not cause + * process termination or block the client indefinitely. Leaving the + * buffer content in an indeterminate state or returning an error are both + * acceptable. + * + * The client must not modify the content of the buffer outside of + * accessRegion, and the device need not guarantee that content outside of + * accessRegion is valid for reading. The result of reading or writing + * outside of accessRegion is undefined, except that it must not cause + * process termination. + * + * data will be filled with a pointer to the locked buffer memory. This + * address will represent the top-left corner of the entire buffer, even + * if accessRegion does not begin at the top-left corner. + * + * acquireFence is a file descriptor referring to a acquire sync fence + * object, which will be signaled when it is safe for the device to access + * the contents of the buffer (prior to locking). If it is already safe to + * access the buffer contents, -1 may be passed instead. + * + * @param bufferHandle is the buffer to lock. + * @param producerUsageMask contains the producer usage flags to request; + * either this or consumerUsagemask must be 0, and the other must + * be a CPU usage. + * @param consumerUsageMask contains the consumer usage flags to request; + * either this or producerUsageMask must be 0, and the other must + * be a CPU usage. + * @param accessRegion is the portion of the buffer that the client + * intends to access. + * @param acquireFence is a sync fence file descriptor as described above. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * BAD_VALUE when neither or both of producerUsageMask + * and consumerUsageMask were 0, or the usage + * which was not 0 was not a CPU usage. + * NO_RESOURCES when the buffer cannot be locked at this + * time, but locking may succeed at a future + * time. + * UNSUPPORTED when the buffer cannot be locked with the + * given usage, and any future attempts at + * locking will also fail. + * @return data will be filled with a CPU-accessible pointer to the buffer + * data. + */ + @callflow(next="unlock") + lock(handle bufferHandle, + uint64_t producerUsageMask, + uint64_t consumerUsageMask, + Rect accessRegion, + handle acquireFence) + generates (Error error, + pointer data); + + /* + * This is largely the same as lock(), except that instead of returning a + * pointer directly to the buffer data, it returns an FlexLayout struct + * describing how to access the data planes. + * + * This function must work on buffers with PixelFormat::YCbCr_*_888 if + * supported by the device, as well as with any other formats requested by + * multimedia codecs when they are configured with a + * flexible-YUV-compatible color format. + * + * This function may also be called on buffers of other formats, including + * non-YUV formats, but if the buffer format is not compatible with a + * flexible representation, it may return UNSUPPORTED. + * + * @param device is the mapper device. + * @param bufferHandle is the buffer to lock. + * @param producerUsageMask contains the producer usage flags to request; + * either this or consumerUsagemask must be 0, and the other must + * be a CPU usage. + * @param consumerUsageMask contains the consumer usage flags to request; + * either this or producerUsageMask must be 0, and the other must + * be a CPU usage. + * @param accessRegion is the portion of the buffer that the client + * intends to access. + * @param acquireFence is a sync fence file descriptor as described in + * lock(). + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * BAD_VALUE when neither or both of producerUsageMask + * and consumerUsageMask were 0, or the usage + * which was not 0 was not a CPU usage. + * NO_RESOURCES when the buffer cannot be locked at this + * time, but locking may succeed at a future + * time. + * UNSUPPORTED when the buffer cannot be locked with the + * given usage, and any future attempts at + * locking will also fail. + * @return flexLayout will be filled with the description of the planes in + * the buffer. + */ + @callflow(next="unlock") + lockFlex(handle bufferHandle, + uint64_t producerUsageMask, + uint64_t consumerUsageMask, + Rect accessRegion, + handle acquireFence) + generates (Error error, + FlexLayout layout); + + /* + * This function indicates to the device that the client will be done with + * the buffer when releaseFence signals. + * + * releaseFence will be filled with a file descriptor referring to a + * release sync fence object, which will be signaled when it is safe to + * access the contents of the buffer (after the buffer has been unlocked). + * If it is already safe to access the buffer contents, then -1 may be + * returned instead. + * + * This function is used to unlock both buffers locked by lock() and those + * locked by lockFlex(). + * + * @param device is the mapper device. + * @param bufferHandle is the buffer to unlock. + * @return error is NONE upon success. Otherwise, + * BAD_BUFFER when the buffer handle is invalid. + * @return releaseFence is a sync fence file descriptor as described + * above. + */ + @callflow(next="*") + unlock(handle bufferHandle) + generates (Error error, + handle releaseFence); +};
diff --git a/graphics/mapper/2.0/default/Android.bp b/graphics/mapper/2.0/default/Android.bp new file mode 100644 index 0000000..1dc5aea --- /dev/null +++ b/graphics/mapper/2.0/default/Android.bp
@@ -0,0 +1,34 @@ +// +// Copyright (C) 2016 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. + +cc_library_shared { + name: "android.hardware.graphics.mapper@2.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["GrallocMapper.cpp"], + cppflags: ["-Wall", "-Wextra"], + shared_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.mapper@2.0", + "libbase", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + ], +}
diff --git a/graphics/mapper/2.0/default/GrallocMapper.cpp b/graphics/mapper/2.0/default/GrallocMapper.cpp new file mode 100644 index 0000000..526aca2 --- /dev/null +++ b/graphics/mapper/2.0/default/GrallocMapper.cpp
@@ -0,0 +1,426 @@ +/* + * Copyright 2016 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. + */ + +#define LOG_TAG "GrallocMapperPassthrough" + +#include "GrallocMapper.h" + +#include <mutex> +#include <vector> +#include <unordered_map> + +#include <string.h> + +#include <hardware/gralloc1.h> +#include <log/log.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V2_0 { +namespace implementation { + +namespace { + +using android::hardware::graphics::allocator::V2_0::Error; +using android::hardware::graphics::common::V1_0::PixelFormat; + +class GrallocMapperHal : public IMapper { +public: + GrallocMapperHal(const hw_module_t* module); + ~GrallocMapperHal(); + + // IMapper interface + Return<Error> retain(const hidl_handle& bufferHandle) override; + Return<Error> release(const hidl_handle& bufferHandle) override; + Return<void> getDimensions(const hidl_handle& bufferHandle, + getDimensions_cb hidl_cb) override; + Return<void> getFormat(const hidl_handle& bufferHandle, + getFormat_cb hidl_cb) override; + Return<void> getLayerCount(const hidl_handle& bufferHandle, + getLayerCount_cb hidl_cb) override; + Return<void> getProducerUsageMask(const hidl_handle& bufferHandle, + getProducerUsageMask_cb hidl_cb) override; + Return<void> getConsumerUsageMask(const hidl_handle& bufferHandle, + getConsumerUsageMask_cb hidl_cb) override; + Return<void> getBackingStore(const hidl_handle& bufferHandle, + getBackingStore_cb hidl_cb) override; + Return<void> getStride(const hidl_handle& bufferHandle, + getStride_cb hidl_cb) override; + Return<void> lock(const hidl_handle& bufferHandle, + uint64_t producerUsageMask, uint64_t consumerUsageMask, + const IMapper::Rect& accessRegion, const hidl_handle& acquireFence, + lock_cb hidl_cb) override; + Return<void> lockFlex(const hidl_handle& bufferHandle, + uint64_t producerUsageMask, uint64_t consumerUsageMask, + const IMapper::Rect& accessRegion, const hidl_handle& acquireFence, + lockFlex_cb hidl_cb) override; + Return<void> unlock(const hidl_handle& bufferHandle, + unlock_cb hidl_cb) override; + +private: + void initCapabilities(); + + template<typename T> + void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn); + void initDispatch(); + + static gralloc1_rect_t asGralloc1Rect(const IMapper::Rect& rect); + static bool dupFence(const hidl_handle& fenceHandle, int* outFd); + + gralloc1_device_t* mDevice; + + struct { + bool layeredBuffers; + } mCapabilities; + + struct { + GRALLOC1_PFN_RETAIN retain; + GRALLOC1_PFN_RELEASE release; + GRALLOC1_PFN_GET_DIMENSIONS getDimensions; + GRALLOC1_PFN_GET_FORMAT getFormat; + GRALLOC1_PFN_GET_LAYER_COUNT getLayerCount; + GRALLOC1_PFN_GET_PRODUCER_USAGE getProducerUsage; + GRALLOC1_PFN_GET_CONSUMER_USAGE getConsumerUsage; + GRALLOC1_PFN_GET_BACKING_STORE getBackingStore; + GRALLOC1_PFN_GET_STRIDE getStride; + GRALLOC1_PFN_GET_NUM_FLEX_PLANES getNumFlexPlanes; + GRALLOC1_PFN_LOCK lock; + GRALLOC1_PFN_LOCK_FLEX lockFlex; + GRALLOC1_PFN_UNLOCK unlock; + } mDispatch; + + std::mutex mMutex; + std::unordered_map<buffer_handle_t, size_t> mBufferReferenceCounts; +}; + +GrallocMapperHal::GrallocMapperHal(const hw_module_t* module) + : mDevice(nullptr), mCapabilities(), mDispatch() +{ + int status = gralloc1_open(module, &mDevice); + if (status) { + LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s", + strerror(-status)); + } + + initCapabilities(); + initDispatch(); +} + +GrallocMapperHal::~GrallocMapperHal() +{ + gralloc1_close(mDevice); +} + +void GrallocMapperHal::initCapabilities() +{ + uint32_t count = 0; + mDevice->getCapabilities(mDevice, &count, nullptr); + + std::vector<int32_t> caps(count); + mDevice->getCapabilities(mDevice, &count, caps.data()); + caps.resize(count); + + for (auto cap : caps) { + switch (cap) { + case GRALLOC1_CAPABILITY_LAYERED_BUFFERS: + mCapabilities.layeredBuffers = true; + break; + default: + break; + } + } +} + +template<typename T> +void GrallocMapperHal::initDispatch(gralloc1_function_descriptor_t desc, + T* outPfn) +{ + auto pfn = mDevice->getFunction(mDevice, desc); + if (!pfn) { + LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc); + } + + *outPfn = reinterpret_cast<T>(pfn); +} + +void GrallocMapperHal::initDispatch() +{ + initDispatch(GRALLOC1_FUNCTION_RETAIN, &mDispatch.retain); + initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release); + initDispatch(GRALLOC1_FUNCTION_GET_DIMENSIONS, &mDispatch.getDimensions); + initDispatch(GRALLOC1_FUNCTION_GET_FORMAT, &mDispatch.getFormat); + if (mCapabilities.layeredBuffers) { + initDispatch(GRALLOC1_FUNCTION_GET_LAYER_COUNT, + &mDispatch.getLayerCount); + } + initDispatch(GRALLOC1_FUNCTION_GET_PRODUCER_USAGE, + &mDispatch.getProducerUsage); + initDispatch(GRALLOC1_FUNCTION_GET_CONSUMER_USAGE, + &mDispatch.getConsumerUsage); + initDispatch(GRALLOC1_FUNCTION_GET_BACKING_STORE, + &mDispatch.getBackingStore); + initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride); + initDispatch(GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES, + &mDispatch.getNumFlexPlanes); + initDispatch(GRALLOC1_FUNCTION_LOCK, &mDispatch.lock); + initDispatch(GRALLOC1_FUNCTION_LOCK_FLEX, &mDispatch.lockFlex); + initDispatch(GRALLOC1_FUNCTION_UNLOCK, &mDispatch.unlock); +} + +gralloc1_rect_t GrallocMapperHal::asGralloc1Rect(const IMapper::Rect& rect) +{ + return gralloc1_rect_t{rect.left, rect.top, rect.width, rect.height}; +} + +bool GrallocMapperHal::dupFence(const hidl_handle& fenceHandle, int* outFd) +{ + auto handle = fenceHandle.getNativeHandle(); + if (!handle || handle->numFds == 0) { + *outFd = -1; + return true; + } + + if (handle->numFds > 1) { + ALOGE("invalid fence handle with %d fds", handle->numFds); + return false; + } + + *outFd = dup(handle->data[0]); + return (*outFd >= 0); +} + +Return<Error> GrallocMapperHal::retain(const hidl_handle& bufferHandle) +{ + int32_t err = mDispatch.retain(mDevice, bufferHandle); + if (err == GRALLOC1_ERROR_NONE) { + auto nativeHandle = bufferHandle.getNativeHandle(); + std::lock_guard<std::mutex> lock(mMutex); + + ++mBufferReferenceCounts[nativeHandle]; + } + return static_cast<Error>(err); +} + +Return<Error> GrallocMapperHal::release(const hidl_handle& bufferHandle) +{ + int32_t err = mDispatch.release(mDevice, bufferHandle); + if (err == GRALLOC1_ERROR_NONE) { + auto nativeHandle = bufferHandle.getNativeHandle(); + std::lock_guard<std::mutex> lock(mMutex); + + auto iter = mBufferReferenceCounts.find(bufferHandle); + if (iter == mBufferReferenceCounts.end()) { + // this should never happen + err = GRALLOC1_ERROR_BAD_HANDLE; + } else if (--iter->second == 0) { + native_handle_close(nativeHandle); + native_handle_delete(const_cast<native_handle_t*>(nativeHandle)); + + mBufferReferenceCounts.erase(iter); + } + } + + return static_cast<Error>(err); +} + +Return<void> GrallocMapperHal::getDimensions(const hidl_handle& bufferHandle, + getDimensions_cb hidl_cb) +{ + uint32_t width = 0; + uint32_t height = 0; + int32_t err = mDispatch.getDimensions(mDevice, bufferHandle, + &width, &height); + + hidl_cb(static_cast<Error>(err), width, height); + return Void(); +} + +Return<void> GrallocMapperHal::getFormat(const hidl_handle& bufferHandle, + getFormat_cb hidl_cb) +{ + int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + int32_t err = mDispatch.getFormat(mDevice, bufferHandle, &format); + + hidl_cb(static_cast<Error>(err), static_cast<PixelFormat>(format)); + return Void(); +} + +Return<void> GrallocMapperHal::getLayerCount(const hidl_handle& bufferHandle, + getLayerCount_cb hidl_cb) +{ + int32_t err = GRALLOC1_ERROR_NONE; + uint32_t count = 1; + if (mCapabilities.layeredBuffers) { + err = mDispatch.getLayerCount(mDevice, bufferHandle, &count); + } + + hidl_cb(static_cast<Error>(err), count); + return Void(); +} + +Return<void> GrallocMapperHal::getProducerUsageMask( + const hidl_handle& bufferHandle, getProducerUsageMask_cb hidl_cb) +{ + uint64_t mask = 0x0; + int32_t err = mDispatch.getProducerUsage(mDevice, bufferHandle, &mask); + + hidl_cb(static_cast<Error>(err), mask); + return Void(); +} + +Return<void> GrallocMapperHal::getConsumerUsageMask( + const hidl_handle& bufferHandle, getConsumerUsageMask_cb hidl_cb) +{ + uint64_t mask = 0x0; + int32_t err = mDispatch.getConsumerUsage(mDevice, bufferHandle, &mask); + + hidl_cb(static_cast<Error>(err), mask); + return Void(); +} + +Return<void> GrallocMapperHal::getBackingStore( + const hidl_handle& bufferHandle, getBackingStore_cb hidl_cb) +{ + uint64_t store = 0; + int32_t err = mDispatch.getBackingStore(mDevice, bufferHandle, &store); + + hidl_cb(static_cast<Error>(err), store); + return Void(); +} + +Return<void> GrallocMapperHal::getStride(const hidl_handle& bufferHandle, + getStride_cb hidl_cb) +{ + uint32_t stride = 0; + int32_t err = mDispatch.getStride(mDevice, bufferHandle, &stride); + + hidl_cb(static_cast<Error>(err), stride); + return Void(); +} + +Return<void> GrallocMapperHal::lock(const hidl_handle& bufferHandle, + uint64_t producerUsageMask, uint64_t consumerUsageMask, + const IMapper::Rect& accessRegion, const hidl_handle& acquireFence, + lock_cb hidl_cb) +{ + gralloc1_rect_t rect = asGralloc1Rect(accessRegion); + + int fence = -1; + if (!dupFence(acquireFence, &fence)) { + hidl_cb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + void* data = nullptr; + int32_t err = mDispatch.lock(mDevice, bufferHandle, producerUsageMask, + consumerUsageMask, &rect, &data, fence); + if (err != GRALLOC1_ERROR_NONE) { + close(fence); + } + + hidl_cb(static_cast<Error>(err), data); + return Void(); +} + +Return<void> GrallocMapperHal::lockFlex(const hidl_handle& bufferHandle, + uint64_t producerUsageMask, uint64_t consumerUsageMask, + const IMapper::Rect& accessRegion, const hidl_handle& acquireFence, + lockFlex_cb hidl_cb) +{ + FlexLayout layout_reply{}; + + uint32_t planeCount = 0; + int32_t err = mDispatch.getNumFlexPlanes(mDevice, bufferHandle, + &planeCount); + if (err != GRALLOC1_ERROR_NONE) { + hidl_cb(static_cast<Error>(err), layout_reply); + return Void(); + } + + gralloc1_rect_t rect = asGralloc1Rect(accessRegion); + + int fence = -1; + if (!dupFence(acquireFence, &fence)) { + hidl_cb(Error::NO_RESOURCES, layout_reply); + return Void(); + } + + std::vector<android_flex_plane_t> planes(planeCount); + android_flex_layout_t layout{}; + layout.num_planes = planes.size(); + layout.planes = planes.data(); + + err = mDispatch.lockFlex(mDevice, bufferHandle, producerUsageMask, + consumerUsageMask, &rect, &layout, fence); + if (err == GRALLOC1_ERROR_NONE) { + layout_reply.format = static_cast<FlexFormat>(layout.format); + + planes.resize(layout.num_planes); + layout_reply.planes.setToExternal( + reinterpret_cast<FlexPlane*>(planes.data()), planes.size()); + } else { + close(fence); + } + + hidl_cb(static_cast<Error>(err), layout_reply); + return Void(); +} + +Return<void> GrallocMapperHal::unlock(const hidl_handle& bufferHandle, + unlock_cb hidl_cb) +{ + int32_t fence = -1; + int32_t err = mDispatch.unlock(mDevice, bufferHandle, &fence); + + NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0); + hidl_handle fenceHandle; + if (err == GRALLOC1_ERROR_NONE && fence >= 0) { + auto nativeHandle = native_handle_init(fenceStorage, 1, 0); + nativeHandle->data[0] = fence; + + fenceHandle = nativeHandle; + } + + hidl_cb(static_cast<Error>(err), fenceHandle); + return Void(); +} + +} // anonymous namespace + +IMapper* HIDL_FETCH_IMapper(const char* /* name */) { + const hw_module_t* module = nullptr; + int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); + if (err) { + ALOGE("failed to get gralloc module"); + return nullptr; + } + + uint8_t major = (module->module_api_version >> 8) & 0xff; + if (major != 1) { + ALOGE("unknown gralloc module major version %d", major); + return nullptr; + } + + return new GrallocMapperHal(module); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android
diff --git a/graphics/mapper/2.0/default/GrallocMapper.h b/graphics/mapper/2.0/default/GrallocMapper.h new file mode 100644 index 0000000..a2f89d1 --- /dev/null +++ b/graphics/mapper/2.0/default/GrallocMapper.h
@@ -0,0 +1,38 @@ +/* + * Copyright 2016 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. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H +#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H + +#include <android/hardware/graphics/mapper/2.0/IMapper.h> + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V2_0 { +namespace implementation { + +extern "C" IMapper* HIDL_FETCH_IMapper(const char* name); + +} // namespace implementation +} // namespace V2_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
diff --git a/graphics/mapper/2.0/types.hal b/graphics/mapper/2.0/types.hal new file mode 100644 index 0000000..aa33141 --- /dev/null +++ b/graphics/mapper/2.0/types.hal
@@ -0,0 +1,116 @@ +/* + * Copyright (C) 2016 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.graphics.mapper@2.0; + +/* + * Structures for describing flexible YUVA/RGBA formats for consumption by + * applications. Such flexible formats contain a plane for each component (e.g. + * red, green, blue), where each plane is laid out in a grid-like pattern + * occupying unique byte addresses and with consistent byte offsets between + * neighboring pixels. + * + * The FlexLayout structure is used with any pixel format that can be + * represented by it, such as: + * - PixelFormat::YCBCR_*_888 + * - PixelFormat::FLEX_RGB*_888 + * - PixelFormat::RGB[AX]_888[8],BGRA_8888,RGB_888 + * - PixelFormat::YV12,Y8,Y16,YCBCR_422_SP/I,YCRCB_420_SP + * - even implementation defined formats that can be represented by + * the structures + * + * Vertical increment (aka. row increment or stride) describes the distance in + * bytes from the first pixel of one row to the first pixel of the next row + * (below) for the component plane. This can be negative. + * + * Horizontal increment (aka. column or pixel increment) describes the distance + * in bytes from one pixel to the next pixel (to the right) on the same row for + * the component plane. This can be negative. + * + * Each plane can be subsampled either vertically or horizontally by + * a power-of-two factor. + * + * The bit-depth of each component can be arbitrary, as long as the pixels are + * laid out on whole bytes, in native byte-order, using the most significant + * bits of each unit. + */ + +enum FlexComponent : int32_t { + Y = 1 << 0, /* luma */ + CB = 1 << 1, /* chroma blue */ + CR = 1 << 2, /* chroma red */ + + R = 1 << 10, /* red */ + G = 1 << 11, /* green */ + B = 1 << 12, /* blue */ + + A = 1 << 30, /* alpha */ +}; + +enum FlexFormat : int32_t { + /* not a flexible format */ + INVALID = 0x0, + + Y = FlexComponent:Y, + YCBCR = Y | FlexComponent:CB | FlexComponent:CR, + YCBCRA = YCBCR | FlexComponent:A, + + RGB = FlexComponent:R | FlexComponent:G | FlexComponent:B, + RGBA = RGB | FlexComponent:A, +}; + +struct FlexPlane { + /* Pointer to the first byte of the top-left pixel of the plane. */ + pointer topLeft; + + FlexComponent component; + + /* + * Bits allocated for the component in each pixel. Must be a positive + * multiple of 8. + */ + int32_t bitsPerComponent; + + /* + * Number of the most significant bits used in the format for this + * component. Must be between 1 and bitsPerComponent, inclusive. + */ + int32_t bitsUsed; + + /* Horizontal increment. */ + int32_t hIncrement; + /* Vertical increment. */ + int32_t vIncrement; + /* Horizontal subsampling. Must be a positive power of 2. */ + int32_t hSubsampling; + /* Vertical subsampling. Must be a positive power of 2. */ + int32_t vSubsampling; +}; + +struct FlexLayout { + /* The kind of flexible format. */ + FlexFormat format; + + /* + * A plane for each component; ordered in increasing component value + * order. E.g. FlexFormat::RGBA maps 0 -> R, 1 -> G, etc. Can have size 0 + * for FlexFormat::INVALID. + */ + vec<FlexPlane> planes; +}; + +/* Backing store ID of a buffer. See IMapper::getBackingStore. */ +typedef uint64_t BackingStore;
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp new file mode 100644 index 0000000..e26f087 --- /dev/null +++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -0,0 +1,68 @@ +// +// Copyright (C) 2016 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. +// + +cc_library_static { + name: "libVtsHalGraphicsMapperTestUtils", + defaults: ["hidl_defaults"], + srcs: ["VtsHalGraphicsMapperTestUtils.cpp"], + shared_libs: [ + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.mapper@2.0", + ], + static_libs: [ + "VtsHalHidlTargetTestBase", + "libVtsHalGraphicsAllocatorTestUtils", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-O0", + "-g", + ], + export_include_dirs: ["."], +} + +cc_test { + name: "VtsHalGraphicsMapperV2_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalGraphicsMapperV2_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libsync", + "libutils", + "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.common@1.0", + ], + static_libs: [ + "libVtsHalGraphicsAllocatorTestUtils", + "libVtsHalGraphicsMapperTestUtils", + "VtsHalHidlTargetTestBase", + ], + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-O0", + "-g", + ] +}
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp new file mode 100644 index 0000000..f6a26ac --- /dev/null +++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
@@ -0,0 +1,257 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <VtsHalHidlTargetTestBase.h> + +#include "VtsHalGraphicsMapperTestUtils.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V2_0 { +namespace tests { + +using android::hardware::graphics::allocator::V2_0::Buffer; +using android::hardware::graphics::allocator::V2_0::BufferDescriptor; +using android::hardware::graphics::allocator::V2_0::Error; + +Mapper::Mapper() { init(); } + +void Mapper::init() { + mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(); + ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service"; + ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode"; +} + +Mapper::~Mapper() { + for (auto it : mHandles) { + while (it.second) { + EXPECT_EQ(Error::NONE, mMapper->release(it.first)) + << "failed to release handle " << it.first; + it.second--; + } + } + mHandles.clear(); +} + +sp<IMapper> Mapper::getRaw() const { return mMapper; } + +void Mapper::retain(const native_handle_t* handle) { + Error error = mMapper->retain(handle); + ASSERT_EQ(Error::NONE, error) << "failed to retain handle " << handle; + + mHandles[handle]++; +} + +void Mapper::release(const native_handle_t* handle) { + Error error = mMapper->release(handle); + ASSERT_EQ(Error::NONE, error) << "failed to release handle " << handle; + + if (--mHandles[handle] == 0) { + mHandles.erase(handle); + } +} + +Mapper::Dimensions Mapper::getDimensions(const native_handle_t* handle) { + Dimensions dimensions = {}; + mMapper->getDimensions(handle, [&](const auto& tmpError, const auto& tmpWidth, + const auto& tmpHeight) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to get dimensions for handle " << handle; + dimensions.width = tmpWidth; + dimensions.height = tmpHeight; + }); + + return dimensions; +} + +PixelFormat Mapper::getFormat(const native_handle_t* handle) { + PixelFormat format = static_cast<PixelFormat>(0); + mMapper->getFormat(handle, [&](const auto& tmpError, const auto& tmpFormat) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to get format for handle " << handle; + format = tmpFormat; + }); + + return format; +} + +uint32_t Mapper::getLayerCount(const native_handle_t* handle) { + uint32_t count = 0; + mMapper->getLayerCount( + handle, [&](const auto& tmpError, const auto& tmpCount) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to get layer count for handle " << handle; + count = tmpCount; + }); + + return count; +} + +uint64_t Mapper::getProducerUsageMask(const native_handle_t* handle) { + uint64_t usageMask = 0; + mMapper->getProducerUsageMask( + handle, [&](const auto& tmpError, const auto& tmpUsageMask) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to get producer usage mask for handle " << handle; + usageMask = tmpUsageMask; + }); + + return usageMask; +} + +uint64_t Mapper::getConsumerUsageMask(const native_handle_t* handle) { + uint64_t usageMask = 0; + mMapper->getConsumerUsageMask( + handle, [&](const auto& tmpError, const auto& tmpUsageMask) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to get consumer usage mask for handle " << handle; + usageMask = tmpUsageMask; + }); + + return usageMask; +} + +BackingStore Mapper::getBackingStore(const native_handle_t* handle) { + BackingStore backingStore = 0; + mMapper->getBackingStore( + handle, [&](const auto& tmpError, const auto& tmpBackingStore) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to get backing store for handle " << handle; + backingStore = tmpBackingStore; + }); + + return backingStore; +} + +uint32_t Mapper::getStride(const native_handle_t* handle) { + uint32_t stride = 0; + mMapper->getStride(handle, [&](const auto& tmpError, const auto& tmpStride) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to get stride for handle " << handle; + stride = tmpStride; + }); + + return stride; +} + +void* Mapper::lock(const native_handle_t* handle, uint64_t producerUsageMask, + uint64_t consumerUsageMask, + const IMapper::Rect& accessRegion, int acquireFence) { + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1); + native_handle_t* acquireFenceHandle = nullptr; + if (acquireFence >= 0) { + acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1); + acquireFenceHandle->data[0] = acquireFence; + } + + void* data = nullptr; + mMapper->lock( + handle, producerUsageMask, consumerUsageMask, accessRegion, + acquireFenceHandle, [&](const auto& tmpError, const auto& tmpData) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to lock handle " << handle; + data = tmpData; + }); + + if (acquireFence >= 0) { + close(acquireFence); + } + + return data; +} + +FlexLayout Mapper::lockFlex(const native_handle_t* handle, + uint64_t producerUsageMask, + uint64_t consumerUsageMask, + const IMapper::Rect& accessRegion, + int acquireFence) { + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1); + native_handle_t* acquireFenceHandle = nullptr; + if (acquireFence >= 0) { + acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1); + acquireFenceHandle->data[0] = acquireFence; + } + + FlexLayout layout = {}; + mMapper->lockFlex(handle, producerUsageMask, consumerUsageMask, accessRegion, + acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpLayout) { + ASSERT_EQ(Error::NONE, tmpError) + << "failed to lockFlex handle " << handle; + layout = tmpLayout; + }); + + if (acquireFence >= 0) { + close(acquireFence); + } + + return layout; +} + +int Mapper::unlock(const native_handle_t* handle) { + int releaseFence = -1; + mMapper->unlock(handle, [&](const auto& tmpError, + const auto& tmpReleaseFence) { + ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock handle " << handle; + + auto handle = tmpReleaseFence.getNativeHandle(); + if (handle) { + ASSERT_EQ(0, handle->numInts) << "invalid fence handle " << handle; + if (handle->numFds == 1) { + releaseFence = dup(handle->data[0]); + ASSERT_LT(0, releaseFence) << "failed to dup fence fd"; + } else { + ASSERT_EQ(0, handle->numFds) << " invalid fence handle " << handle; + } + } + }); + + return releaseFence; +} + +const native_handle_t* Mapper::allocate( + std::unique_ptr<AllocatorClient>& allocatorClient, + const IAllocatorClient::BufferDescriptorInfo& info) { + BufferDescriptor descriptor = allocatorClient->createDescriptor(info); + if (::testing::Test::HasFatalFailure()) { + return nullptr; + } + + Buffer buffer = allocatorClient->allocate(descriptor); + if (::testing::Test::HasFatalFailure()) { + allocatorClient->destroyDescriptor(descriptor); + return nullptr; + } + + const native_handle_t* handle = + allocatorClient->exportHandle(descriptor, buffer); + if (handle) { + retain(handle); + } + + allocatorClient->free(buffer); + allocatorClient->destroyDescriptor(descriptor); + + return handle; +} + +} // namespace tests +} // namespace V2_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h new file mode 100644 index 0000000..c186b00 --- /dev/null +++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
@@ -0,0 +1,97 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef VTS_HAL_GRAPHICS_MAPPER_UTILS +#define VTS_HAL_GRAPHICS_MAPPER_UTILS + +#include <memory> +#include <unordered_map> + +#include <android/hardware/graphics/mapper/2.0/IMapper.h> +#include <utils/StrongPointer.h> + +#include "VtsHalGraphicsAllocatorTestUtils.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V2_0 { +namespace tests { + +using android::hardware::graphics::common::V1_0::PixelFormat; +using android::hardware::graphics::allocator::V2_0::IAllocatorClient; +using android::hardware::graphics::allocator::V2_0::tests::AllocatorClient; + +// A wrapper to IMapper. +class Mapper { + public: + Mapper(); + ~Mapper(); + + sp<IMapper> getRaw() const; + + void retain(const native_handle_t* handle); + void release(const native_handle_t* handle); + + struct Dimensions { + uint32_t width; + uint32_t height; + }; + Dimensions getDimensions(const native_handle_t* handle); + + PixelFormat getFormat(const native_handle_t* handle); + uint32_t getLayerCount(const native_handle_t* handle); + uint64_t getProducerUsageMask(const native_handle_t* handle); + uint64_t getConsumerUsageMask(const native_handle_t* handle); + BackingStore getBackingStore(const native_handle_t* handle); + uint32_t getStride(const native_handle_t* handle); + + // We use fd instead of hidl_handle in these functions to pass fences + // in and out of the mapper. The ownership of the fd is always transferred + // with each of these functions. + void* lock(const native_handle_t* handle, uint64_t producerUsageMask, + uint64_t consumerUsageMask, const IMapper::Rect& accessRegion, + int acquireFence); + FlexLayout lockFlex(const native_handle_t* handle, uint64_t producerUsageMask, + uint64_t consumerUsageMask, + const IMapper::Rect& accessRegion, int acquireFence); + int unlock(const native_handle_t* handle); + + // Requests AllocatorClient to allocate a buffer, export the handle, and + // register the handle with mapper. + const native_handle_t* allocate( + std::unique_ptr<AllocatorClient>& allocatorClient, + const IAllocatorClient::BufferDescriptorInfo& info); + + private: + void init(); + + sp<IMapper> mMapper; + + // Keep track of all registered (retained) handles. When a test fails with + // ASSERT_*, the destructor will release the handles for the test. + std::unordered_map<const native_handle_t*, uint64_t> mHandles; +}; + +} // namespace tests +} // namespace V2_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // VTS_HAL_GRAPHICS_MAPPER_UTILS
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp new file mode 100644 index 0000000..92d74d5 --- /dev/null +++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -0,0 +1,242 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "graphics_mapper_hidl_hal_test" + +#include <android-base/logging.h> +#include <VtsHalHidlTargetTestBase.h> +#include <sync/sync.h> +#include "VtsHalGraphicsMapperTestUtils.h" + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V2_0 { +namespace tests { +namespace { + +using namespace android::hardware::graphics::allocator::V2_0; +using namespace android::hardware::graphics::allocator::V2_0::tests; + +class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase { + protected: + void SetUp() override { + ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>()); + ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient()); + ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique<Mapper>()); + + mDummyDescriptorInfo.width = 64; + mDummyDescriptorInfo.height = 64; + mDummyDescriptorInfo.layerCount = 1; + mDummyDescriptorInfo.format = PixelFormat::RGBA_8888; + mDummyDescriptorInfo.producerUsageMask = + static_cast<uint64_t>(ProducerUsage::CPU_WRITE); + mDummyDescriptorInfo.consumerUsageMask = + static_cast<uint64_t>(ConsumerUsage::CPU_READ); + } + + void TearDown() override {} + + std::unique_ptr<Allocator> mAllocator; + std::unique_ptr<AllocatorClient> mAllocatorClient; + std::unique_ptr<Mapper> mMapper; + IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{}; +}; + +/** + * Test IMapper::retain and IMapper::release. + */ +TEST_F(GraphicsMapperHidlTest, RetainRelease) { + const native_handle_t* buffer; + ASSERT_NO_FATAL_FAILURE( + buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo)); + + const int maxRefs = 10; + for (int i = 0; i < maxRefs; i++) { + ASSERT_NO_FATAL_FAILURE(mMapper->retain(buffer)); + } + for (int i = 0; i < maxRefs; i++) { + ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer)); + } + + ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer)); +} + +/** + * Test IMapper::get* getters. + */ +TEST_F(GraphicsMapperHidlTest, Getters) { + const native_handle_t* buffer; + ASSERT_NO_FATAL_FAILURE( + buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo)); + + IAllocatorClient::BufferDescriptorInfo info = {}; + + Mapper::Dimensions dimensions; + ASSERT_NO_FATAL_FAILURE(dimensions = mMapper->getDimensions(buffer)); + info.width = dimensions.width; + info.height = dimensions.height; + + ASSERT_NO_FATAL_FAILURE(info.format = mMapper->getFormat(buffer)); + ASSERT_NO_FATAL_FAILURE(info.producerUsageMask = + mMapper->getProducerUsageMask(buffer)); + ASSERT_NO_FATAL_FAILURE(info.consumerUsageMask = + mMapper->getConsumerUsageMask(buffer)); + + EXPECT_EQ(mDummyDescriptorInfo.width, info.width); + EXPECT_EQ(mDummyDescriptorInfo.height, info.height); + EXPECT_EQ(mDummyDescriptorInfo.format, info.format); + EXPECT_EQ(mDummyDescriptorInfo.producerUsageMask, info.producerUsageMask); + EXPECT_EQ(mDummyDescriptorInfo.consumerUsageMask, info.consumerUsageMask); + + ASSERT_NO_FATAL_FAILURE(mMapper->getBackingStore(buffer)); + + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer)); + EXPECT_LE(info.width, stride); +} + +/** + * Test IMapper::lock and IMapper::unlock. + */ +TEST_F(GraphicsMapperHidlTest, LockBasic) { + const auto& info = mDummyDescriptorInfo; + + const native_handle_t* buffer; + ASSERT_NO_FATAL_FAILURE( + buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo)); + + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer)); + + // lock buffer for writing + const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width), + static_cast<int32_t>(info.height)}; + int fence = -1; + uint32_t* data; + ASSERT_NO_FATAL_FAILURE( + data = static_cast<uint32_t*>( + mMapper->lock(buffer, info.producerUsageMask, 0, region, fence))); + + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + data[stride * y + x] = info.height * y + x; + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer)); + + // lock buffer for reading + ASSERT_NO_FATAL_FAILURE( + data = static_cast<uint32_t*>( + mMapper->lock(buffer, 0, info.consumerUsageMask, region, fence))); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + EXPECT_EQ(info.height * y + x, data[stride * y + x]); + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer)); + if (fence >= 0) { + close(fence); + } +} + +/** + * Test IMapper::lockFlex. This locks a YV12 buffer, and makes sure we can + * write to and read from it. + */ +TEST_F(GraphicsMapperHidlTest, LockFlexBasic) { + auto info = mDummyDescriptorInfo; + info.format = PixelFormat::YV12; + + const native_handle_t* buffer; + ASSERT_NO_FATAL_FAILURE(buffer = mMapper->allocate(mAllocatorClient, info)); + + // lock buffer for writing + const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width), + static_cast<int32_t>(info.height)}; + int fence = -1; + FlexLayout layout; + ASSERT_NO_FATAL_FAILURE( + layout = + mMapper->lockFlex(buffer, info.producerUsageMask, 0, region, fence)); + ASSERT_EQ(FlexFormat::YCBCR, layout.format); + ASSERT_EQ(3u, layout.planes.size()); + + const auto y_stride = layout.planes[0].vIncrement; + const auto c_stride = layout.planes[1].vIncrement; + auto y_data = static_cast<uint8_t*>(layout.planes[0].topLeft); + auto cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft); + auto cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft); + + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast<uint8_t>(info.height * y + x); + + y_data[y_stride * y + x] = val; + if (y % 2 == 0 && x % 2 == 0) { + cb_data[c_stride * y / 2 + x / 2] = val; + cr_data[c_stride * y / 2 + x / 2] = val; + } + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer)); + + // lock buffer for reading + ASSERT_NO_FATAL_FAILURE( + layout = + mMapper->lockFlex(buffer, 0, info.consumerUsageMask, region, fence)); + + y_data = static_cast<uint8_t*>(layout.planes[0].topLeft); + cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft); + cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast<uint8_t>(info.height * y + x); + + EXPECT_EQ(val, y_data[y_stride * y + x]); + if (y % 2 == 0 && x % 2 == 0) { + EXPECT_EQ(val, cb_data[c_stride * y / 2 + x / 2]); + EXPECT_EQ(val, cr_data[c_stride * y / 2 + x / 2]); + } + } + } + + ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer)); + if (fence >= 0) { + close(fence); + } +} + +} // namespace anonymous +} // namespace tests +} // namespace V2_0 +} // namespace mapper +} // namespace graphics +} // namespace hardware +} // namespace android + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + + return status; +}
diff --git a/graphics/mapper/Android.mk b/graphics/mapper/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/graphics/mapper/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/health/1.0/Android.bp b/health/1.0/Android.bp new file mode 100644 index 0000000..a428c7d --- /dev/null +++ b/health/1.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.health@1.0_hal", + srcs: [ + "types.hal", + "IHealth.hal", + ], +} + +genrule { + name: "android.hardware.health@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.health@1.0", + srcs: [ + ":android.hardware.health@1.0_hal", + ], + out: [ + "android/hardware/health/1.0/types.cpp", + "android/hardware/health/1.0/HealthAll.cpp", + ], +} + +genrule { + name: "android.hardware.health@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.health@1.0", + srcs: [ + ":android.hardware.health@1.0_hal", + ], + out: [ + "android/hardware/health/1.0/types.h", + "android/hardware/health/1.0/IHealth.h", + "android/hardware/health/1.0/IHwHealth.h", + "android/hardware/health/1.0/BnHwHealth.h", + "android/hardware/health/1.0/BpHwHealth.h", + "android/hardware/health/1.0/BsHealth.h", + ], +} + +cc_library_shared { + name: "android.hardware.health@1.0", + generated_sources: ["android.hardware.health@1.0_genc++"], + generated_headers: ["android.hardware.health@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.health@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/health/1.0/Android.mk b/health/1.0/Android.mk new file mode 100644 index 0000000..ebb89a7 --- /dev/null +++ b/health/1.0/Android.mk
@@ -0,0 +1,304 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.health@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (BatteryHealth) +# +GEN := $(intermediates)/android/hardware/health/V1_0/BatteryHealth.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.BatteryHealth + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (BatteryStatus) +# +GEN := $(intermediates)/android/hardware/health/V1_0/BatteryStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.BatteryStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HealthConfig) +# +GEN := $(intermediates)/android/hardware/health/V1_0/HealthConfig.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.HealthConfig + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HealthInfo) +# +GEN := $(intermediates)/android/hardware/health/V1_0/HealthInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.HealthInfo + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Result) +# +GEN := $(intermediates)/android/hardware/health/V1_0/Result.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.Result + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IHealth.hal +# +GEN := $(intermediates)/android/hardware/health/V1_0/IHealth.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHealth.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::IHealth + +$(GEN): $(LOCAL_PATH)/IHealth.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.health@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (BatteryHealth) +# +GEN := $(intermediates)/android/hardware/health/V1_0/BatteryHealth.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.BatteryHealth + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (BatteryStatus) +# +GEN := $(intermediates)/android/hardware/health/V1_0/BatteryStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.BatteryStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HealthConfig) +# +GEN := $(intermediates)/android/hardware/health/V1_0/HealthConfig.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.HealthConfig + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HealthInfo) +# +GEN := $(intermediates)/android/hardware/health/V1_0/HealthInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.HealthInfo + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Result) +# +GEN := $(intermediates)/android/hardware/health/V1_0/Result.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::types.Result + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IHealth.hal +# +GEN := $(intermediates)/android/hardware/health/V1_0/IHealth.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHealth.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0::IHealth + +$(GEN): $(LOCAL_PATH)/IHealth.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.health@1.0-java-constants +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +# +GEN := $(intermediates)/android/hardware/health/V1_0/Constants.java +$(GEN): $(HIDL) +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/IHealth.hal + +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava-constants \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.health@1.0 + +$(GEN): + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +# Avoid dependency cycle of framework.jar -> this-library -> framework.jar +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj + +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/health/1.0/IHealth.hal b/health/1.0/IHealth.hal new file mode 100644 index 0000000..3828589 --- /dev/null +++ b/health/1.0/IHealth.hal
@@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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.health@1.0; + +interface IHealth { + /** + * This function lets you change healthd configuration from default if + * desired. It must be called exactly once at startup time. + * + * The configuration values are described in 'struct HealthConfig'. + * To use default configuration, simply return without modifying the + * fields of the config parameter. + * + * @param default healthd configuration. + */ + init(HealthConfig config) generates (HealthConfig configOut); + + /** + * This function is a hook to update/change device's HealthInfo (as described + * in 'struct HealthInfo'). + * + * 'HealthInfo' describes device's battery and charging status, typically + * read from kernel. These values may be modified in this call. + * + * @param Device Health info as described in 'struct HealthInfo'. + * @return skipLogging Indication to the caller to add 'or' skip logging the health + * information. Return 'true' to skip logging the update. + * @return infoOut HealthInfo to be sent to client code. (May or may + * not be modified). + */ + update(HealthInfo info) generates (bool skipLogging, HealthInfo infoOut); + + /** + * This function is called by healthd when framework queries for remaining + * energy in the Battery through BatteryManager APIs. + * + * @return result Result of querying enery counter for the battery. + * @return energy Battery remaining energy in nanowatt-hours. + * Must be '0' if result is anything other than Result::SUCCESS. + */ + energyCounter() generates (Result result, int64_t energy); +};
diff --git a/health/1.0/default/Android.mk b/health/1.0/default/Android.mk new file mode 100644 index 0000000..96ff91f --- /dev/null +++ b/health/1.0/default/Android.mk
@@ -0,0 +1,59 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.health@1.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_C_INCLUDES := system/core/healthd/include system/core/base/include +LOCAL_SRC_FILES := \ + Health.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libhidlbase \ + libhidltransport \ + liblog \ + libutils \ + android.hardware.health@1.0 \ + +LOCAL_STATIC_LIBRARIES := android.hardware.health@1.0-convert + +LOCAL_HAL_STATIC_LIBRARIES := libhealthd + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.health@1.0-convert +LOCAL_SRC_FILES := convert.cpp +LOCAL_C_INCLUDES := system/core/healthd/include system/core/base/include +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libhidlbase \ + libhidltransport \ + libutils \ + android.hardware.health@1.0 \ + +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE := android.hardware.health@1.0-service +LOCAL_INIT_RC := android.hardware.health@1.0-service.rc +LOCAL_SRC_FILES := \ + HealthService.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhidlbase \ + libhidltransport \ + android.hardware.health@1.0 \ + +include $(BUILD_EXECUTABLE) + +include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/health/1.0/default/Health.cpp b/health/1.0/default/Health.cpp new file mode 100644 index 0000000..1a02956 --- /dev/null +++ b/health/1.0/default/Health.cpp
@@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "health-hal" + +#include <Health.h> +#include <include/hal_conversion.h> + +namespace android { +namespace hardware { +namespace health { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::health::V1_0::hal_conversion::convertToHealthConfig; +using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig; +using ::android::hardware::health::V1_0::hal_conversion::convertToHealthInfo; +using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo; + +// Methods from ::android::hardware::health::V1_0::IHealth follow. +Return<void> Health::init(const HealthConfig& config, init_cb _hidl_cb) { + struct healthd_config healthd_config = {}; + HealthConfig configOut; + + // To keep working with existing healthd static HALs, + // convert the new HealthConfig to the old healthd_config + // and back. + + convertFromHealthConfig(config, &healthd_config); + healthd_board_init(&healthd_config); + mGetEnergyCounter = healthd_config.energyCounter; + convertToHealthConfig(&healthd_config, configOut); + + _hidl_cb(configOut); + + return Void(); +} + +Return<void> Health::update(const HealthInfo& info, update_cb _hidl_cb) { + struct android::BatteryProperties p = {}; + HealthInfo infoOut; + + // To keep working with existing healthd static HALs, + // convert the new HealthInfo to android::Batteryproperties + // and back. + + convertFromHealthInfo(info, &p); + int skipLogging = healthd_board_battery_update(&p); + convertToHealthInfo(&p, infoOut); + + _hidl_cb(!!skipLogging, infoOut); + + return Void(); +} + +Return<void> Health::energyCounter(energyCounter_cb _hidl_cb) { + int64_t energy = 0; + Result result = Result::NOT_SUPPORTED; + + if (mGetEnergyCounter) { + int status = mGetEnergyCounter(&energy); + if (status == 0) { + result = Result::SUCCESS; + } + } + + _hidl_cb(result, energy); + + return Void(); +} + +IHealth* HIDL_FETCH_IHealth(const char* /* name */) { + return new Health(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace health +} // namespace hardware +} // namespace android
diff --git a/health/1.0/default/Health.h b/health/1.0/default/Health.h new file mode 100644 index 0000000..ed364c1 --- /dev/null +++ b/health/1.0/default/Health.h
@@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_HEALTH_V1_0_HEALTH_H +#define ANDROID_HARDWARE_HEALTH_V1_0_HEALTH_H + +#include <android/hardware/health/1.0/IHealth.h> +#include <hidl/Status.h> +#include <hidl/MQDescriptor.h> +#include <healthd/healthd.h> +#include <utils/String8.h> + +namespace android { +namespace hardware { +namespace health { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::health::V1_0::HealthInfo; +using ::android::hardware::health::V1_0::HealthConfig; +using ::android::hardware::health::V1_0::IHealth; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Health : public IHealth { + // Methods from ::android::hardware::health::V1_0::IHealth follow. + Return<void> init(const HealthConfig& config, init_cb _hidl_cb) override; + Return<void> update(const HealthInfo& info, update_cb _hidl_cb) override; + Return<void> energyCounter(energyCounter_cb _hidl_cb) override; +private: + std::function<int(int64_t *)> mGetEnergyCounter; +}; + +extern "C" IHealth* HIDL_FETCH_IHealth(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace health +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_HEALTH_V1_0_HEALTH_H
diff --git a/health/1.0/default/HealthService.cpp b/health/1.0/default/HealthService.cpp new file mode 100644 index 0000000..55848d2 --- /dev/null +++ b/health/1.0/default/HealthService.cpp
@@ -0,0 +1,27 @@ +/* + * Copyright 2016 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. + */ + +#define LOG_TAG "android.hardware.health@1.0-service" + +#include <android/hardware/health/1.0/IHealth.h> +#include <hidl/LegacySupport.h> + +using android::hardware::health::V1_0::IHealth; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IHealth>(); +}
diff --git a/health/1.0/default/android.hardware.health@1.0-service.rc b/health/1.0/default/android.hardware.health@1.0-service.rc new file mode 100644 index 0000000..13cd7a5 --- /dev/null +++ b/health/1.0/default/android.hardware.health@1.0-service.rc
@@ -0,0 +1,4 @@ +service health-hal-1-0 /vendor/bin/hw/android.hardware.health@1.0-service + class hal + user system + group system
diff --git a/health/1.0/default/convert.cpp b/health/1.0/default/convert.cpp new file mode 100644 index 0000000..7f1e3c4 --- /dev/null +++ b/health/1.0/default/convert.cpp
@@ -0,0 +1,148 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "include/hal_conversion.h" + +namespace android { +namespace hardware { +namespace health { +namespace V1_0 { +namespace hal_conversion { + +void convertToHealthConfig(const struct healthd_config *hc, HealthConfig& config) { + config.periodicChoresIntervalFast = hc->periodic_chores_interval_fast; + config.periodicChoresIntervalSlow = hc->periodic_chores_interval_slow; + + config.batteryStatusPath = hc->batteryStatusPath.string(); + config.batteryHealthPath = hc->batteryHealthPath.string(); + config.batteryPresentPath = hc->batteryPresentPath.string(); + config.batteryCapacityPath = hc->batteryCapacityPath.string(); + config.batteryVoltagePath = hc->batteryVoltagePath.string(); + config.batteryTemperaturePath = hc->batteryTemperaturePath.string(); + config.batteryTechnologyPath = hc->batteryTechnologyPath.string(); + config.batteryCurrentNowPath = hc->batteryCurrentNowPath.string(); + config.batteryCurrentAvgPath = hc->batteryCurrentAvgPath.string(); + config.batteryChargeCounterPath = hc->batteryChargeCounterPath.string(); + config.batteryFullChargePath = hc->batteryFullChargePath.string(); + config.batteryCycleCountPath = hc->batteryCycleCountPath.string(); + +} + +void convertFromHealthConfig(const HealthConfig& c, struct healthd_config *hc) { + hc->periodic_chores_interval_fast = c.periodicChoresIntervalFast; + hc->periodic_chores_interval_slow = c.periodicChoresIntervalSlow; + + hc->batteryStatusPath = + android::String8(c.batteryStatusPath.c_str(), + c.batteryStatusPath.size()); + + hc->batteryHealthPath = + android::String8(c.batteryHealthPath.c_str(), + c.batteryHealthPath.size()); + + hc->batteryPresentPath = + android::String8(c.batteryPresentPath.c_str(), + c.batteryPresentPath.size()); + + hc->batteryCapacityPath = + android::String8(c.batteryCapacityPath.c_str(), + c.batteryCapacityPath.size()); + + hc->batteryVoltagePath = + android::String8(c.batteryVoltagePath.c_str(), + c.batteryVoltagePath.size()); + + hc->batteryTemperaturePath = + android::String8(c.batteryTemperaturePath.c_str(), + c.batteryTemperaturePath.size()); + + hc->batteryTechnologyPath = + android::String8(c.batteryTechnologyPath.c_str(), + c.batteryTechnologyPath.size()); + + hc->batteryCurrentNowPath = + android::String8(c.batteryCurrentNowPath.c_str(), + c.batteryCurrentNowPath.size()); + + hc->batteryCurrentAvgPath = + android::String8(c.batteryCurrentAvgPath.c_str(), + c.batteryCurrentNowPath.size()); + + hc->batteryChargeCounterPath = + android::String8(c.batteryChargeCounterPath.c_str(), + c.batteryChargeCounterPath.size()); + + hc->batteryFullChargePath = + android::String8(c.batteryFullChargePath.c_str(), + c.batteryFullChargePath.size()); + + hc->batteryCycleCountPath = + android::String8(c.batteryCycleCountPath.c_str(), + c.batteryCycleCountPath.size()); + + // energyCounter is handled through special means so all calls to + // the function go across the HALs + + // boot_min_cap - never used in Android (only in charger-mode). + + // screen_on - never used in Android (only in charger mode). +} + +void convertToHealthInfo(const struct android::BatteryProperties *p, + HealthInfo& info) { + info.chargerAcOnline = p->chargerAcOnline; + info.chargerUsbOnline = p->chargerUsbOnline; + info.chargerWirelessOnline = p->chargerWirelessOnline; + info.maxChargingCurrent = p->maxChargingCurrent; + info.maxChargingVoltage = p->maxChargingVoltage; + info.batteryStatus = static_cast<BatteryStatus>(p->batteryStatus); + info.batteryHealth = static_cast<BatteryHealth>(p->batteryHealth); + info.batteryPresent = p->batteryPresent; + info.batteryLevel = p->batteryLevel; + info.batteryVoltage = p->batteryVoltage; + info.batteryTemperature = p->batteryTemperature; + info.batteryCurrent = p->batteryCurrent; + info.batteryCycleCount = p->batteryCycleCount; + info.batteryFullCharge = p->batteryFullCharge; + info.batteryChargeCounter = p->batteryChargeCounter; + info.batteryTechnology = p->batteryTechnology; +} + +void convertFromHealthInfo(const HealthInfo& info, + struct android::BatteryProperties *p) { + p->chargerAcOnline = info.chargerAcOnline; + p->chargerUsbOnline = info.chargerUsbOnline; + p->chargerWirelessOnline = info.chargerWirelessOnline; + p->maxChargingCurrent = info.maxChargingCurrent; + p->maxChargingVoltage = info.maxChargingVoltage; + p->batteryStatus = static_cast<int>(info.batteryStatus); + p->batteryHealth = static_cast<int>(info.batteryHealth); + p->batteryPresent = info.batteryPresent; + p->batteryLevel = info.batteryLevel; + p->batteryVoltage = info.batteryVoltage; + p->batteryTemperature = info.batteryTemperature; + p->batteryCurrent = info.batteryCurrent; + p->batteryCycleCount = info.batteryCycleCount; + p->batteryFullCharge = info.batteryFullCharge; + p->batteryChargeCounter = info.batteryChargeCounter; + p->batteryTechnology = android::String8(info.batteryTechnology.c_str()); +} + +} // namespace hal_conversion +} // namespace V1_0 +} // namespace health +} // namespace hardware +} // namespace android
diff --git a/health/1.0/default/include/hal_conversion.h b/health/1.0/default/include/hal_conversion.h new file mode 100644 index 0000000..a92b208 --- /dev/null +++ b/health/1.0/default/include/hal_conversion.h
@@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef HARDWARE_INTERFACES_HEALTH_V1_0_DEFAULT_INCLUDE_HAL_CONVERSION_H_ +#define HARDWARE_INTERFACES_HEALTH_V1_0_DEFAULT_INCLUDE_HAL_CONVERSION_H_ + +#include <android/hardware/health/1.0/IHealth.h> +#include <healthd/healthd.h> + +namespace android { +namespace hardware { +namespace health { +namespace V1_0 { +namespace hal_conversion { + +void convertToHealthConfig(const struct healthd_config *hc, + HealthConfig& config); +void convertFromHealthConfig(const HealthConfig& c, struct healthd_config *hc); + +void convertToHealthInfo(const struct android::BatteryProperties *p, + HealthInfo& info); +void convertFromHealthInfo(const HealthInfo& info, + struct android::BatteryProperties *p); + +} // namespace hal_conversion +} // namespace V1_0 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // HARDWARE_INTERFACES_HEALTH_V1_0_DEFAULT_INCLUDE_HAL_CONVERSION_H_
diff --git a/health/1.0/default/libhealthd/Android.mk b/health/1.0/default/libhealthd/Android.mk new file mode 100644 index 0000000..a5f4445 --- /dev/null +++ b/health/1.0/default/libhealthd/Android.mk
@@ -0,0 +1,10 @@ +# Copyright 2016 The Android Open Source Project + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := healthd_board_default.cpp +LOCAL_MODULE := libhealthd.default +LOCAL_CFLAGS := -Werror +LOCAL_C_INCLUDES := system/core/healthd/include system/core/base/include +include $(BUILD_STATIC_LIBRARY)
diff --git a/health/1.0/default/libhealthd/healthd_board_default.cpp b/health/1.0/default/libhealthd/healthd_board_default.cpp new file mode 100644 index 0000000..127f98e --- /dev/null +++ b/health/1.0/default/libhealthd/healthd_board_default.cpp
@@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013 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. + */ + +#include <healthd/healthd.h> + +void healthd_board_init(struct healthd_config*) +{ + // use defaults +} + +int healthd_board_battery_update(struct android::BatteryProperties*) +{ + // return 0 to log periodic polled battery status to kernel log + return 0; +}
diff --git a/health/1.0/types.hal b/health/1.0/types.hal new file mode 100644 index 0000000..c5b5cc1 --- /dev/null +++ b/health/1.0/types.hal
@@ -0,0 +1,213 @@ +/* + * Copyright (C) 2016 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.health@1.0; + +/* + * Possible return values for optional HAL method(s) like + * IHealth::energyCounter() + */ +enum Result : int32_t { + SUCCESS, + NOT_SUPPORTED, + UNKNOWN, +}; + +/* + * Possible values for Battery Status. + * Note: These are currently in sync with BatteryManager and must not + * be extended / altered. + */ +@export(name="", value_prefix="BATTERY_STATUS_") +enum BatteryStatus : int32_t { + UNKNOWN = 1, + CHARGING = 2, + DISCHARGING = 3, + /* + * Battery is *not* charging - special case when charger is present + * but battery isn't charging + */ + NOT_CHARGING = 4, + FULL = 5, +}; + +/* + * Possible values for Battery Health. + * Note: These are currently in sync with BatteryManager and must not + * be extended / altered. + */ +@export(name="", value_prefix="BATTERY_HEALTH_") +enum BatteryHealth : int32_t { + UNKNOWN = 1, + GOOD = 2, + OVERHEAT = 3, + DEAD = 4, + OVER_VOLTAGE = 5, + /* + * Battery experienced an unknown/unspecifid failure. + */ + UNSPECIFIED_FAILURE = 6, + COLD = 7, +}; + +struct HealthConfig { + + /* + * periodicChoresIntervalFast is used while the device is not in + * suspend, or in suspend and connected to a charger (to watch for battery + * overheat due to charging) + */ + int32_t periodicChoresIntervalFast; + + /* + * periodicChoresIntervalSlow is used when the device is in suspend and + * not connected to a charger (to watch for a battery drained to zero + * remaining capacity). + */ + int32_t periodicChoresIntervalSlow; + + /* + * power_supply sysfs attribute file paths. Set these to specific paths + * to use for the associated battery parameters. Clients must search + * for appropriate power_supply attribute files to use, for any paths + * left empty after the HAL is initialized. + */ + + /* + * batteryStatusPath - file path to read battery charging status. + * (POWER_SUPPLY_PROP_STATUS) + */ + string batteryStatusPath; + + + /* + * batteryHealthPath - file path to read battery health. + * (POWER_SUPPLY_PROP_HEALTH) + */ + string batteryHealthPath; + + /* + * batteryPresentPath - file path to read battery present status. + * (POWER_SUPPLY_PROP_PRESENT) + */ + string batteryPresentPath; + + + /* + * batteryCapacityPath - file path to read remaining battery capacity. + * (POWER_SUPPLY_PROP_CAPACITY) + */ + string batteryCapacityPath; + + /* + * batteryVoltagePath - file path to read battery voltage. + * (POWER_SUPPLY_PROP_VOLTAGE_NOW) + */ + string batteryVoltagePath; + + /* + * batteryTemperaturePath - file path to read battery temperature in tenths + * of degree celcius. (POWER_SUPPLY_PROP_TEMP) + */ + string batteryTemperaturePath; + + /* + * batteryTechnologyPath - file path to read battery technology. + * (POWER_SUPPLY_PROP_TECHNOLOGY) + */ + string batteryTechnologyPath; + + /* + * batteryCurrentNowPath - file path to read battery instantaneous current. + * (POWER_SUPPLY_PROP_CURRENT_NOW) + */ + string batteryCurrentNowPath; + + /* + * batteryCurrentAvgPath - file path to read battery average current. + * (POWER_SUPPLY_PROP_CURRENT_AVG) + */ + string batteryCurrentAvgPath; + + /* + * batteryChargeCounterPath - file path to read battery accumulated charge. + * (POWER_SUPPLY_PROP_CHARGE_COUNTER) + */ + string batteryChargeCounterPath; + + /* + * batteryFullChargerPath - file path to read battery charge value when it + * is considered to be full. (POWER_SUPPLY_PROP_CHARGE_FULL) + */ + string batteryFullChargePath; + + /* + * batteryCycleCountPath - file path to read battery charge cycle count. + * (POWER_SUPPLY_PROP_CYCLE_COUNT) + */ + string batteryCycleCountPath; +}; + +/* + * The parameter to healthd mainloop update calls + */ +struct HealthInfo { + /* AC charger state - 'true' if online */ + bool chargerAcOnline; + + /* USB charger state - 'true' if online */ + bool chargerUsbOnline; + + /* Wireless charger state - 'true' if online */ + bool chargerWirelessOnline; + + /* Maximum charging current supported by charger in uA */ + int32_t maxChargingCurrent; + + /* Maximum charging voltage supported by charger in uV */ + int32_t maxChargingVoltage; + + BatteryStatus batteryStatus; + + BatteryHealth batteryHealth; + + /* 'true' if battery is present */ + bool batteryPresent; + + /* Remaining battery capacity in percent */ + int32_t batteryLevel; + + /* Instantaneous battery voltage in uV */ + int32_t batteryVoltage; + + /* Instantaneous battery temperature in tenths of degree celcius */ + int32_t batteryTemperature; + + /* Instantaneous battery current in uA */ + int32_t batteryCurrent; + + /* Battery charge cycle count */ + int32_t batteryCycleCount; + + /* Battery charge value when it is considered to be "full" in uA-h */ + int32_t batteryFullCharge; + + /* Instantaneous battery capacity in uA-h */ + int32_t batteryChargeCounter; + + /* Battery technology, e.g. "Li-ion, Li-Poly" etc. */ + string batteryTechnology; +};
diff --git a/health/Android.bp b/health/Android.bp new file mode 100644 index 0000000..bbb3e4b --- /dev/null +++ b/health/Android.bp
@@ -0,0 +1,4 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", +]
diff --git a/keymaster/3.0/Android.bp b/keymaster/3.0/Android.bp new file mode 100644 index 0000000..074bb68 --- /dev/null +++ b/keymaster/3.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.keymaster@3.0_hal", + srcs: [ + "types.hal", + "IKeymasterDevice.hal", + ], +} + +genrule { + name: "android.hardware.keymaster@3.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.keymaster@3.0", + srcs: [ + ":android.hardware.keymaster@3.0_hal", + ], + out: [ + "android/hardware/keymaster/3.0/types.cpp", + "android/hardware/keymaster/3.0/KeymasterDeviceAll.cpp", + ], +} + +genrule { + name: "android.hardware.keymaster@3.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.keymaster@3.0", + srcs: [ + ":android.hardware.keymaster@3.0_hal", + ], + out: [ + "android/hardware/keymaster/3.0/types.h", + "android/hardware/keymaster/3.0/IKeymasterDevice.h", + "android/hardware/keymaster/3.0/IHwKeymasterDevice.h", + "android/hardware/keymaster/3.0/BnHwKeymasterDevice.h", + "android/hardware/keymaster/3.0/BpHwKeymasterDevice.h", + "android/hardware/keymaster/3.0/BsKeymasterDevice.h", + ], +} + +cc_library_shared { + name: "android.hardware.keymaster@3.0", + generated_sources: ["android.hardware.keymaster@3.0_genc++"], + generated_headers: ["android.hardware.keymaster@3.0_genc++_headers"], + export_generated_headers: ["android.hardware.keymaster@3.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/keymaster/3.0/IKeymasterDevice.hal b/keymaster/3.0/IKeymasterDevice.hal new file mode 100644 index 0000000..50a41ec --- /dev/null +++ b/keymaster/3.0/IKeymasterDevice.hal
@@ -0,0 +1,339 @@ +/* + * Copyright (C) 2016 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.keymaster@3.0; + +/** + * Keymaster device definition. For thorough documentation see the implementer's reference, at + * https://source.android.com/security/keystore/implementer-ref.html + */ +interface IKeymasterDevice { + + /** + * Returns information about the underlying keymaster hardware. + * + * @return isSecure is true if keys are stored and never leave secure hardware (Trusted + * Execution Environment or similar). CDD requires that all devices initially + * launched with Marshmallow or later must have secure hardware. + * + * @return supportsEllipticCurve is true if the hardware supports Elliptic Curve cryptography + * with the NIST curves (P-224, P-256, P-384, and P-521). CDD requires that all + * devices initially launched with Nougat or later must support Elliptic Curve + * cryptography. + * + * @return supportsSymmetricCryptography is true if the hardware supports symmetric + * cryptography, including AES and HMAC. CDD requires that all devices initially + * launched with Nougat or later must support hardware enforcement of Keymaster + * authorizations. + * + * @return supportsAttestation is true if the hardware supports generation of Keymaster public + * key attestation certificates, signed with a key injected in a secure + * environment. CDD requires that all devices initially launched with Android O or + * later must support hardware attestation. + */ + getHardwareFeatures() + generates(bool isSecure, bool supportsEllipticCurve, + bool supportsSymmetricCryptography, bool supportsAttestation); + + /** + * Adds entropy to the RNG used by keymaster. Entropy added through this method is guaranteed + * not to be the only source of entropy used, and the mixing function is required to be secure, + * in the sense that if the RNG is seeded (from any source) with any data the attacker cannot + * predict (or control), then the RNG output is indistinguishable from random. Thus, if the + * entropy from any source is good, the output must be good. + * + * @param data Bytes to be mixed into the RNG. + * + * @return error See the ErrorCode enum in types.hal. + */ + addRngEntropy(vec<uint8_t> data) generates(ErrorCode error); + + /** + * Generates a key, or key pair, returning a key blob and/or a description of the key. + * + * @param keyParams Key generation parameters are defined as keymaster tag/value pairs, provided + * in params. See Tag in types.hal for the full list. + * + * @return error See the ErrorCode enum in types.hal. + * + * @return keyBlob Opaque, encrypted descriptor of the generated key, which generally contains a + * copy of the key material, wrapped in a key unavailable outside secure hardware. + * + * @return keyCharacteristics Description of the generated key. See KeyCharacteristis in + * types.hal. + */ + generateKey(vec<KeyParameter> keyParams) + generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics); + + /** + * Imports a key, or key pair, returning a key blob and/or a description of the key. + * + * @param keyParams Key generation parameters are defined as keymaster tag/value pairs, provided + * in params. See Tag for the full list. + * + * @param keyFormat The format of the key material to import. See KeyFormat in types.hal. + * + * @pram keyData The key material to import, in the format specifed in keyFormat. + * + * @return error See the ErrorCode enum. + * + * @return keyBlob Opaque, encrypted descriptor of the generated key, which will generally + * contain a copy of the key material, wrapped in a key unavailable outside secure + * hardware. + * + * @return keyCharacteristics Decription of the generated key. See KeyCharacteristis. + * + * @return error See the ErrorCode enum. + */ + importKey(vec<KeyParameter> params, KeyFormat keyFormat, vec<uint8_t> keyData) + generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics); + + /** + * Returns the characteristics of the specified key, if the keyBlob is valid (implementations + * must fully validate the integrity of the key). + * + * @param keyBlob The opaque descriptor returned by generateKey() or importKey(); + * + * @param clientId An opaque byte string identifying the client. This value must match the + * Tag::APPLICATION_ID data provided during key generation/import. Without the + * correct value it must be cryptographically impossible for the secure hardware to + * obtain the key material. + * + * @param appData An opaque byte string provided by the application. This value must match the + * Tag::APPLICATION_DATA data provided during key generation/import. Without the + * correct value it must be cryptographically impossible for the secure hardware to + * obtain the key material. + * + * @return error See the ErrorCode enum in types.hal. + * + * @return keyCharacteristics Decription of the generated key. See KeyCharacteristis in + * types.hal. + */ + getKeyCharacteristics(vec<uint8_t> keyBlob, vec<uint8_t> clientId, vec<uint8_t> appData) + generates(ErrorCode error, KeyCharacteristics keyCharacteristics); + + /** + * Exports a public key, returning the key in the specified format. + * + * @parm keyFormat The format used for export. See KeyFormat in types.hal. + * + * @param keyBlob The opaque descriptor returned by generateKey() or importKey(). The + * referenced key must be asymmetric. + * + * @param clientId An opaque byte string identifying the client. This value must match the + * Tag::APPLICATION_ID data provided during key generation/import. Without the + * correct value it must be cryptographically impossible for the secure hardware to + * obtain the key material. + * + * @param appData An opaque byte string provided by the application. This value must match the + * Tag::APPLICATION_DATA data provided during key generation/import. Without the + * correct value it must be cryptographically impossible for the secure hardware to + * obtain the key material. + * + * @return error See the ErrorCode enum in types.hal. + * + * @return keyMaterial The public key material in PKCS#8 format. + */ + exportKey(KeyFormat keyFormat, vec<uint8_t> keyBlob, vec<uint8_t> clientId, + vec<uint8_t> appData) generates(ErrorCode error, vec<uint8_t> keyMaterial); + + /** + * Generates a signed X.509 certificate chain attesting to the presence of keyToAttest in + * keymaster. The certificate will contain an extension with OID 1.3.6.1.4.1.11129.2.1.17 and + * value defined in: + * + * https://developer.android.com/training/articles/security-key-attestation.html. + * + * @param keyToAttest The opaque descriptor returned by generateKey() or importKey(). The + * referenced key must be asymmetric. + * + * @param attestParams Parameters for the attestation, notably Tag::ATTESTATION_CHALLENGE. + * + * @return error See the ErrorCode enum in types.hal. + */ + attestKey(vec<uint8_t> keyToAttest, vec<KeyParameter> attestParams) + generates(ErrorCode error, vec<vec<uint8_t>> certChain); + + /** + * Upgrades an old key. Keys can become "old" in two ways: Keymaster can be upgraded to a new + * version, or the system can be updated to invalidate the OS version and/or patch level. In + * either case, attempts to use an old key with getKeyCharacteristics(), exportKey(), + * attestKey() or begin() will result in keymaster returning + * ErrorCode::KEY_REQUIRES_UPGRADE. This method must then be called to upgrade the key. + * + * @param keyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey(); + * + * @param upgradeParams A parameter list containing any parameters needed to complete the + * upgrade, including Tag::APPLICATION_ID and Tag::APPLICATION_DATA. + * + * @return error See the ErrorCode enum. + */ + upgradeKey(vec<uint8_t> keyBlobToUpgrade, vec<KeyParameter> upgradeParams) + generates(ErrorCode error, vec<uint8_t> upgradedKeyBlob); + + /** + * Deletes the key, or key pair, associated with the key blob. After calling this function it + * will be impossible to use the key for any other operations. May be applied to keys from + * foreign roots of trust (keys not usable under the current root of trust). + * + * This is a NOP for keys that don't have rollback protection. + * + * @param keyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey(); + * + * @return error See the ErrorCode enum. + */ + deleteKey(vec<uint8_t> keyBlob) generates(ErrorCode error); + + /** + * Deletes all keys in the hardware keystore. Used when keystore is reset completely. After + * calling this function it will be impossible to use any previously generated or imported key + * blobs for any operations. + * + * This is a NOP if keys don't have rollback protection. + * + * @return error See the ErrorCode enum. + */ + deleteAllKeys() generates(ErrorCode error); + + /** + * Destroys knowledge of the device's ids. This prevents all device id attestation in the + * future. The destruction must be permanent so that not even a factory reset will restore the + * device ids. + * + * Device id attestation may be provided only if this method is fully implemented, allowing the + * user to permanently disable device id attestation. If this cannot be guaranteed, the device + * must never attest any device ids. + * + * This is a NOP if device id attestation is not supported. + * + * @return error See the ErrorCode enum. + */ + destroyAttestationIds() generates(ErrorCode error); + + /** + * Begins a cryptographic operation using the specified key. If all is well, begin() will return + * ErrorCode::OK and create an operation handle which must be passed to subsequent calls to + * update(), finish() or abort(). + * + * It is critical that each call to begin() be paired with a subsequent call to finish() or + * abort(), to allow the keymaster implementation to clean up any internal operation state. + * Failure to do this may leak internal state space or other internal resources and may + * eventually cause begin() to return ErrorCode::TOO_MANY_OPERATIONS when it runs out of space + * for operations. Any result other than ErrorCode::OK from begin(), update() or finish() + * implicitly aborts the operation, in which case abort() need not be called (and will return + * ErrorCode::INVALID_OPERATION_HANDLE if called). + * + * @param purpose The purpose of the operation, one of KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT, + * KeyPurpose::SIGN or KeyPurpose::VERIFY. Note that for AEAD modes, encryption and + * decryption imply signing and verification, respectively, but must be specified as + * KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT. + * + * @param keyBlob The opaque key descriptor returned by generateKey() or importKey(). The key + * must have a purpose compatible with purpose and all of its usage requirements + * must be satisfied, or begin() will return an appropriate error code. + * + * @param inParams Additional parameters for the operation. This is typically used to provide + * authentication data, with Tag::AUTH_TOKEN. If Tag::APPLICATION_ID or + * Tag::APPLICATION_DATA were provided during generation, they must be provided + * here, or the operation will fail with ErrorCode::INVALID_KEY_BLOB. For operations + * that require a nonce or IV, on keys that were generated with Tag::CALLER_NONCE, + * inParams may contain a tag Tag::NONCE. + * + * @return error See the ErrorCode enum in types.hal. + * + * @return outParams Output parameters. Used to return additional data from the operation + * initialization, notably to return the IV or nonce from operations that generate + * an IV or nonce. + * + * @return operationHandle The newly-created operation handle which must be passed to update(), + * finish() or abort(). + */ + begin(KeyPurpose purpose, vec<uint8_t> key, vec<KeyParameter> inParams) + generates(ErrorCode error, vec<KeyParameter> outParams, OperationHandle operationHandle); + + /** + * Provides data to, and possibly receives output from, an ongoing cryptographic operation begun + * with begin(). + * + * If operationHandle is invalid, update() will return ErrorCode::INVALID_OPERATION_HANDLE. + * + * update() may not consume all of the data provided in the data buffer. update() will return + * the amount consumed in inputConsumed. The caller may provide the unconsumed data in a + * subsequent call. + * + * @param operationHandle The operation handle returned by begin(). + * + * @param inParams Additional parameters for the operation. For AEAD modes, this is used to + * specify Tag::ADDITIONAL_DATA. Note that additional data may be provided in + * multiple calls to update(), but only until input data has been provided. + * + * @param input Data to be processed, per the parameters established in the call to begin(). + * Note that update() may or may not consume all of the data provided. See + * inputConsumed. + * + * @return error See the ErrorCode enum in types.hal. + * + * @return inputConsumed Amount of data that was consumed by update(). If this is less than the + * amount provided, the caller may provide the remainder in a subsequent call to + * update() or finish(). + * + * @return outParams Output parameters, used to return additional data from the operation The + * caller takes ownership of the output parameters array and must free it with + * keymaster_free_param_set(). + * + * @return output The output data, if any. + */ + update(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input) + generates(ErrorCode error, uint32_t inputConsumed, vec<KeyParameter> outParams, + vec<uint8_t> output); + + /** + * Finalizes a cryptographic operation begun with begin() and invalidates operationHandle. + * + * @param operationHandle The operation handle returned by begin(). This handle will be + * invalid when finish() returns. + * + * @param inParams Additional parameters for the operation. For AEAD modes, this is used to + * specify Tag::ADDITIONAL_DATA, but only if no input data was provided to update(). + * + * @param input Data to be processed, per the parameters established in the call to + * begin(). finish() must consume all provided data or return + * ErrorCode::INVALID_INPUT_LENGTH. + * + * @param signature The signature to be verified if the purpose specified in the begin() call + * was KeyPurpose::VERIFY. + * + * @return error See the ErrorCode enum in types.hal. + * + * @return outParams Any output parameters generated by finish(). + * + * @return output The output data, if any. + */ + finish(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input, + vec<uint8_t> signature) + generates(ErrorCode error, vec<KeyParameter> outParams, vec<uint8_t> output); + + /** + * Aborts a cryptographic operation begun with begin(), freeing all internal resources and + * invalidating operationHandle. + * + * @param operationHandle The operation handle returned by begin(). This handle will be + * invalid when abort() returns. + * + * @return error See the ErrorCode enum in types.hal. + */ + abort(OperationHandle operationHandle) generates(ErrorCode error); +};
diff --git a/keymaster/3.0/default/Android.mk b/keymaster/3.0/default/Android.mk new file mode 100644 index 0000000..c537346 --- /dev/null +++ b/keymaster/3.0/default/Android.mk
@@ -0,0 +1,43 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.keymaster@3.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + KeymasterDevice.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libsoftkeymasterdevice \ + libcrypto \ + libkeymaster1 \ + libhidlbase \ + libhidltransport \ + libutils \ + libhardware \ + android.hardware.keymaster@3.0 + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.keymaster@3.0-service +LOCAL_INIT_RC := android.hardware.keymaster@3.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + libhidlbase \ + libhidltransport \ + android.hardware.keymaster@3.0 + +include $(BUILD_EXECUTABLE)
diff --git a/keymaster/3.0/default/KeymasterDevice.cpp b/keymaster/3.0/default/KeymasterDevice.cpp new file mode 100644 index 0000000..24cf53a --- /dev/null +++ b/keymaster/3.0/default/KeymasterDevice.cpp
@@ -0,0 +1,717 @@ +/* + ** + ** Copyright 2016, 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. + */ + +#define LOG_TAG "android.hardware.keymaster@3.0-impl" + +#include "KeymasterDevice.h" + +#include <cutils/log.h> + +#include <hardware/keymaster_defs.h> +#include <keymaster/keymaster_configuration.h> +#include <keymaster/soft_keymaster_device.h> + +namespace android { +namespace hardware { +namespace keymaster { +namespace V3_0 { +namespace implementation { + +using ::keymaster::SoftKeymasterDevice; + +class SoftwareOnlyHidlKeymasterEnforcement : public ::keymaster::KeymasterEnforcement { + public: + SoftwareOnlyHidlKeymasterEnforcement() : KeymasterEnforcement(64, 64) {} + + uint32_t get_current_time() const override { + struct timespec tp; + int err = clock_gettime(CLOCK_MONOTONIC, &tp); + if (err || tp.tv_sec < 0) return 0; + return static_cast<uint32_t>(tp.tv_sec); + } + + bool activation_date_valid(uint64_t) const override { return true; } + bool expiration_date_passed(uint64_t) const override { return false; } + bool auth_token_timed_out(const hw_auth_token_t&, uint32_t) const override { return false; } + bool ValidateTokenSignature(const hw_auth_token_t&) const override { return true; } +}; + +class SoftwareOnlyHidlKeymasterContext : public ::keymaster::SoftKeymasterContext { + public: + SoftwareOnlyHidlKeymasterContext() : enforcement_(new SoftwareOnlyHidlKeymasterEnforcement) {} + + ::keymaster::KeymasterEnforcement* enforcement_policy() override { return enforcement_.get(); } + + private: + std::unique_ptr<::keymaster::KeymasterEnforcement> enforcement_; +}; + +static int keymaster0_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) { + assert(mod->module_api_version < KEYMASTER_MODULE_API_VERSION_1_0); + ALOGI("Found keymaster0 module %s, version %x", mod->name, mod->module_api_version); + + UniquePtr<SoftKeymasterDevice> soft_keymaster(new SoftKeymasterDevice); + keymaster0_device_t* km0_device = NULL; + keymaster_error_t error = KM_ERROR_OK; + + int rc = keymaster0_open(mod, &km0_device); + if (rc) { + ALOGE("Error opening keystore keymaster0 device."); + goto err; + } + + if (km0_device->flags & KEYMASTER_SOFTWARE_ONLY) { + ALOGI("Keymaster0 module is software-only. Using SoftKeymasterDevice instead."); + km0_device->common.close(&km0_device->common); + km0_device = NULL; + // SoftKeymasterDevice will be deleted by keymaster_device_release() + *dev = soft_keymaster.release()->keymaster2_device(); + return 0; + } + + ALOGD("Wrapping keymaster0 module %s with SoftKeymasterDevice", mod->name); + error = soft_keymaster->SetHardwareDevice(km0_device); + km0_device = NULL; // SoftKeymasterDevice has taken ownership. + if (error != KM_ERROR_OK) { + ALOGE("Got error %d from SetHardwareDevice", error); + rc = error; + goto err; + } + + // SoftKeymasterDevice will be deleted by keymaster_device_release() + *dev = soft_keymaster.release()->keymaster2_device(); + return 0; + +err: + if (km0_device) km0_device->common.close(&km0_device->common); + *dev = NULL; + return rc; +} + +static int keymaster1_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) { + assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0); + ALOGI("Found keymaster1 module %s, version %x", mod->name, mod->module_api_version); + + UniquePtr<SoftKeymasterDevice> soft_keymaster(new SoftKeymasterDevice); + keymaster1_device_t* km1_device = nullptr; + keymaster_error_t error = KM_ERROR_OK; + + int rc = keymaster1_open(mod, &km1_device); + if (rc) { + ALOGE("Error %d opening keystore keymaster1 device", rc); + goto err; + } + + ALOGD("Wrapping keymaster1 module %s with SofKeymasterDevice", mod->name); + error = soft_keymaster->SetHardwareDevice(km1_device); + km1_device = nullptr; // SoftKeymasterDevice has taken ownership. + if (error != KM_ERROR_OK) { + ALOGE("Got error %d from SetHardwareDevice", error); + rc = error; + goto err; + } + + // SoftKeymasterDevice will be deleted by keymaster_device_release() + *dev = soft_keymaster.release()->keymaster2_device(); + return 0; + +err: + if (km1_device) km1_device->common.close(&km1_device->common); + *dev = NULL; + return rc; +} + +static int keymaster2_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) { + assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_2_0); + ALOGI("Found keymaster2 module %s, version %x", mod->name, mod->module_api_version); + + keymaster2_device_t* km2_device = nullptr; + + int rc = keymaster2_open(mod, &km2_device); + if (rc) { + ALOGE("Error %d opening keystore keymaster2 device", rc); + goto err; + } + + *dev = km2_device; + return 0; + +err: + if (km2_device) km2_device->common.close(&km2_device->common); + *dev = nullptr; + return rc; +} + +static int keymaster_device_initialize(keymaster2_device_t** dev, uint32_t* version, + bool* supports_ec) { + const hw_module_t* mod; + + *supports_ec = true; + + int rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod); + if (rc) { + ALOGI("Could not find any keystore module, using software-only implementation."); + // SoftKeymasterDevice will be deleted by keymaster_device_release() + *dev = (new SoftKeymasterDevice(new SoftwareOnlyHidlKeymasterContext))->keymaster2_device(); + *version = -1; + return 0; + } + + if (mod->module_api_version < KEYMASTER_MODULE_API_VERSION_1_0) { + *version = 0; + int rc = keymaster0_device_initialize(mod, dev); + if (rc == 0 && ((*dev)->flags & KEYMASTER_SUPPORTS_EC) == 0) { + *supports_ec = false; + } + return rc; + } else if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) { + *version = 1; + return keymaster1_device_initialize(mod, dev); + } else { + *version = 2; + return keymaster2_device_initialize(mod, dev); + } +} + +KeymasterDevice::~KeymasterDevice() { + if (keymaster_device_) keymaster_device_->common.close(&keymaster_device_->common); +} + +static inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) { + return keymaster_tag_get_type(tag); +} + +/** + * legacy_enum_conversion converts enums from hidl to keymaster and back. Currently, this is just a + * cast to make the compiler happy. One of two thigs should happen though: + * TODO The keymaster enums should become aliases for the hidl generated enums so that we have a + * single point of truth. Then this cast function can go away. + */ +inline static keymaster_tag_t legacy_enum_conversion(const Tag value) { + return keymaster_tag_t(value); +} +inline static Tag legacy_enum_conversion(const keymaster_tag_t value) { + return Tag(value); +} +inline static keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) { + return keymaster_purpose_t(value); +} +inline static keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) { + return keymaster_key_format_t(value); +} +inline static ErrorCode legacy_enum_conversion(const keymaster_error_t value) { + return ErrorCode(value); +} + +class KmParamSet : public keymaster_key_param_set_t { + public: + KmParamSet(const hidl_vec<KeyParameter>& keyParams) { + params = new keymaster_key_param_t[keyParams.size()]; + length = keyParams.size(); + for (size_t i = 0; i < keyParams.size(); ++i) { + auto tag = legacy_enum_conversion(keyParams[i].tag); + switch (typeFromTag(tag)) { + case KM_ENUM: + case KM_ENUM_REP: + params[i] = keymaster_param_enum(tag, keyParams[i].f.integer); + break; + case KM_UINT: + case KM_UINT_REP: + params[i] = keymaster_param_int(tag, keyParams[i].f.integer); + break; + case KM_ULONG: + case KM_ULONG_REP: + params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger); + break; + case KM_DATE: + params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime); + break; + case KM_BOOL: + if (keyParams[i].f.boolValue) + params[i] = keymaster_param_bool(tag); + else + params[i].tag = KM_TAG_INVALID; + break; + case KM_BIGNUM: + case KM_BYTES: + params[i] = + keymaster_param_blob(tag, &keyParams[i].blob[0], keyParams[i].blob.size()); + break; + case KM_INVALID: + default: + params[i].tag = KM_TAG_INVALID; + /* just skip */ + break; + } + } + } + KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} { + other.length = 0; + other.params = nullptr; + } + KmParamSet(const KmParamSet&) = delete; + ~KmParamSet() { delete[] params; } +}; + +inline static KmParamSet hidlParams2KmParamSet(const hidl_vec<KeyParameter>& params) { + return KmParamSet(params); +} + +inline static keymaster_blob_t hidlVec2KmBlob(const hidl_vec<uint8_t>& blob) { + /* hidl unmarshals funny pointers if the the blob is empty */ + if (blob.size()) return {&blob[0], blob.size()}; + return {nullptr, 0}; +} + +inline static keymaster_key_blob_t hidlVec2KmKeyBlob(const hidl_vec<uint8_t>& blob) { + /* hidl unmarshals funny pointers if the the blob is empty */ + if (blob.size()) return {&blob[0], blob.size()}; + return {nullptr, 0}; +} + +inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_key_blob_t& blob) { + hidl_vec<uint8_t> result; + result.setToExternal(const_cast<unsigned char*>(blob.key_material), blob.key_material_size); + return result; +} +inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_blob_t& blob) { + hidl_vec<uint8_t> result; + result.setToExternal(const_cast<unsigned char*>(blob.data), blob.data_length); + return result; +} + +inline static hidl_vec<hidl_vec<uint8_t>> +kmCertChain2Hidl(const keymaster_cert_chain_t* cert_chain) { + hidl_vec<hidl_vec<uint8_t>> result; + if (!cert_chain || cert_chain->entry_count == 0 || !cert_chain->entries) return result; + + result.resize(cert_chain->entry_count); + for (size_t i = 0; i < cert_chain->entry_count; ++i) { + auto& entry = cert_chain->entries[i]; + result[i] = kmBlob2hidlVec(entry); + } + + return result; +} + +static inline hidl_vec<KeyParameter> kmParamSet2Hidl(const keymaster_key_param_set_t& set) { + hidl_vec<KeyParameter> result; + if (set.length == 0 || set.params == nullptr) return result; + + result.resize(set.length); + keymaster_key_param_t* params = set.params; + for (size_t i = 0; i < set.length; ++i) { + auto tag = params[i].tag; + result[i].tag = legacy_enum_conversion(tag); + switch (typeFromTag(tag)) { + case KM_ENUM: + case KM_ENUM_REP: + result[i].f.integer = params[i].enumerated; + break; + case KM_UINT: + case KM_UINT_REP: + result[i].f.integer = params[i].integer; + break; + case KM_ULONG: + case KM_ULONG_REP: + result[i].f.longInteger = params[i].long_integer; + break; + case KM_DATE: + result[i].f.dateTime = params[i].date_time; + break; + case KM_BOOL: + result[i].f.boolValue = params[i].boolean; + break; + case KM_BIGNUM: + case KM_BYTES: + result[i].blob.setToExternal(const_cast<unsigned char*>(params[i].blob.data), + params[i].blob.data_length); + break; + case KM_INVALID: + default: + params[i].tag = KM_TAG_INVALID; + /* just skip */ + break; + } + } + return result; +} + +// Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow. +Return<void> KeymasterDevice::getHardwareFeatures(getHardwareFeatures_cb _hidl_cb) { + bool is_secure = false; + bool supports_symmetric_cryptography = false; + bool supports_attestation = false; + + switch (hardware_version_) { + case 2: + supports_attestation = true; + /* Falls through */ + case 1: + supports_symmetric_cryptography = true; + /* Falls through */ + case 0: + is_secure = true; + break; + }; + + _hidl_cb(is_secure, hardware_supports_ec_, supports_symmetric_cryptography, + supports_attestation); + return Void(); +} + +Return<ErrorCode> KeymasterDevice::addRngEntropy(const hidl_vec<uint8_t>& data) { + if (!data.size()) return ErrorCode::OK; + return legacy_enum_conversion( + keymaster_device_->add_rng_entropy(keymaster_device_, &data[0], data.size())); +} + +Return<void> KeymasterDevice::generateKey(const hidl_vec<KeyParameter>& keyParams, + generateKey_cb _hidl_cb) { + // result variables for the wire + KeyCharacteristics resultCharacteristics; + hidl_vec<uint8_t> resultKeyBlob; + + // result variables the backend understands + keymaster_key_blob_t key_blob{nullptr, 0}; + keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}}; + + // convert the parameter set to something our backend understands + auto kmParams = hidlParams2KmParamSet(keyParams); + + auto rc = keymaster_device_->generate_key(keymaster_device_, &kmParams, &key_blob, + &key_characteristics); + + if (rc == KM_ERROR_OK) { + // on success convert the result to wire format + resultKeyBlob = kmBlob2hidlVec(key_blob); + resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced); + resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced); + } + + // send results off to the client + _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob, resultCharacteristics); + + // free buffers that we are responsible for + if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material)); + keymaster_free_characteristics(&key_characteristics); + + return Void(); +} + +Return<void> KeymasterDevice::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob, + const hidl_vec<uint8_t>& clientId, + const hidl_vec<uint8_t>& appData, + getKeyCharacteristics_cb _hidl_cb) { + // result variables for the wire + KeyCharacteristics resultCharacteristics; + + // result variables the backend understands + keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}}; + + auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob); + auto kmClientId = hidlVec2KmBlob(clientId); + auto kmAppData = hidlVec2KmBlob(appData); + + auto rc = keymaster_device_->get_key_characteristics( + keymaster_device_, keyBlob.size() ? &kmKeyBlob : nullptr, + clientId.size() ? &kmClientId : nullptr, appData.size() ? &kmAppData : nullptr, + &key_characteristics); + + if (rc == KM_ERROR_OK) { + resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced); + resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced); + } + + _hidl_cb(legacy_enum_conversion(rc), resultCharacteristics); + + keymaster_free_characteristics(&key_characteristics); + + return Void(); +} + +Return<void> KeymasterDevice::importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat, + const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) { + // result variables for the wire + KeyCharacteristics resultCharacteristics; + hidl_vec<uint8_t> resultKeyBlob; + + // result variables the backend understands + keymaster_key_blob_t key_blob{nullptr, 0}; + keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}}; + + auto kmParams = hidlParams2KmParamSet(params); + auto kmKeyData = hidlVec2KmBlob(keyData); + + auto rc = keymaster_device_->import_key(keymaster_device_, &kmParams, + legacy_enum_conversion(keyFormat), &kmKeyData, + &key_blob, &key_characteristics); + + if (rc == KM_ERROR_OK) { + // on success convert the result to wire format + // (Can we assume that key_blob is {nullptr, 0} or a valid buffer description?) + resultKeyBlob = kmBlob2hidlVec(key_blob); + resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced); + resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced); + } + + _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob, resultCharacteristics); + + // free buffers that we are responsible for + if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material)); + keymaster_free_characteristics(&key_characteristics); + + return Void(); +} + +Return<void> KeymasterDevice::exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob, + const hidl_vec<uint8_t>& clientId, + const hidl_vec<uint8_t>& appData, exportKey_cb _hidl_cb) { + + // result variables for the wire + hidl_vec<uint8_t> resultKeyBlob; + + // result variables the backend understands + keymaster_blob_t out_blob{nullptr, 0}; + + auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob); + auto kmClientId = hidlVec2KmBlob(clientId); + auto kmAppData = hidlVec2KmBlob(appData); + + auto rc = keymaster_device_->export_key(keymaster_device_, legacy_enum_conversion(exportFormat), + keyBlob.size() ? &kmKeyBlob : nullptr, + clientId.size() ? &kmClientId : nullptr, + appData.size() ? &kmAppData : nullptr, &out_blob); + + if (rc == KM_ERROR_OK) { + // on success convert the result to wire format + // (Can we assume that key_blob is {nullptr, 0} or a valid buffer description?) + resultKeyBlob = kmBlob2hidlVec(out_blob); + } + + _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob); + + // free buffers that we are responsible for + if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data)); + + return Void(); +} + +Return<void> KeymasterDevice::attestKey(const hidl_vec<uint8_t>& keyToAttest, + const hidl_vec<KeyParameter>& attestParams, + attestKey_cb _hidl_cb) { + + hidl_vec<hidl_vec<uint8_t>> resultCertChain; + + for (size_t i = 0; i < attestParams.size(); ++i) { + switch (attestParams[i].tag) { + case Tag::ATTESTATION_ID_BRAND: + case Tag::ATTESTATION_ID_DEVICE: + case Tag::ATTESTATION_ID_PRODUCT: + case Tag::ATTESTATION_ID_SERIAL: + case Tag::ATTESTATION_ID_IMEI: + case Tag::ATTESTATION_ID_MEID: + // Device id attestation may only be supported if the device is able to permanently + // destroy its knowledge of the ids. This device is unable to do this, so it must + // never perform any device id attestation. + _hidl_cb(ErrorCode::CANNOT_ATTEST_IDS, resultCertChain); + return Void(); + default: + break; + } + } + + keymaster_cert_chain_t cert_chain{nullptr, 0}; + + auto kmKeyToAttest = hidlVec2KmKeyBlob(keyToAttest); + auto kmAttestParams = hidlParams2KmParamSet(attestParams); + + auto rc = keymaster_device_->attest_key(keymaster_device_, &kmKeyToAttest, &kmAttestParams, + &cert_chain); + + if (rc == KM_ERROR_OK) { + resultCertChain = kmCertChain2Hidl(&cert_chain); + } + + _hidl_cb(legacy_enum_conversion(rc), resultCertChain); + + keymaster_free_cert_chain(&cert_chain); + + return Void(); +} + +Return<void> KeymasterDevice::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade, + const hidl_vec<KeyParameter>& upgradeParams, + upgradeKey_cb _hidl_cb) { + + // result variables for the wire + hidl_vec<uint8_t> resultKeyBlob; + + // result variables the backend understands + keymaster_key_blob_t key_blob{nullptr, 0}; + + auto kmKeyBlobToUpgrade = hidlVec2KmKeyBlob(keyBlobToUpgrade); + auto kmUpgradeParams = hidlParams2KmParamSet(upgradeParams); + + auto rc = keymaster_device_->upgrade_key(keymaster_device_, &kmKeyBlobToUpgrade, + &kmUpgradeParams, &key_blob); + + if (rc == KM_ERROR_OK) { + // on success convert the result to wire format + resultKeyBlob = kmBlob2hidlVec(key_blob); + } + + _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob); + + if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material)); + + return Void(); +} + +Return<ErrorCode> KeymasterDevice::deleteKey(const hidl_vec<uint8_t>& keyBlob) { + auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob); + return legacy_enum_conversion(keymaster_device_->delete_key(keymaster_device_, &kmKeyBlob)); +} + +Return<ErrorCode> KeymasterDevice::deleteAllKeys() { + if (keymaster_device_->delete_all_keys == nullptr) { + return ErrorCode::UNIMPLEMENTED; + } + return legacy_enum_conversion(keymaster_device_->delete_all_keys(keymaster_device_)); +} + +Return<ErrorCode> KeymasterDevice::destroyAttestationIds() { + return ErrorCode::UNIMPLEMENTED; +} + +Return<void> KeymasterDevice::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key, + const hidl_vec<KeyParameter>& inParams, begin_cb _hidl_cb) { + + // result variables for the wire + hidl_vec<KeyParameter> resultParams; + uint64_t resultOpHandle = 0; + + // result variables the backend understands + keymaster_key_param_set_t out_params{nullptr, 0}; + keymaster_operation_handle_t& operation_handle = resultOpHandle; + + auto kmKey = hidlVec2KmKeyBlob(key); + auto kmInParams = hidlParams2KmParamSet(inParams); + + auto rc = keymaster_device_->begin(keymaster_device_, legacy_enum_conversion(purpose), &kmKey, + &kmInParams, &out_params, &operation_handle); + + if (rc == KM_ERROR_OK) resultParams = kmParamSet2Hidl(out_params); + + _hidl_cb(legacy_enum_conversion(rc), resultParams, resultOpHandle); + + keymaster_free_param_set(&out_params); + + return Void(); +} + +Return<void> KeymasterDevice::update(uint64_t operationHandle, + const hidl_vec<KeyParameter>& inParams, + const hidl_vec<uint8_t>& input, update_cb _hidl_cb) { + // result variables for the wire + uint32_t resultConsumed = 0; + hidl_vec<KeyParameter> resultParams; + hidl_vec<uint8_t> resultBlob; + + // result variables the backend understands + size_t consumed = 0; + keymaster_key_param_set_t out_params{nullptr, 0}; + keymaster_blob_t out_blob{nullptr, 0}; + + auto kmInParams = hidlParams2KmParamSet(inParams); + auto kmInput = hidlVec2KmBlob(input); + + auto rc = keymaster_device_->update(keymaster_device_, operationHandle, &kmInParams, &kmInput, + &consumed, &out_params, &out_blob); + + if (rc == KM_ERROR_OK) { + resultConsumed = consumed; + resultParams = kmParamSet2Hidl(out_params); + resultBlob = kmBlob2hidlVec(out_blob); + } + + _hidl_cb(legacy_enum_conversion(rc), resultConsumed, resultParams, resultBlob); + + keymaster_free_param_set(&out_params); + if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data)); + + return Void(); +} + +Return<void> KeymasterDevice::finish(uint64_t operationHandle, + const hidl_vec<KeyParameter>& inParams, + const hidl_vec<uint8_t>& input, + const hidl_vec<uint8_t>& signature, finish_cb _hidl_cb) { + // result variables for the wire + hidl_vec<KeyParameter> resultParams; + hidl_vec<uint8_t> resultBlob; + + // result variables the backend understands + keymaster_key_param_set_t out_params{nullptr, 0}; + keymaster_blob_t out_blob{nullptr, 0}; + + auto kmInParams = hidlParams2KmParamSet(inParams); + auto kmInput = hidlVec2KmBlob(input); + auto kmSignature = hidlVec2KmBlob(signature); + + auto rc = keymaster_device_->finish(keymaster_device_, operationHandle, &kmInParams, &kmInput, + &kmSignature, &out_params, &out_blob); + + if (rc == KM_ERROR_OK) { + resultParams = kmParamSet2Hidl(out_params); + resultBlob = kmBlob2hidlVec(out_blob); + } + + _hidl_cb(legacy_enum_conversion(rc), resultParams, resultBlob); + + keymaster_free_param_set(&out_params); + if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data)); + + return Void(); +} + +Return<ErrorCode> KeymasterDevice::abort(uint64_t operationHandle) { + return legacy_enum_conversion(keymaster_device_->abort(keymaster_device_, operationHandle)); +} + +IKeymasterDevice* HIDL_FETCH_IKeymasterDevice(const char* /* name */) { + keymaster2_device_t* dev = nullptr; + + uint32_t version; + bool supports_ec; + auto rc = keymaster_device_initialize(&dev, &version, &supports_ec); + if (rc) return nullptr; + + auto kmrc = ::keymaster::ConfigureDevice(dev); + if (kmrc != KM_ERROR_OK) { + dev->common.close(&dev->common); + return nullptr; + } + + return new KeymasterDevice(dev, version, supports_ec); +} + +} // namespace implementation +} // namespace V3_0 +} // namespace keymaster +} // namespace hardware +} // namespace android
diff --git a/keymaster/3.0/default/KeymasterDevice.h b/keymaster/3.0/default/KeymasterDevice.h new file mode 100644 index 0000000..382f45f --- /dev/null +++ b/keymaster/3.0/default/KeymasterDevice.h
@@ -0,0 +1,98 @@ +/* + ** + ** Copyright 2016, 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. + */ + +#ifndef HIDL_GENERATED_android_hardware_keymaster_V3_0_KeymasterDevice_H_ +#define HIDL_GENERATED_android_hardware_keymaster_V3_0_KeymasterDevice_H_ + +#include <hardware/keymaster2.h> + +#include <android/hardware/keymaster/3.0/IKeymasterDevice.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace keymaster { +namespace V3_0 { +namespace implementation { + +using ::android::hardware::keymaster::V3_0::ErrorCode; +using ::android::hardware::keymaster::V3_0::IKeymasterDevice; +using ::android::hardware::keymaster::V3_0::KeyCharacteristics; +using ::android::hardware::keymaster::V3_0::KeyFormat; +using ::android::hardware::keymaster::V3_0::KeyParameter; +using ::android::hardware::keymaster::V3_0::KeyPurpose; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +class KeymasterDevice : public IKeymasterDevice { + public: + KeymasterDevice(keymaster2_device_t* dev, uint32_t hardware_version, bool hardware_supports_ec) + : keymaster_device_(dev), hardware_version_(hardware_version), + hardware_supports_ec_(hardware_supports_ec) {} + virtual ~KeymasterDevice(); + + // Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow. + Return<void> getHardwareFeatures(getHardwareFeatures_cb _hidl_cb); + Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override; + Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams, + generateKey_cb _hidl_cb) override; + Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob, + const hidl_vec<uint8_t>& clientId, + const hidl_vec<uint8_t>& appData, + getKeyCharacteristics_cb _hidl_cb) override; + Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat, + const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override; + Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob, + const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData, + exportKey_cb _hidl_cb) override; + Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest, + const hidl_vec<KeyParameter>& attestParams, + attestKey_cb _hidl_cb) override; + Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade, + const hidl_vec<KeyParameter>& upgradeParams, + upgradeKey_cb _hidl_cb) override; + Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override; + Return<ErrorCode> deleteAllKeys() override; + Return<ErrorCode> destroyAttestationIds() override; + Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key, + const hidl_vec<KeyParameter>& inParams, begin_cb _hidl_cb) override; + Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams, + const hidl_vec<uint8_t>& input, update_cb _hidl_cb) override; + Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams, + const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature, + finish_cb _hidl_cb) override; + Return<ErrorCode> abort(uint64_t operationHandle) override; + + private: + keymaster2_device_t* keymaster_device_; + uint32_t hardware_version_; + bool hardware_supports_ec_; +}; + +extern "C" IKeymasterDevice* HIDL_FETCH_IKeymasterDevice(const char* name); + +} // namespace implementation +} // namespace V3_0 +} // namespace keymaster +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_keymaster_V3_0_KeymasterDevice_H_
diff --git a/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc new file mode 100644 index 0000000..fd43178 --- /dev/null +++ b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
@@ -0,0 +1,4 @@ +service keymaster-3-0 /vendor/bin/hw/android.hardware.keymaster@3.0-service + class hal + user system + group system drmrpc
diff --git a/keymaster/3.0/default/service.cpp b/keymaster/3.0/default/service.cpp new file mode 100644 index 0000000..a6a9a93 --- /dev/null +++ b/keymaster/3.0/default/service.cpp
@@ -0,0 +1,33 @@ +/* +** +** Copyright 2016, 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. +*/ + +#define LOG_TAG "android.hardware.keymaster@3.0-service" + +#include <android/hardware/keymaster/3.0/IKeymasterDevice.h> + +#include <hidl/HidlTransportSupport.h> +#include <hidl/LegacySupport.h> + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; + +using android::hardware::keymaster::V3_0::IKeymasterDevice; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IKeymasterDevice>(); +}
diff --git a/keymaster/3.0/types.hal b/keymaster/3.0/types.hal new file mode 100644 index 0000000..9f29b6a --- /dev/null +++ b/keymaster/3.0/types.hal
@@ -0,0 +1,429 @@ +/* + * Copyright (C) 2016 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.keymaster@3.0; + +enum TagType : uint32_t { + INVALID = 0 << 28, /* Invalid type, used to designate a tag as uninitialized */ + ENUM = 1 << 28, + ENUM_REP = 2 << 28, /* Repeatable enumeration value. */ + UINT = 3 << 28, + UINT_REP = 4 << 28, /* Repeatable integer value */ + ULONG = 5 << 28, + DATE = 6 << 28, + BOOL = 7 << 28, + BIGNUM = 8 << 28, + BYTES = 9 << 28, + ULONG_REP = 10 << 28, /* Repeatable long value */ +}; + +enum Tag : uint32_t { + INVALID = TagType:INVALID | 0, + + /* + * Tags that must be semantically enforced by hardware and software implementations. + */ + + /* Crypto parameters */ + PURPOSE = TagType:ENUM_REP | 1, /* KeyPurpose. */ + ALGORITHM = TagType:ENUM | 2, /* Algorithm. */ + KEY_SIZE = TagType:UINT | 3, /* Key size in bits. */ + BLOCK_MODE = TagType:ENUM_REP | 4, /* BlockMode. */ + DIGEST = TagType:ENUM_REP | 5, /* Digest. */ + PADDING = TagType:ENUM_REP | 6, /* PaddingMode. */ + CALLER_NONCE = TagType:BOOL | 7, /* Allow caller to specify nonce or IV. */ + MIN_MAC_LENGTH = TagType:UINT | 8, /* Minimum length of MAC or AEAD authentication tag in + * bits. */ + KDF = TagType:ENUM_REP | 9, /* KeyDerivationFunction. */ + EC_CURVE = TagType:ENUM | 10, /* EcCurve. */ + + /* Algorithm-specific. */ + RSA_PUBLIC_EXPONENT = TagType:ULONG | 200, + ECIES_SINGLE_HASH_MODE = TagType:BOOL | 201, /* Whether the ephemeral public key is fed into the + * KDF. */ + INCLUDE_UNIQUE_ID = TagType:BOOL | 202, /* If true, attestation certificates for this key + * will contain an application-scoped and + * time-bounded device-unique ID.*/ + + /* Other hardware-enforced. */ + BLOB_USAGE_REQUIREMENTS = TagType:ENUM | 301, /* KeyBlobUsageRequirements. */ + BOOTLOADER_ONLY = TagType:BOOL | 302, /* Usable only by bootloader. */ + + /* + * Tags that should be semantically enforced by hardware if possible and will otherwise be + * enforced by software (keystore). + */ + + /* Key validity period */ + ACTIVE_DATETIME = TagType:DATE | 400, /* Start of validity. */ + ORIGINATION_EXPIRE_DATETIME = TagType:DATE | 401, /* Date when new "messages" should no longer + * be created. */ + USAGE_EXPIRE_DATETIME = TagType:DATE | 402, /* Date when existing "messages" should no + * longer be trusted. */ + MIN_SECONDS_BETWEEN_OPS = TagType:UINT | 403, /* Minimum elapsed time between + * cryptographic operations with the key. */ + MAX_USES_PER_BOOT = TagType:UINT | 404, /* Number of times the key can be used per + * boot. */ + + /* User authentication */ + ALL_USERS = TagType:BOOL | 500, /* Reserved for future use -- ignore. */ + USER_ID = TagType:UINT | 501, /* Reserved for future use -- ignore. */ + USER_SECURE_ID = TagType:ULONG_REP | 502, /* Secure ID of authorized user or authenticator(s). + * Disallowed if ALL_USERS or NO_AUTH_REQUIRED is + * present. */ + NO_AUTH_REQUIRED = TagType:BOOL | 503, /* If key is usable without authentication. */ + USER_AUTH_TYPE = TagType:ENUM | 504, /* Bitmask of authenticator types allowed when + * USER_SECURE_ID contains a secure user ID, rather + * than a secure authenticator ID. Defined in + * HardwareAuthenticatorType. */ + AUTH_TIMEOUT = TagType:UINT | 505, /* Required freshness of user authentication for + * private/secret key operations, in seconds. Public + * key operations require no authentication. If + * absent, authentication is required for every use. + * Authentication state is lost when the device is + * powered off. */ + ALLOW_WHILE_ON_BODY = TagType:BOOL | 506, /* Allow key to be used after authentication timeout + * if device is still on-body (requires secure on-body + * sensor. */ + + /* Application access control */ + ALL_APPLICATIONS = TagType:BOOL | 600, /* Specified to indicate key is usable by all + * applications. */ + APPLICATION_ID = TagType:BYTES | 601, /* Byte string identifying the authorized application. */ + EXPORTABLE = TagType:BOOL | 602, /* If true, private/secret key can be exported, but only + * if all access control requirements for use are + * met. (keymaster2) */ + + /* + * Semantically unenforceable tags, either because they have no specific meaning or because + * they're informational only. + */ + APPLICATION_DATA = TagType:BYTES | 700, /* Data provided by authorized application. */ + CREATION_DATETIME = TagType:DATE | 701, /* Key creation time */ + ORIGIN = TagType:ENUM | 702, /* keymaster_key_origin_t. */ + ROLLBACK_RESISTANT = TagType:BOOL | 703, /* Whether key is rollback-resistant. */ + ROOT_OF_TRUST = TagType:BYTES | 704, /* Root of trust ID. */ + OS_VERSION = TagType:UINT | 705, /* Version of system (keymaster2) */ + OS_PATCHLEVEL = TagType:UINT | 706, /* Patch level of system (keymaster2) */ + UNIQUE_ID = TagType:BYTES | 707, /* Used to provide unique ID in attestation */ + ATTESTATION_CHALLENGE = TagType:BYTES | 708, /* Used to provide challenge in attestation */ + ATTESTATION_APPLICATION_ID = TagType:BYTES | 709, /* Used to identify the set of possible + * applications of which one has initiated a + * key attestation */ + ATTESTATION_ID_BRAND = TagType:BYTES | 710, /* Used to provide the device's brand name to be + included in attestation */ + ATTESTATION_ID_DEVICE = TagType:BYTES | 711, /* Used to provide the device's device name to be + included in attestation */ + ATTESTATION_ID_PRODUCT = TagType:BYTES | 712, /* Used to provide the device's product name to be + included in attestation */ + ATTESTATION_ID_SERIAL = TagType:BYTES | 713, /* Used to provide the device's serial number to be + included in attestation */ + ATTESTATION_ID_IMEI = TagType:BYTES | 714, /* Used to provide the device's IMEI to be included + in attestation */ + ATTESTATION_ID_MEID = TagType:BYTES | 715, /* Used to provide the device's MEID to be included + in attestation */ + + + /* Tags used only to provide data to or receive data from operations */ + ASSOCIATED_DATA = TagType:BYTES | 1000, /* Used to provide associated data for AEAD modes. */ + NONCE = TagType:BYTES | 1001, /* Nonce or Initialization Vector */ + AUTH_TOKEN = TagType:BYTES | 1002, /* Authentication token that proves secure user + * authentication has been performed. Structure defined + * in hw_auth_token_t in hw_auth_token.h. */ + MAC_LENGTH = TagType:UINT | 1003, /* MAC or AEAD authentication tag length in bits. */ + + RESET_SINCE_ID_ROTATION = TagType:BOOL | 1004, /* Whether the device has beeen factory reset + * since the last unique ID rotation. Used for + * key attestation. */ +}; + +enum Algorithm : uint32_t { + /* Asymmetric algorithms. */ + RSA = 1, + // DSA = 2, -- Removed, do not re-use value 2. + EC = 3, + + /* Block ciphers algorithms */ + AES = 32, + + /* MAC algorithms */ + HMAC = 128, +}; + +/** + * Symmetric block cipher modes provided by keymaster implementations. + */ +enum BlockMode : uint32_t { + /* Unauthenticated modes, usable only for encryption/decryption and not generally recommended + * except for compatibility with existing other protocols. */ + ECB = 1, + CBC = 2, + CTR = 3, + + /* Authenticated modes, usable for encryption/decryption and signing/verification. Recommended + * over unauthenticated modes for all purposes. */ + GCM = 32, +}; + +/** + * Padding modes that may be applied to plaintext for encryption operations. This list includes + * padding modes for both symmetric and asymmetric algorithms. Note that implementations should not + * provide all possible combinations of algorithm and padding, only the + * cryptographically-appropriate pairs. + */ +enum PaddingMode : uint32_t { + NONE = 1, /* deprecated */ + RSA_OAEP = 2, + RSA_PSS = 3, + RSA_PKCS1_1_5_ENCRYPT = 4, + RSA_PKCS1_1_5_SIGN = 5, + PKCS7 = 64, +}; + +/** + * Digests provided by keymaster implementations. + */ +enum Digest : uint32_t { + NONE = 0, + MD5 = 1, /* Optional, may not be implemented in hardware, will be handled in software if + * needed. */ + SHA1 = 2, + SHA_2_224 = 3, + SHA_2_256 = 4, + SHA_2_384 = 5, + SHA_2_512 = 6, +}; + +/** + * Supported EC curves, used in ECDSA + */ +enum EcCurve : uint32_t { + P_224 = 0, + P_256 = 1, + P_384 = 2, + P_521 = 3, +}; + +/** + * The origin of a key (or pair), i.e. where it was generated. Note that ORIGIN can be found in + * either the hardware-enforced or software-enforced list for a key, indicating whether the key is + * hardware or software-based. Specifically, a key with GENERATED in the hardware-enforced list is + * guaranteed never to have existed outide the secure hardware. + */ +enum KeyOrigin : uint32_t { + GENERATED = 0, /* Generated in keymaster. Should not exist outside the TEE. */ + DERIVED = 1, /* Derived inside keymaster. Likely exists off-device. */ + IMPORTED = 2, /* Imported into keymaster. Existed as cleartext in Android. */ + UNKNOWN = 3, /* Keymaster did not record origin. This value can only be seen on keys in a + * keymaster0 implementation. The keymaster0 adapter uses this value to document + * the fact that it is unkown whether the key was generated inside or imported + * into keymaster. */ +}; + +/** + * Usability requirements of key blobs. This defines what system functionality must be available + * for the key to function. For example, key "blobs" which are actually handles referencing + * encrypted key material stored in the file system cannot be used until the file system is + * available, and should have BLOB_REQUIRES_FILE_SYSTEM. Other requirements entries will be added + * as needed for implementations. + */ +enum KeyBlobUsageRequirements : uint32_t { + STANDALONE = 0, + REQUIRES_FILE_SYSTEM = 1, +}; + +/** + * Possible purposes of a key (or pair). + */ +enum KeyPurpose : uint32_t { + ENCRYPT = 0, /* Usable with RSA, EC and AES keys. */ + DECRYPT = 1, /* Usable with RSA, EC and AES keys. */ + SIGN = 2, /* Usable with RSA, EC and HMAC keys. */ + VERIFY = 3, /* Usable with RSA, EC and HMAC keys. */ + DERIVE_KEY = 4, /* Usable with EC keys. */ + WRAP_KEY = 5, /* Usable with wrapping keys. */ +}; + +/** + * Keymaster error codes. + */ +enum ErrorCode : uint32_t { + OK = 0, + ROOT_OF_TRUST_ALREADY_SET = -1, + UNSUPPORTED_PURPOSE = -2, + INCOMPATIBLE_PURPOSE = -3, + UNSUPPORTED_ALGORITHM = -4, + INCOMPATIBLE_ALGORITHM = -5, + UNSUPPORTED_KEY_SIZE = -6, + UNSUPPORTED_BLOCK_MODE = -7, + INCOMPATIBLE_BLOCK_MODE = -8, + UNSUPPORTED_MAC_LENGTH = -9, + UNSUPPORTED_PADDING_MODE = -10, + INCOMPATIBLE_PADDING_MODE = -11, + UNSUPPORTED_DIGEST = -12, + INCOMPATIBLE_DIGEST = -13, + INVALID_EXPIRATION_TIME = -14, + INVALID_USER_ID = -15, + INVALID_AUTHORIZATION_TIMEOUT = -16, + UNSUPPORTED_KEY_FORMAT = -17, + INCOMPATIBLE_KEY_FORMAT = -18, + UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19, /* For PKCS8 & PKCS12 */ + UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20, /* For PKCS8 & PKCS12 */ + INVALID_INPUT_LENGTH = -21, + KEY_EXPORT_OPTIONS_INVALID = -22, + DELEGATION_NOT_ALLOWED = -23, + KEY_NOT_YET_VALID = -24, + KEY_EXPIRED = -25, + KEY_USER_NOT_AUTHENTICATED = -26, + OUTPUT_PARAMETER_NULL = -27, + INVALID_OPERATION_HANDLE = -28, + INSUFFICIENT_BUFFER_SPACE = -29, + VERIFICATION_FAILED = -30, + TOO_MANY_OPERATIONS = -31, + UNEXPECTED_NULL_POINTER = -32, + INVALID_KEY_BLOB = -33, + IMPORTED_KEY_NOT_ENCRYPTED = -34, + IMPORTED_KEY_DECRYPTION_FAILED = -35, + IMPORTED_KEY_NOT_SIGNED = -36, + IMPORTED_KEY_VERIFICATION_FAILED = -37, + INVALID_ARGUMENT = -38, + UNSUPPORTED_TAG = -39, + INVALID_TAG = -40, + MEMORY_ALLOCATION_FAILED = -41, + IMPORT_PARAMETER_MISMATCH = -44, + SECURE_HW_ACCESS_DENIED = -45, + OPERATION_CANCELLED = -46, + CONCURRENT_ACCESS_CONFLICT = -47, + SECURE_HW_BUSY = -48, + SECURE_HW_COMMUNICATION_FAILED = -49, + UNSUPPORTED_EC_FIELD = -50, + MISSING_NONCE = -51, + INVALID_NONCE = -52, + MISSING_MAC_LENGTH = -53, + KEY_RATE_LIMIT_EXCEEDED = -54, + CALLER_NONCE_PROHIBITED = -55, + KEY_MAX_OPS_EXCEEDED = -56, + INVALID_MAC_LENGTH = -57, + MISSING_MIN_MAC_LENGTH = -58, + UNSUPPORTED_MIN_MAC_LENGTH = -59, + UNSUPPORTED_KDF = -60, + UNSUPPORTED_EC_CURVE = -61, + KEY_REQUIRES_UPGRADE = -62, + ATTESTATION_CHALLENGE_MISSING = -63, + KEYMASTER_NOT_CONFIGURED = -64, + ATTESTATION_APPLICATION_ID_MISSING = -65, + CANNOT_ATTEST_IDS = -66, + + UNIMPLEMENTED = -100, + VERSION_MISMATCH = -101, + + UNKNOWN_ERROR = -1000, +}; + +/** + * Key derivation functions, mostly used in ECIES. + */ +enum KeyDerivationFunction : uint32_t { + /* Do not apply a key derivation function; use the raw agreed key */ + NONE = 0, + /* HKDF defined in RFC 5869 with SHA256 */ + RFC5869_SHA256 = 1, + /* KDF1 defined in ISO 18033-2 with SHA1 */ + ISO18033_2_KDF1_SHA1 = 2, + /* KDF1 defined in ISO 18033-2 with SHA256 */ + ISO18033_2_KDF1_SHA256 = 3, + /* KDF2 defined in ISO 18033-2 with SHA1 */ + ISO18033_2_KDF2_SHA1 = 4, + /* KDF2 defined in ISO 18033-2 with SHA256 */ + ISO18033_2_KDF2_SHA256 = 5, +}; + +/** + * Hardware authentication type, used by HardwareAuthTokens to specify the mechanism used to + * authentiate the user, and in KeyCharacteristics to specify the allowable mechanisms for + * authenticating to activate a key. + */ +enum HardwareAuthenticatorType : uint32_t { + NONE = 0, + PASSWORD = 1 << 0, + FINGERPRINT = 1 << 1, + // Additional entries must be powers of 2. + ANY = 0xFFFFFFFF, +}; + +struct KeyParameter { + /* Discriminates the uinon/blob field used. The blob cannot be coincided with the union, but + * only one of "f" and "blob" is ever used at a time. */ + Tag tag; + union IntegerParams { + /* Enum types */ + Algorithm algorithm; + BlockMode blockMode; + PaddingMode paddingMode; + Digest digest; + EcCurve ecCurve; + KeyOrigin origin; + KeyBlobUsageRequirements keyBlobUsageRequirements; + KeyPurpose purpose; + KeyDerivationFunction keyDerivationFunction; + HardwareAuthenticatorType hardwareAuthenticatorType; + + /* Other types */ + bool boolValue; // Always true, if a boolean tag is present. + uint32_t integer; + uint64_t longInteger; + uint64_t dateTime; + }; + IntegerParams f; // Hidl does not support anonymous unions, so we have to name it. + vec<uint8_t> blob; +}; + +struct KeyCharacteristics { + vec<KeyParameter> softwareEnforced; + vec<KeyParameter> teeEnforced; +}; + +/** + * Data used to prove successful authentication. + */ +struct HardwareAuthToken { + uint64_t challenge; + uint64_t userId; // Secure User ID, not Android user ID. + uint64_t authenticatorId; // Secure authenticator ID. + uint32_t authenticatorType; // HardwareAuthenticatorType, in network order. + uint64_t timestamp; // In network order. + uint8_t[32] hmac; // HMAC is computed over 0 || challenge || user_id || + // authenticator_id || authenticator_type || timestamp, with a + // prefixed 0 byte (which was a version field in Keymaster1 and + // Keymaster2) and the fields packed (no padding; so you probably + // can't just compute over the bytes of the struct). +}; + +enum SecurityLevel : uint32_t { + SOFTWARE = 0, + TRUSTED_ENVIRONMENT = 1, +}; + +/** + * Formats for key import and export. + */ +enum KeyFormat : uint32_t { + X509 = 0, /* for public key export */ + PKCS8 = 1, /* for asymmetric key pair import */ + RAW = 3, /* for symmetric key import and export*/ +}; + +typedef uint64_t OperationHandle;
diff --git a/keymaster/Android.bp b/keymaster/Android.bp new file mode 100644 index 0000000..09b8cb2 --- /dev/null +++ b/keymaster/Android.bp
@@ -0,0 +1,4 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "3.0", +]
diff --git a/light/2.0/Android.bp b/light/2.0/Android.bp new file mode 100644 index 0000000..093a9f3 --- /dev/null +++ b/light/2.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.light@2.0_hal", + srcs: [ + "types.hal", + "ILight.hal", + ], +} + +genrule { + name: "android.hardware.light@2.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.light@2.0", + srcs: [ + ":android.hardware.light@2.0_hal", + ], + out: [ + "android/hardware/light/2.0/types.cpp", + "android/hardware/light/2.0/LightAll.cpp", + ], +} + +genrule { + name: "android.hardware.light@2.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.light@2.0", + srcs: [ + ":android.hardware.light@2.0_hal", + ], + out: [ + "android/hardware/light/2.0/types.h", + "android/hardware/light/2.0/ILight.h", + "android/hardware/light/2.0/IHwLight.h", + "android/hardware/light/2.0/BnHwLight.h", + "android/hardware/light/2.0/BpHwLight.h", + "android/hardware/light/2.0/BsLight.h", + ], +} + +cc_library_shared { + name: "android.hardware.light@2.0", + generated_sources: ["android.hardware.light@2.0_genc++"], + generated_headers: ["android.hardware.light@2.0_genc++_headers"], + export_generated_headers: ["android.hardware.light@2.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/light/2.0/Android.mk b/light/2.0/Android.mk new file mode 100644 index 0000000..7bb4293 --- /dev/null +++ b/light/2.0/Android.mk
@@ -0,0 +1,270 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.light@2.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (Brightness) +# +GEN := $(intermediates)/android/hardware/light/V2_0/Brightness.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.Brightness + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Flash) +# +GEN := $(intermediates)/android/hardware/light/V2_0/Flash.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.Flash + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (LightState) +# +GEN := $(intermediates)/android/hardware/light/V2_0/LightState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.LightState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/light/V2_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Type) +# +GEN := $(intermediates)/android/hardware/light/V2_0/Type.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.Type + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build ILight.hal +# +GEN := $(intermediates)/android/hardware/light/V2_0/ILight.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/ILight.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::ILight + +$(GEN): $(LOCAL_PATH)/ILight.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.light@2.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (Brightness) +# +GEN := $(intermediates)/android/hardware/light/V2_0/Brightness.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.Brightness + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Flash) +# +GEN := $(intermediates)/android/hardware/light/V2_0/Flash.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.Flash + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (LightState) +# +GEN := $(intermediates)/android/hardware/light/V2_0/LightState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.LightState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/light/V2_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Type) +# +GEN := $(intermediates)/android/hardware/light/V2_0/Type.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::types.Type + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build ILight.hal +# +GEN := $(intermediates)/android/hardware/light/V2_0/ILight.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/ILight.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.light@2.0::ILight + +$(GEN): $(LOCAL_PATH)/ILight.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/light/2.0/ILight.hal b/light/2.0/ILight.hal new file mode 100644 index 0000000..a7cd684 --- /dev/null +++ b/light/2.0/ILight.hal
@@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 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.light@2.0; + +interface ILight { + + /** + * Set the provided lights to the provided values. + * + * @param type logical light to set + * @param state describes what the light should look like. + * @return status result of applying state transformation. + */ + setLight(Type type, LightState state) generates (Status status); + + /** + * Discover what indicator lights are available. + * + * @return types list of available lights + */ + getSupportedTypes() generates (vec<Type> types); + +};
diff --git a/light/2.0/default/Android.mk b/light/2.0/default/Android.mk new file mode 100644 index 0000000..3439c9b --- /dev/null +++ b/light/2.0/default/Android.mk
@@ -0,0 +1,45 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.light@2.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + Light.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libhidlbase \ + libhidltransport \ + libutils \ + liblog \ + libcutils \ + libhardware \ + libbase \ + libcutils \ + android.hardware.light@2.0 \ + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.light@2.0-service +LOCAL_INIT_RC := android.hardware.light@2.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + +LOCAL_SHARED_LIBRARIES += \ + libhidlbase \ + libhidltransport \ + android.hardware.light@2.0 \ + +include $(BUILD_EXECUTABLE)
diff --git a/light/2.0/default/Light.cpp b/light/2.0/default/Light.cpp new file mode 100644 index 0000000..cde1536 --- /dev/null +++ b/light/2.0/default/Light.cpp
@@ -0,0 +1,160 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "light" + +#include <log/log.h> + +#include "Light.h" + +namespace android { +namespace hardware { +namespace light { +namespace V2_0 { +namespace implementation { + +static_assert(LIGHT_FLASH_NONE == static_cast<int>(Flash::NONE), + "Flash::NONE must match legacy value."); +static_assert(LIGHT_FLASH_TIMED == static_cast<int>(Flash::TIMED), + "Flash::TIMED must match legacy value."); +static_assert(LIGHT_FLASH_HARDWARE == static_cast<int>(Flash::HARDWARE), + "Flash::HARDWARE must match legacy value."); + +static_assert(BRIGHTNESS_MODE_USER == static_cast<int>(Brightness::USER), + "Brightness::USER must match legacy value."); +static_assert(BRIGHTNESS_MODE_SENSOR == static_cast<int>(Brightness::SENSOR), + "Brightness::SENSOR must match legacy value."); +static_assert(BRIGHTNESS_MODE_LOW_PERSISTENCE == + static_cast<int>(Brightness::LOW_PERSISTENCE), + "Brightness::LOW_PERSISTENCE must match legacy value."); + +Light::Light(std::map<Type, light_device_t*> &&lights) + : mLights(std::move(lights)) {} + +// Methods from ::android::hardware::light::V2_0::ILight follow. +Return<Status> Light::setLight(Type type, const LightState& state) { + auto it = mLights.find(type); + + if (it == mLights.end()) { + return Status::LIGHT_NOT_SUPPORTED; + } + + light_device_t* hwLight = it->second; + + light_state_t legacyState { + .color = state.color, + .flashMode = static_cast<int>(state.flashMode), + .flashOnMS = state.flashOnMs, + .flashOffMS = state.flashOffMs, + .brightnessMode = static_cast<int>(state.brightnessMode), + }; + + int ret = hwLight->set_light(hwLight, &legacyState); + + switch (ret) { + case -ENOSYS: + return Status::BRIGHTNESS_NOT_SUPPORTED; + case 0: + return Status::SUCCESS; + default: + return Status::UNKNOWN; + } +} + +Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) { + Type *types = new Type[mLights.size()]; + + int idx = 0; + for(auto const &pair : mLights) { + Type type = pair.first; + + types[idx++] = type; + } + + { + hidl_vec<Type> hidl_types{}; + hidl_types.setToExternal(types, mLights.size()); + + _hidl_cb(hidl_types); + } + + delete[] types; + + return Void(); +} + +const static std::map<Type, const char*> kLogicalLights = { + {Type::BACKLIGHT, LIGHT_ID_BACKLIGHT}, + {Type::KEYBOARD, LIGHT_ID_KEYBOARD}, + {Type::BUTTONS, LIGHT_ID_BUTTONS}, + {Type::BATTERY, LIGHT_ID_BATTERY}, + {Type::NOTIFICATIONS, LIGHT_ID_NOTIFICATIONS}, + {Type::ATTENTION, LIGHT_ID_ATTENTION}, + {Type::BLUETOOTH, LIGHT_ID_BLUETOOTH}, + {Type::WIFI, LIGHT_ID_WIFI} +}; + +light_device_t* getLightDevice(const char* name) { + light_device_t* lightDevice; + const hw_module_t* hwModule = NULL; + + int ret = hw_get_module (LIGHTS_HARDWARE_MODULE_ID, &hwModule); + if (ret == 0) { + ret = hwModule->methods->open(hwModule, name, + reinterpret_cast<hw_device_t**>(&lightDevice)); + if (ret != 0) { + ALOGE("light_open %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret); + } + } else { + ALOGE("hw_get_module %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret); + } + + if (ret == 0) { + return lightDevice; + } else { + ALOGE("Light passthrough failed to load legacy HAL."); + return nullptr; + } +} + +ILight* HIDL_FETCH_ILight(const char* /* name */) { + std::map<Type, light_device_t*> lights; + + for(auto const &pair : kLogicalLights) { + Type type = pair.first; + const char* name = pair.second; + + light_device_t* light = getLightDevice(name); + + if (light != nullptr) { + lights[type] = light; + } + } + + if (lights.size() == 0) { + // Log information, but still return new Light. + // Some devices may not have any lights. + ALOGI("Could not open any lights."); + } + + return new Light(std::move(lights)); +} + +} // namespace implementation +} // namespace V2_0 +} // namespace light +} // namespace hardware +} // namespace android
diff --git a/light/2.0/default/Light.h b/light/2.0/default/Light.h new file mode 100644 index 0000000..8987036 --- /dev/null +++ b/light/2.0/default/Light.h
@@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H +#define ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H + +#include <android/hardware/light/2.0/ILight.h> +#include <hardware/hardware.h> +#include <hardware/lights.h> +#include <hidl/Status.h> +#include <hidl/MQDescriptor.h> +#include <map> + +namespace android { +namespace hardware { +namespace light { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::light::V2_0::ILight; +using ::android::hardware::light::V2_0::LightState; +using ::android::hardware::light::V2_0::Status; +using ::android::hardware::light::V2_0::Type; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Light : public ILight { + Light(std::map<Type, light_device_t*> &&lights); + + // Methods from ::android::hardware::light::V2_0::ILight follow. + Return<Status> setLight(Type type, const LightState& state) override; + Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override; + +private: + std::map<Type, light_device_t*> mLights; +}; + +extern "C" ILight* HIDL_FETCH_ILight(const char* name); + +} // namespace implementation +} // namespace V2_0 +} // namespace light +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
diff --git a/light/2.0/default/android.hardware.light@2.0-service.rc b/light/2.0/default/android.hardware.light@2.0-service.rc new file mode 100644 index 0000000..c3284c6 --- /dev/null +++ b/light/2.0/default/android.hardware.light@2.0-service.rc
@@ -0,0 +1,4 @@ +service light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service + class hal + user system + group system \ No newline at end of file
diff --git a/light/2.0/default/service.cpp b/light/2.0/default/service.cpp new file mode 100644 index 0000000..70ae565 --- /dev/null +++ b/light/2.0/default/service.cpp
@@ -0,0 +1,27 @@ +/* + * Copyright 2016 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. + */ + +#define LOG_TAG "android.hardware.light@2.0-service" + +#include <android/hardware/light/2.0/ILight.h> +#include <hidl/LegacySupport.h> + +using android::hardware::light::V2_0::ILight; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<ILight>(); +}
diff --git a/light/2.0/types.hal b/light/2.0/types.hal new file mode 100644 index 0000000..cc2ec32 --- /dev/null +++ b/light/2.0/types.hal
@@ -0,0 +1,134 @@ +/* + * Copyright (C) 2016 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.light@2.0; + +enum Status : int32_t { + SUCCESS, + LIGHT_NOT_SUPPORTED, + BRIGHTNESS_NOT_SUPPORTED, + UNKNOWN, +}; + +enum Flash : int32_t { + /* + * Keep the light steady on or off. + */ + NONE, + + /* + * Flash the light at specified rate. + */ + TIMED, + + /* + * Flash the light using hardware assist. + */ + HARDWARE, +}; + +enum Brightness : int32_t { + /** + * Light brightness is managed by a user setting. + */ + USER, + + /** + * Light brightness is managed by a light sensor. + */ + SENSOR, + + /** + * Use a low-persistence mode for display backlights. + * + * When set, the device driver must switch to a mode optimized for low display + * persistence that is intended to be used when the device is being treated as a + * head mounted display (HMD). The actual display brightness in this mode is + * implementation dependent, and any value set for color in LightState may be + * overridden by the HAL implementation. + * + * For an optimal HMD viewing experience, the display must meet the following + * criteria in this mode: + * - Gray-to-Gray, White-to-Black, and Black-to-White switching time must be ≤ 3 ms. + * - The display must support low-persistence with ≤ 3.5 ms persistence. + * Persistence is defined as the amount of time for which a pixel is + * emitting light for a single frame. + * - Any "smart panel" or other frame buffering options that increase display + * latency are disabled. + * - Display brightness is set so that the display is still visible to the user + * under normal indoor lighting. + * - The display must update at 60 Hz at least, but higher refresh rates are + * recommended for low latency. + * + */ + LOW_PERSISTENCE, +}; + +/* + * These light IDs correspond to logical lights, not physical. + * So for example, if your INDICATOR light is in line with your + * BUTTONS, it might make sense to also light the INDICATOR + * light to a reasonable color when the BUTTONS are lit. + */ +enum Type : int32_t { + BACKLIGHT, + KEYBOARD, + BUTTONS, + BATTERY, + NOTIFICATIONS, + ATTENTION, + BLUETOOTH, + WIFI, + + COUNT, +}; + +/** + * The parameters that can be set for a given light. + * + * Not all lights must support all parameters. If you + * can do something backward-compatible, do it. + */ +struct LightState { + /** + * The color of the LED in ARGB. + * + * Do your best here. + * - If your light can only do red or green, if they ask for blue, + * you should do green. + * - If you can only do a brightness ramp, then use this formula: + * unsigned char brightness = ((77*((color>>16)&0x00ff)) + * + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8; + * - If you can only do on or off, 0 is off, anything else is on. + * + * The high byte should be ignored. Callers will set it to 0xff (which + * would correspond to 255 alpha). + */ + uint32_t color; + + /** + * To flash the light at a given rate, set flashMode to LIGHT_FLASH_TIMED, + * and then flashOnMS should be set to the number of milliseconds to turn + * the light on, followed by the number of milliseconds to turn the light + * off. + */ + Flash flashMode; + + int32_t flashOnMs; + int32_t flashOffMs; + + Brightness brightnessMode; +};
diff --git a/light/2.0/vts/Android.mk b/light/2.0/vts/Android.mk new file mode 100644 index 0000000..089503b --- /dev/null +++ b/light/2.0/vts/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/light/2.0/vts/functional/Android.bp b/light/2.0/vts/functional/Android.bp new file mode 100644 index 0000000..0558ff2 --- /dev/null +++ b/light/2.0/vts/functional/Android.bp
@@ -0,0 +1,34 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalLightV2_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalLightV2_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "libhidlbase", + "liblog", + "libutils", + "android.hardware.light@2.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ] +} +
diff --git a/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp b/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp new file mode 100644 index 0000000..3405422 --- /dev/null +++ b/light/2.0/vts/functional/VtsHalLightV2_0TargetTest.cpp
@@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "light_hidl_hal_test" + +#include <android-base/logging.h> +#include <android/hardware/light/2.0/ILight.h> +#include <android/hardware/light/2.0/types.h> +#include <VtsHalHidlTargetTestBase.h> +#include <set> +#include <unistd.h> + +using ::android::hardware::light::V2_0::Brightness; +using ::android::hardware::light::V2_0::Flash; +using ::android::hardware::light::V2_0::ILight; +using ::android::hardware::light::V2_0::LightState; +using ::android::hardware::light::V2_0::Status; +using ::android::hardware::light::V2_0::Type; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk()) +#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk()) + +const static LightState kWhite = { + .color = 0xFFFFFFFF, + .flashMode = Flash::TIMED, + .flashOnMs = 100, + .flashOffMs = 50, + .brightnessMode = Brightness::USER, +}; + +const static LightState kLowPersistance = { + .color = 0xFF123456, + .flashMode = Flash::TIMED, + .flashOnMs = 100, + .flashOffMs = 50, + .brightnessMode = Brightness::LOW_PERSISTENCE, +}; + +const static LightState kOff = { + .color = 0x00000000, + .flashMode = Flash::NONE, + .flashOnMs = 0, + .flashOffMs = 0, + .brightnessMode = Brightness::USER, +}; + +const static std::set<Type> kAllTypes = { + Type::BACKLIGHT, + Type::KEYBOARD, + Type::BUTTONS, + Type::BATTERY, + Type::NOTIFICATIONS, + Type::ATTENTION, + Type::BLUETOOTH, + Type::WIFI +}; + +class LightHidlTest : public ::testing::VtsHalHidlTargetTestBase { +public: + virtual void SetUp() override { + light = ::testing::VtsHalHidlTargetTestBase::getService<ILight>(); + + ASSERT_NE(light, nullptr); + LOG(INFO) << "Test is remote " << light->isRemote(); + + ASSERT_OK(light->getSupportedTypes([this](const hidl_vec<Type> &types) { + supportedTypes = types; + })); + } + + sp<ILight> light; + std::vector<Type> supportedTypes; + + virtual void TearDown() override { + for (const Type& type: supportedTypes) { + Return<Status> ret = light->setLight(type, kOff); + EXPECT_OK(ret); + EXPECT_EQ(Status::SUCCESS, static_cast<Status>(ret)); + } + + // must leave the device in a useable condition + if (std::find(supportedTypes.begin(), + supportedTypes.end(), + Type::BACKLIGHT) != supportedTypes.end()) { + Return<Status> ret = light->setLight(Type::BACKLIGHT, kWhite); + EXPECT_OK(ret); + EXPECT_EQ(Status::SUCCESS, static_cast<Status>(ret)); + } + } + +}; + +/** + * Ensure all lights which are reported as supported work. + */ +TEST_F(LightHidlTest, TestSupported) { + for (const Type& type: supportedTypes) { + Return<Status> ret = light->setLight(type, kWhite); + EXPECT_OK(ret); + EXPECT_EQ(Status::SUCCESS, static_cast<Status>(ret)); + } +} + +/** + * Ensure BRIGHTNESS_NOT_SUPPORTED is returned if LOW_PERSISTANCE is not supported. + */ +TEST_F(LightHidlTest, TestLowPersistance) { + for (const Type& type: supportedTypes) { + Return<Status> ret = light->setLight(type, kLowPersistance); + EXPECT_OK(ret); + + Status status = ret; + EXPECT_TRUE(Status::SUCCESS == status || + Status::BRIGHTNESS_NOT_SUPPORTED == status); + } +} + +/** + * Ensure lights which are not supported return LIGHT_NOT_SUPPORTED + */ +TEST_F(LightHidlTest, TestUnsupported) { + std::set<Type> unsupportedTypes = kAllTypes; + for (const Type& type: supportedTypes) { + unsupportedTypes.erase(type); + } + + for (const Type& type: unsupportedTypes) { + Return<Status> ret = light->setLight(type, kWhite); + EXPECT_OK(ret); + EXPECT_EQ(Status::LIGHT_NOT_SUPPORTED, static_cast<Status>(ret)); + } +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +}
diff --git a/light/Android.bp b/light/Android.bp new file mode 100644 index 0000000..8d2c986 --- /dev/null +++ b/light/Android.bp
@@ -0,0 +1,5 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "2.0", + "2.0/vts/functional", +]
diff --git a/media/1.0/Android.bp b/media/1.0/Android.bp new file mode 100644 index 0000000..7518eb3 --- /dev/null +++ b/media/1.0/Android.bp
@@ -0,0 +1,55 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.media@1.0_hal", + srcs: [ + "types.hal", + ], +} + +genrule { + name: "android.hardware.media@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.media@1.0", + srcs: [ + ":android.hardware.media@1.0_hal", + ], + out: [ + "android/hardware/media/1.0/types.cpp", + ], +} + +genrule { + name: "android.hardware.media@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.media@1.0", + srcs: [ + ":android.hardware.media@1.0_hal", + ], + out: [ + "android/hardware/media/1.0/types.h", + ], +} + +cc_library_shared { + name: "android.hardware.media@1.0", + generated_sources: ["android.hardware.media@1.0_genc++"], + generated_headers: ["android.hardware.media@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.media@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.graphics.common@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.graphics.common@1.0", + ], +}
diff --git a/media/1.0/types.hal b/media/1.0/types.hal new file mode 100644 index 0000000..1f9c4dc --- /dev/null +++ b/media/1.0/types.hal
@@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 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.media@1.0; + +import android.hardware.graphics.common@1.0::PixelFormat; + +/** + * Aliases + */ +typedef handle FileDescriptor; // This must have no more than one fd. +typedef FileDescriptor Fence; +typedef vec<uint8_t> Bytes; + +/** + * Ref: frameworks/native/include/ui/GraphicBuffer.h + * Ref: system/core/include/system/window.h: ANativeWindowBuffer + */ + +/** + * This struct contains attributes for a gralloc buffer that can be put into a + * union. + */ +struct AnwBufferAttributes { + uint32_t width; + uint32_t height; + uint32_t stride; + PixelFormat format; + uint32_t usage; // TODO: convert to an enum + uint32_t generationNumber; + uint64_t layerCount; + uint64_t id; +}; + +/** + * An AnwBuffer is simply AnwBufferAttributes plus a native handle. + */ +struct AnwBuffer { + handle nativeHandle; + AnwBufferAttributes attr; +}; + +/** + * Ref: frameworks/native/include/android/rect.h + * Ref: frameworks/native/include/ui/Rect.h + */ +struct Rect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +}; + +/** + * Ref: frameworks/native/include/ui/Region.h + */ +typedef vec<Rect> Region; +
diff --git a/media/Android.bp b/media/Android.bp new file mode 100644 index 0000000..f2abc67 --- /dev/null +++ b/media/Android.bp
@@ -0,0 +1,5 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "omx/1.0", +]
diff --git a/media/omx/1.0/Android.bp b/media/omx/1.0/Android.bp new file mode 100644 index 0000000..85d15ae --- /dev/null +++ b/media/omx/1.0/Android.bp
@@ -0,0 +1,108 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.media.omx@1.0_hal", + srcs: [ + "types.hal", + "IGraphicBufferSource.hal", + "IOmx.hal", + "IOmxBufferProducer.hal", + "IOmxBufferSource.hal", + "IOmxNode.hal", + "IOmxObserver.hal", + "IOmxProducerListener.hal", + ], +} + +genrule { + name: "android.hardware.media.omx@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.media.omx@1.0", + srcs: [ + ":android.hardware.media.omx@1.0_hal", + ], + out: [ + "android/hardware/media/omx/1.0/types.cpp", + "android/hardware/media/omx/1.0/GraphicBufferSourceAll.cpp", + "android/hardware/media/omx/1.0/OmxAll.cpp", + "android/hardware/media/omx/1.0/OmxBufferProducerAll.cpp", + "android/hardware/media/omx/1.0/OmxBufferSourceAll.cpp", + "android/hardware/media/omx/1.0/OmxNodeAll.cpp", + "android/hardware/media/omx/1.0/OmxObserverAll.cpp", + "android/hardware/media/omx/1.0/OmxProducerListenerAll.cpp", + ], +} + +genrule { + name: "android.hardware.media.omx@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.media.omx@1.0", + srcs: [ + ":android.hardware.media.omx@1.0_hal", + ], + out: [ + "android/hardware/media/omx/1.0/types.h", + "android/hardware/media/omx/1.0/IGraphicBufferSource.h", + "android/hardware/media/omx/1.0/IHwGraphicBufferSource.h", + "android/hardware/media/omx/1.0/BnHwGraphicBufferSource.h", + "android/hardware/media/omx/1.0/BpHwGraphicBufferSource.h", + "android/hardware/media/omx/1.0/BsGraphicBufferSource.h", + "android/hardware/media/omx/1.0/IOmx.h", + "android/hardware/media/omx/1.0/IHwOmx.h", + "android/hardware/media/omx/1.0/BnHwOmx.h", + "android/hardware/media/omx/1.0/BpHwOmx.h", + "android/hardware/media/omx/1.0/BsOmx.h", + "android/hardware/media/omx/1.0/IOmxBufferProducer.h", + "android/hardware/media/omx/1.0/IHwOmxBufferProducer.h", + "android/hardware/media/omx/1.0/BnHwOmxBufferProducer.h", + "android/hardware/media/omx/1.0/BpHwOmxBufferProducer.h", + "android/hardware/media/omx/1.0/BsOmxBufferProducer.h", + "android/hardware/media/omx/1.0/IOmxBufferSource.h", + "android/hardware/media/omx/1.0/IHwOmxBufferSource.h", + "android/hardware/media/omx/1.0/BnHwOmxBufferSource.h", + "android/hardware/media/omx/1.0/BpHwOmxBufferSource.h", + "android/hardware/media/omx/1.0/BsOmxBufferSource.h", + "android/hardware/media/omx/1.0/IOmxNode.h", + "android/hardware/media/omx/1.0/IHwOmxNode.h", + "android/hardware/media/omx/1.0/BnHwOmxNode.h", + "android/hardware/media/omx/1.0/BpHwOmxNode.h", + "android/hardware/media/omx/1.0/BsOmxNode.h", + "android/hardware/media/omx/1.0/IOmxObserver.h", + "android/hardware/media/omx/1.0/IHwOmxObserver.h", + "android/hardware/media/omx/1.0/BnHwOmxObserver.h", + "android/hardware/media/omx/1.0/BpHwOmxObserver.h", + "android/hardware/media/omx/1.0/BsOmxObserver.h", + "android/hardware/media/omx/1.0/IOmxProducerListener.h", + "android/hardware/media/omx/1.0/IHwOmxProducerListener.h", + "android/hardware/media/omx/1.0/BnHwOmxProducerListener.h", + "android/hardware/media/omx/1.0/BpHwOmxProducerListener.h", + "android/hardware/media/omx/1.0/BsOmxProducerListener.h", + ], +} + +cc_library_shared { + name: "android.hardware.media.omx@1.0", + generated_sources: ["android.hardware.media.omx@1.0_genc++"], + generated_headers: ["android.hardware.media.omx@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.media.omx@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.graphics.common@1.0", + "android.hardware.media@1.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.graphics.common@1.0", + "android.hardware.media@1.0", + "android.hidl.base@1.0", + ], +}
diff --git a/media/omx/1.0/IGraphicBufferSource.hal b/media/omx/1.0/IGraphicBufferSource.hal new file mode 100644 index 0000000..62073ad --- /dev/null +++ b/media/omx/1.0/IGraphicBufferSource.hal
@@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 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.media.omx@1.0; + +import android.hardware.graphics.common@1.0::Dataspace; + +import android.hardware.media@1.0::types; + +import IOmxNode; + +/** + * Ref: frameworks/av/media/libmedia/aidl/android/IGraphicBufferSource.aidl + * + * TODO: Add documentations. + */ +interface IGraphicBufferSource { + + configure(IOmxNode omxNode, Dataspace dataspace) generates (Status status); + + setSuspend(bool suspend, int64_t timeUs) generates (Status status); + + setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) generates (Status status); + + setMaxFps(float maxFps) generates (Status status); + + setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) generates (Status status); + + setStartTimeUs(int64_t startTimeUs) generates (Status status); + + setStopTimeUs(int64_t stopTimeUs) generates (Status status); + + setColorAspects(ColorAspects aspects) generates (Status status); + + setTimeOffsetUs(int64_t timeOffsetUs) generates (Status status); + + signalEndOfInputStream() generates (Status status); + +}; +
diff --git a/media/omx/1.0/IOmx.hal b/media/omx/1.0/IOmx.hal new file mode 100644 index 0000000..acb1aae --- /dev/null +++ b/media/omx/1.0/IOmx.hal
@@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016 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.media.omx@1.0; + +import android.hardware.media@1.0::types; + +import IOmxNode; +import IOmxObserver; +import IOmxBufferProducer; +import IGraphicBufferSource; + +/** + * Ref: frameworks/av/include/media/IOMX.h: IOMX + * + * IOmx is the main entry point for communicating with OMX components. + */ +interface IOmx { + + /** + * Information for an IOmxNode component. + */ + struct ComponentInfo { + string mName; + vec<string> mRoles; + }; + + /** + * List available components. + * + * @param[out] status The status of the call. + * @param[out] nodeList The list of ComponentInfo. + */ + listNodes( + ) generates ( + Status status, + vec<ComponentInfo> nodeList + ); + + /** + * Allocate an IOmxNode instance with the specified component name. + * + * @param[in] name The name of the component to create. + * @param[in] observer An observer object that will receive messages from + * the created instance. + * @param[out] status The status of the call. + * @param[out] omxNode The allocated instance of IOmxNode. + */ + allocateNode( + string name, + IOmxObserver observer + ) generates ( + Status status, + IOmxNode omxNode + ); + + /** + * Create an input surface for recording. + * + * @param[out] producer The associated producer end of the buffer queue. + * @param[out] source The associated `IGraphicBufferSource`. + */ + createInputSurface( + ) generates ( + Status status, + IOmxBufferProducer producer, + IGraphicBufferSource source + ); +}; +
diff --git a/media/omx/1.0/IOmxBufferProducer.hal b/media/omx/1.0/IOmxBufferProducer.hal new file mode 100644 index 0000000..7e2172b --- /dev/null +++ b/media/omx/1.0/IOmxBufferProducer.hal
@@ -0,0 +1,709 @@ +/* + * Copyright (C) 2016 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.media.omx@1.0; + +import android.hardware.graphics.common@1.0::Dataspace; +import android.hardware.graphics.common@1.0::PixelFormat; + +import android.hardware.media@1.0::types; +import IOmxProducerListener; + +/** + * Ref: frameworks/native/include/gui/IGraphicBufferProducer.h: + * IGraphicBufferProducer + * This is a wrapper/wrapped HAL interface for the actual binder interface. + */ +interface IOmxBufferProducer { + + /** + * Ref: frameworks/native/include/ui/FenceTime.h: FenceTime::Snapshot + * + * An atomic snapshot of the FenceTime that is flattenable. + */ + struct FenceTimeSnapshot { + enum State : int32_t { + EMPTY, + FENCE, + SIGNAL_TIME, + }; + State state; + Fence fence; + int64_t signalTimeNs; + }; + + /** + * Ref: frameworks/native/include/gui/FrameTimestamp.h: FrameEventsDelta + * + * A single frame update from the consumer to producer that can be sent + * through a HIDL interface. Although this may be sent multiple times for + * the same frame as new timestamps are set, Fences only need to be sent + * once. + */ + struct FrameEventsDelta { + uint32_t index; + uint64_t frameNumber; + bool addPostCompositeCalled; + bool addRetireCalled; + bool addReleaseCalled; + int64_t postedTimeNs; + int64_t requestedPresentTimeNs; + int64_t latchTimeNs; + int64_t firstRefreshStartTimeNs; + int64_t lastRefreshStartTimeNs; + int64_t dequeueReadyTime; + FenceTimeSnapshot gpuCompositionDoneFence; + FenceTimeSnapshot displayPresentFence; + FenceTimeSnapshot displayRetireFence; + FenceTimeSnapshot releaseFence; + }; + + /** + * Ref: frameworks/native/include/gui/FrameTimestamp.h: CompositorTiming + * + * The most recent compositor timing info sent from consumer to producer + * through a HIDL interface. + */ + struct CompositorTiming { + int64_t deadlineNs; + int64_t intervalNs; + int64_t presentLatencyNs; + }; + + /** + * Ref: frameworks/native/include/gui/FrameTimestamp.h: FrameEventHistoryDelta + * + * A collection of updates from consumer to producer that can be sent + * through a HIDL interface. + */ + struct FrameEventHistoryDelta { + vec<FrameEventsDelta> deltas; + CompositorTiming compositorTiming; + }; + + /** + * Modes for disconnection. + */ + enum DisconnectMode : int32_t { + /** Disconnect only the specified API. */ + API, + /** Disconnect any API originally connected from the process calling + * disconnect. */ + ALL_LOCAL + }; + + struct QueueBufferInput { + /** A monotonically increasing value in nanoseconds. */ + int64_t timestamp; + /** Whether the timestamp was synthesized at queue time. */ + int32_t isAutoTimestamp; + /** Description of the contents, interpretation depends on format. */ + Dataspace dataSpace; + /** A crop rectangle that's used as a hint to the consumer. */ + Rect crop; + /** A set of flags from NATIVE_WINDOW_SCALING_* in <window.h>. */ + int32_t scalingMode; + /** A set of flags from NATIVE_WINDOW_TRANSFORM_* in <window.h>. */ + uint32_t transform; + /** The sticky transform set in Surface (only used by the LEGACY camera + * mode). */ + uint32_t stickyTransform; + /** A fence that the consumer must wait on before reading the buffer; + * set this to Fence::NO_FENCE if the buffer is ready immediately. */ + Fence fence; + Region surfaceDamage; + /** Whether or not the latest frame timestamps should be retrieved from + * the consumer. */ + bool getFrameTimestamps; + }; + + struct QueueBufferOutput { + uint32_t width; + uint32_t height; + uint32_t transformHint; + uint32_t numPendingBuffers; + uint64_t nextFrameNumber; + bool bufferReplaced; + FrameEventHistoryDelta frameTimestamps; + }; + + /** + * requestBuffer requests a new buffer for the given index. The server (i.e. + * the IOmxBufferProducer implementation) assigns the newly created + * buffer to the given slot index, and the client is expected to mirror the + * slot->buffer mapping so that it's not necessary to transfer an + * AnwBuffer for every dequeue operation. + * + * The slot must be in the range of [0, NUM_BUFFER_SLOTS). + * + * Return of a value other than NO_ERROR means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned or the producer is not + * connected. + * * BAD_VALUE - one of the two conditions occurred: + * * slot was out of range (see above) + * * buffer specified by the slot is not dequeued + */ + requestBuffer( + int32_t slot + ) generates ( + Status status, + AnwBuffer buffer + ); + + /** + * setMaxDequeuedBufferCount sets the maximum number of buffers that can be + * dequeued by the producer at one time. If this method succeeds, any new + * buffer slots will be both unallocated and owned by the BufferQueue object + * (i.e. they are not owned by the producer or consumer). Calling this may + * also cause some buffer slots to be emptied. If the caller is caching the + * contents of the buffer slots, it should empty that cache after calling + * this method. + * + * This function should not be called with a value of maxDequeuedBuffers + * that is less than the number of currently dequeued buffer slots. Doing so + * will result in a BAD_VALUE error. + * + * The buffer count should be at least 1 (inclusive), but at most + * (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The + * minimum undequeued buffer count can be obtained by calling + * query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS). + * + * Return of a value other than NO_ERROR means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned. + * * BAD_VALUE - one of the below conditions occurred: + * * bufferCount was out of range (see above). + * * client would have more than the requested number of dequeued + * buffers after this call. + * * this call would cause the maxBufferCount value to be exceeded. + * * failure to adjust the number of available slots. + */ + setMaxDequeuedBufferCount( + int32_t maxDequeuedBuffers + ) generates ( + Status status + ); + + /** + * Set the async flag if the producer intends to asynchronously queue + * buffers without blocking. Typically this is used for triple-buffering + * and/or when the swap interval is set to zero. + * + * Enabling async mode will internally allocate an additional buffer to + * allow for the asynchronous behavior. If it is not enabled queue/dequeue + * calls may block. + * + * Return of a value other than NO_ERROR means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned. + * * BAD_VALUE - one of the following has occurred: + * * this call would cause the maxBufferCount value to be + * exceeded + * * failure to adjust the number of available slots. + */ + setAsyncMode( + bool async + ) generates ( + Status status + ); + + /** + * dequeueBuffer requests a new buffer slot for the client to use. Ownership + * of the slot is transfered to the client, meaning that the server will not + * use the contents of the buffer associated with that slot. + * + * The slot index returned may or may not contain a buffer (client-side). + * If the slot is empty the client should call requestBuffer to assign a new + * buffer to that slot. + * + * Once the client is done filling this buffer, it is expected to transfer + * buffer ownership back to the server with either cancelBuffer on + * the dequeued slot or to fill in the contents of its associated buffer + * contents and call queueBuffer. + * + * If dequeueBuffer returns the BUFFER_NEEDS_REALLOCATION flag, the client is + * expected to call requestBuffer immediately. + * + * If dequeueBuffer returns the RELEASE_ALL_BUFFERS flag, the client is + * expected to release all of the mirrored slot->buffer mappings. + * + * The fence parameter will be updated to hold the fence associated with + * the buffer. The contents of the buffer must not be overwritten until the + * fence signals. If the fence is Fence::NO_FENCE, the buffer may be written + * immediately. + * + * The width and height parameters must be no greater than the minimum of + * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). + * An error due to invalid dimensions might not be reported until + * updateTexImage() is called. If width and height are both zero, the + * default values specified by setDefaultBufferSize() are used instead. + * + * If the format is 0, the default format will be used. + * + * The usage argument specifies gralloc buffer usage flags. The values + * are enumerated in <gralloc.h>, e.g. GRALLOC_USAGE_HW_RENDER. These + * will be merged with the usage flags specified by + * IGraphicBufferConsumer::setConsumerUsageBits. + * + * This call will block until a buffer is available to be dequeued. If + * both the producer and consumer are controlled by the app, then this call + * can never block and will return WOULD_BLOCK if no buffer is available. + * + * A non-negative value with flags set (see above) will be returned upon + * success as status. + * + * Return of a negative means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned or the producer is not + * connected. + * * BAD_VALUE - both in async mode and buffer count was less than the + * max numbers of buffers that can be allocated at once. + * * INVALID_OPERATION - cannot attach the buffer because it would cause + * too many buffers to be dequeued, either because + * the producer already has a single buffer dequeued + * and did not set a buffer count, or because a + * buffer count was set and this call would cause + * it to be exceeded. + * * WOULD_BLOCK - no buffer is currently available, and blocking is disabled + * since both the producer/consumer are controlled by app + * * NO_MEMORY - out of memory, cannot allocate the graphics buffer. + * * TIMED_OUT - the timeout set by setDequeueTimeout was exceeded while + * waiting for a buffer to become available. + * + * All other negative values are an unknown error returned downstream + * from the graphics allocator (typically errno). + */ + dequeueBuffer( + uint32_t width, + uint32_t height, + PixelFormat format, + uint32_t usage, + bool getFrameTimestamps + ) generates ( + Status status, + int32_t slot, + Fence fence, + FrameEventHistoryDelta outTimestamps + ); + + /** + * detachBuffer attempts to remove all ownership of the buffer in the given + * slot from the buffer queue. If this call succeeds, the slot will be + * freed, and there will be no way to obtain the buffer from this interface. + * The freed slot will remain unallocated until either it is selected to + * hold a freshly allocated buffer in dequeueBuffer or a buffer is attached + * to the slot. The buffer must have already been dequeued, and the caller + * must already possesses the sp<AnwBuffer> (i.e., must have called + * requestBuffer). + * + * Return of a value other than NO_ERROR means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned or the producer is not + * connected. + * * BAD_VALUE - the given slot number is invalid, either because it is + * out of the range [0, NUM_BUFFER_SLOTS), or because the slot + * it refers to is not currently dequeued and requested. + */ + detachBuffer( + int32_t slot + ) generates ( + Status status + ); + + /** + * detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer, + * and detachBuffer in sequence, except for two things: + * + * 1) It is unnecessary to know the dimensions, format, or usage of the + * next buffer. + * 2) It will not block, since if it cannot find an appropriate buffer to + * return, it will return an error instead. + * + * Only slots that are free but still contain an AnwBuffer will be + * considered, and the oldest of those will be returned. buffer is + * equivalent to buffer from the requestBuffer call, and fence is + * equivalent to fence from the dequeueBuffer call. + * + * Return of a value other than NO_ERROR means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned or the producer is not + * connected. + * * BAD_VALUE - either outBuffer or outFence were NULL. + * * NO_MEMORY - no slots were found that were both free and contained a + * AnwBuffer. + */ + detachNextBuffer( + ) generates ( + Status status, + AnwBuffer buffer, + Fence fence + ); + + /** + * attachBuffer attempts to transfer ownership of a buffer to the buffer + * queue. If this call succeeds, it will be as if this buffer was dequeued + * from the returned slot number. As such, this call will fail if attaching + * this buffer would cause too many buffers to be simultaneously dequeued. + * + * If attachBuffer returns the RELEASE_ALL_BUFFERS flag, the caller is + * expected to release all of the mirrored slot->buffer mappings. + * + * A non-negative value with flags set (see above) will be returned upon + * success. + * + * Return of a negative value means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned or the producer is not + * connected. + * * BAD_VALUE - outSlot or buffer were NULL, invalid combination of + * async mode and buffer count override, or the generation + * number of the buffer did not match the buffer queue. + * * INVALID_OPERATION - cannot attach the buffer because it would cause + * too many buffers to be dequeued, either because + * the producer already has a single buffer dequeued + * and did not set a buffer count, or because a + * buffer count was set and this call would cause + * it to be exceeded. + * * WOULD_BLOCK - no buffer slot is currently available, and blocking is + * disabled since both the producer/consumer are + * controlled by the app. + * * TIMED_OUT - the timeout set by setDequeueTimeout was exceeded while + * waiting for a slot to become available. + */ + attachBuffer( + AnwBuffer buffer + ) generates ( + Status status, + int32_t slot + ); + + /** + * queueBuffer indicates that the client has finished filling in the + * contents of the buffer associated with slot and transfers ownership of + * that slot back to the server. + * + * It is not valid to call queueBuffer on a slot that is not owned + * by the client or one for which a buffer associated via requestBuffer + * (an attempt to do so will fail with a return value of BAD_VALUE). + * + * In addition, the input must be described by the client (as documented + * below). Any other properties (zero point, etc) + * are client-dependent, and should be documented by the client. + * + * The slot must be in the range of [0, NUM_BUFFER_SLOTS). + * + * Upon success, the output will be filled with meaningful values + * (refer to the documentation below). + * + * Return of a value other than NO_ERROR means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned or the producer is not + * connected. + * * BAD_VALUE - one of the below conditions occurred: + * * fence was NULL + * * scaling mode was unknown + * * both in async mode and buffer count was less than the + * max numbers of buffers that can be allocated at once + * * slot index was out of range (see above). + * * the slot was not in the dequeued state + * * the slot was enqueued without requesting a buffer + * * crop rect is out of bounds of the buffer dimensions + */ + queueBuffer( + int32_t slot, + QueueBufferInput input + ) generates ( + Status status, + QueueBufferOutput output + ); + + /** + * cancelBuffer indicates that the client does not wish to fill in the + * buffer associated with slot and transfers ownership of the slot back to + * the server. + * + * The buffer is not queued for use by the consumer. + * + * The slot must be in the range of [0, NUM_BUFFER_SLOTS). + * + * The buffer will not be overwritten until the fence signals. The fence + * will usually be the one obtained from dequeueBuffer. + * + * Return of a value other than NO_ERROR means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned or the producer is not + * connected. + * * BAD_VALUE - one of the below conditions occurred: + * * fence was NULL + * * slot index was out of range (see above). + * * the slot was not in the dequeued state + */ + cancelBuffer( + int32_t slot, + Fence fence + ) generates ( + Status status + ); + + /** + * query retrieves some information for this surface + * 'what' tokens allowed are that of NATIVE_WINDOW_* in <window.h> + * + * Return of a value other than NO_ERROR means an error has occurred: + * * NO_INIT - the buffer queue has been abandoned. + * * BAD_VALUE - what was out of range + */ + query( + int32_t what + ) generates ( + int32_t result, + int32_t value + ); + + /** + * connect attempts to connect a client API to the IOmxBufferProducer. + * This must be called before any other IOmxBufferProducer methods are + * called except for getAllocator. A consumer must be already connected. + * + * This method will fail if the connect was previously called on the + * IOmxBufferProducer and no corresponding disconnect call was made. + * + * The listener is an optional binder callback object that can be used if + * the producer wants to be notified when the consumer releases a buffer + * back to the BufferQueue. It is also used to detect the death of the + * producer. If only the latter functionality is desired, there is a + * DummyProducerListener class in IProducerListener.h that can be used. + * + * The api should be one of the NATIVE_WINDOW_API_* values in <window.h> + * + * The producerControlledByApp should be set to true if the producer is hosted + * by an untrusted process (typically app_process-forked processes). If both + * the producer and the consumer are app-controlled then all buffer queues + * will operate in async mode regardless of the async flag. + * + * Upon success, the output will be filled with meaningful data + * (refer to QueueBufferOutput documentation above). + * + * Return of a value other than NO_ERROR means an error has occurred: + * * NO_INIT - one of the following occurred: + * * the buffer queue was abandoned + * * no consumer has yet connected + * * BAD_VALUE - one of the following has occurred: + * * the producer is already connected + * * api was out of range (see above). + * * output was NULL. + * * Failure to adjust the number of available slots. This can + * happen because of trying to allocate/deallocate the async + * buffer in response to the value of producerControlledByApp. + * * DEAD_OBJECT - the token is hosted by an already-dead process + * + * Additional negative errors may be returned by the internals, they + * should be treated as opaque fatal unrecoverable errors. + */ + connect( + IOmxProducerListener listener, + int32_t api, + bool producerControlledByApp + ) generates ( + Status status, + QueueBufferOutput output + ); + + /** + * disconnect attempts to disconnect a client API from the + * IOmxBufferProducer. Calling this method will cause any subsequent + * calls to other IOmxBufferProducer methods to fail except for + * getAllocator and connect. Successfully calling connect after this will + * allow the other methods to succeed again. + * + * The api should be one of the NATIVE_WINDOW_API_* values in <window.h> + * + * Alternatively if mode is AllLocal, then the API value is ignored, and any API + * connected from the same PID calling disconnect will be disconnected. + * + * Disconnecting from an abandoned IOmxBufferProducer is legal and + * is considered a no-op. + * + * Return of a value other than NO_ERROR means an error has occurred: + * * BAD_VALUE - one of the following has occurred: + * * the api specified does not match the one that was connected + * * api was out of range (see above). + * * DEAD_OBJECT - the token is hosted by an already-dead process + */ + disconnect( + int32_t api, + DisconnectMode mode /* = DisconnectMode::API */ + ) generates ( + Status status + ); + + /** + * Attaches a sideband buffer stream to the IOmxBufferProducer. + * + * A sideband stream is a device-specific mechanism for passing buffers + * from the producer to the consumer without using dequeueBuffer/ + * queueBuffer. If a sideband stream is present, the consumer can choose + * whether to acquire buffers from the sideband stream or from the queued + * buffers. + * + * Passing NULL or a different stream handle will detach the previous + * handle if any. + */ + setSidebandStream( + handle stream + ) generates ( + Status status + ); + + /** + * Allocates buffers based on the given dimensions/format. + * + * This function will allocate up to the maximum number of buffers + * permitted by the current BufferQueue configuration. It will use the + * given format, dimensions, and usage bits, which are interpreted in the + * same way as for dequeueBuffer, and the async flag must be set the same + * way as for dequeueBuffer to ensure that the correct number of buffers are + * allocated. This is most useful to avoid an allocation delay during + * dequeueBuffer. If there are already the maximum number of buffers + * allocated, this function has no effect. + */ + allocateBuffers( + uint32_t width, + uint32_t height, + PixelFormat format, + uint32_t usage + ); + + /** + * Sets whether dequeueBuffer is allowed to allocate new buffers. + * + * Normally dequeueBuffer does not discriminate between free slots which + * already have an allocated buffer and those which do not, and will + * allocate a new buffer if the slot doesn't have a buffer or if the slot's + * buffer doesn't match the requested size, format, or usage. This method + * allows the producer to restrict the eligible slots to those which already + * have an allocated buffer of the correct size, format, and usage. If no + * eligible slot is available, dequeueBuffer will block or return an error + * as usual. + */ + allowAllocation( + bool allow + ) generates ( + Status status + ); + + /** + * Sets the current generation number of the BufferQueue. + * + * This generation number will be inserted into any buffers allocated by the + * BufferQueue, and any attempts to attach a buffer with a different + * generation number will fail. Buffers already in the queue are not + * affected and will retain their current generation number. The generation + * number defaults to 0. + */ + setGenerationNumber( + uint32_t generationNumber + ) generates ( + Status status + ); + + /** + * Returns the name of the connected consumer. + */ + getConsumerName( + ) generates ( + string name + ); + + /** + * Used to enable/disable shared buffer mode. + * + * When shared buffer mode is enabled the first buffer that is queued or + * dequeued will be cached and returned to all subsequent calls to + * dequeueBuffer and acquireBuffer. This allows the producer and consumer to + * simultaneously access the same buffer. + */ + setSharedBufferMode( + bool sharedBufferMode + ) generates ( + Status status + ); + + /** + * Used to enable/disable auto-refresh. + * + * Auto refresh has no effect outside of shared buffer mode. In shared + * buffer mode, when enabled, it indicates to the consumer that it should + * attempt to acquire buffers even if it is not aware of any being + * available. + */ + setAutoRefresh( + bool autoRefresh + ) generates ( + Status status + ); + + /** + * Sets how long dequeueBuffer will wait for a buffer to become available + * before returning an error (TIMED_OUT). + * + * This timeout also affects the attachBuffer call, which will block if + * there is not a free slot available into which the attached buffer can be + * placed. + * + * By default, the BufferQueue will wait forever, which is indicated by a + * timeout of -1. If set (to a value other than -1), this will disable + * non-blocking mode and its corresponding spare buffer (which is used to + * ensure a buffer is always available). + * + * Return of a value other than NO_ERROR means an error has occurred: + * * BAD_VALUE - Failure to adjust the number of available slots. This can + * happen because of trying to allocate/deallocate the async + * buffer. + */ + setDequeueTimeout( + int64_t timeoutNs + ) generates ( + Status status + ); + + /** + * Returns the last queued buffer along with a fence which must signal + * before the contents of the buffer are read. If there are no buffers in + * the queue, buffer.nativeHandle and fence will be null handles. + * + * transformMatrix is meaningless if buffer.nativeHandle is null. + */ + getLastQueuedBuffer( + ) generates ( + Status status, + AnwBuffer buffer, + Fence fence, + float[16] transformMatrix + ); + + /** + * Gets the frame events that haven't already been retrieved. + */ + getFrameTimestamps( + ) generates ( + FrameEventHistoryDelta timeStamps + ); + + /** + * Returns a unique id for this BufferQueue. + */ + getUniqueId( + ) generates ( + Status status, + uint64_t outId + ); + +}; + +
diff --git a/media/omx/1.0/IOmxBufferSource.hal b/media/omx/1.0/IOmxBufferSource.hal new file mode 100644 index 0000000..94c43fc --- /dev/null +++ b/media/omx/1.0/IOmxBufferSource.hal
@@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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.media.omx@1.0; + +import android.hardware.media@1.0::types; + +/** + * Ref: frameworks/av/media/libmedia/aidl/android/IOMXBufferSource.aidl + * + * IOmxBufferSource is an interface for a listener for certain events from an + * IOmxNode instance. Use IOmxNode::setInputSurface() to attach an + * IOmxBufferSource instance to an IOmxNode instance. + * + * @see OMX_STATETYPE in the OpenMax IL standard. + */ +interface IOmxBufferSource { + + /** + * onOmxExecuting() is invoked when the node state changes to + * OMX_StateExecuting state. + */ + oneway onOmxExecuting(); + + /** + * onOmxIdle() is invoked when the node transitions from OMX_StateExecuting + * to OMX_StateIdle. + */ + oneway onOmxIdle(); + + /** + * onOmxLoaded() is invoked when the node transitions from OMX_StateIdle or + * OMX_StateExecuting to OMX_StateLoaded. + */ + oneway onOmxLoaded(); + + /** + * onInputBufferAdded() is invoked after a new input buffer is added to the + * node. This may happen within IOmxNode::allocateSecureBuffer() or + * IOmxNode::useBuffer(). + * + * @param[in] buffer is the id of the added buffer. + */ + oneway onInputBufferAdded(BufferId buffer); + + /** + * onInputBufferEmptied() is invoked after an input buffer is emptied. This + * may happen within IOmxNode::emptyBuffer(). + * + * @param[in] buffer is the id of the emptied buffer. + * @param[in] fence is the fence associated with the buffer. + */ + oneway onInputBufferEmptied(BufferId buffer, Fence fence); +}; +
diff --git a/media/omx/1.0/IOmxNode.hal b/media/omx/1.0/IOmxNode.hal new file mode 100644 index 0000000..8729637 --- /dev/null +++ b/media/omx/1.0/IOmxNode.hal
@@ -0,0 +1,365 @@ +/* + * Copyright (C) 2016 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.media.omx@1.0; + +import IOmxBufferSource; + +import android.hardware.media@1.0::types; + +/** + * Ref: frameworks/av/include/media/IOMX.h: IOMXNode + * Ref: https://www.khronos.org/registry/omxil/specs/OpenMAX_IL_1_1_2_Specification.pdf + */ + +/** + * IOmxNode is an interface for communicating with an OMX component (called + * "node" here) that has been previously obtained by calling + * IOmx::allocateNode(). + */ +interface IOmxNode { + + /** + * Free the node. + * + * @param[out] status Status of the call. + */ + freeNode( + ) generates ( + Status status + ); + + /** + * Invoke a command on the node. + * + * @param[in] cmd Type of the command. + * @param[in] param Parameter for the command. + * @param[out] status Status of the call. + * + * @see OMX_SendCommand() in the OpenMax IL standard. + */ + sendCommand( + uint32_t cmd, + int32_t param + ) generates ( + Status status + ); + + /** + * Retrieve a parameter setting from the node. + * + * @param[in] index Type of the parameter to retrieve. + * @param[in] inParams Information about the retrieval. + * @param[out] status Status of the call. + * @param[out] outParams Current parameter setting. + * + * @see OMX_GetParameter() in the OpenMax IL standard. + */ + getParameter( + uint32_t index, + Bytes inParams + ) generates ( + Status status, + Bytes outParams + ); + + /** + * Change a parameter setting of the node. + * + * @param[in] index Type of the parameter to change. + * @param[in] params New parameter setting. + * @param[out] status Status of the call. + * + * @see OMX_SetParameter() in the OpenMax IL standard. + */ + setParameter( + uint32_t index, + Bytes params + ) generates ( + Status status + ); + + /** + * Retrieve a configuration from the node. + * + * @param[in] index Type of the configuration to retrieve. + * @param[in] inConfig Information about the retrieval. + * @param[out] status Status of the call. + * @param[out] outConfig Current configuration. + * + * @see OMX_GetConfig() in the OpenMax IL standard. + */ + getConfig( + uint32_t index, + Bytes inConfig + ) generates ( + Status status, + Bytes outConfig + ); + + /** + * Change a configuration of the node. + * + * @param[in] index Type of the configuration to change. + * @param[in] config New configuration. + * @param[out] status Status of the call. + * + * @see OMX_SetConfig() in the OpenMax IL standard. + */ + setConfig( + uint32_t index, + Bytes config + ) generates ( + Status status + ); + + /** + * Set the mode of a port on the node. + * + * @param[in] portIndex Index of the port. + * @param[in] mode Target mode on the specified port. + * @param[out] status Status of the call. + */ + setPortMode( + uint32_t portIndex, + PortMode mode + ) generates ( + Status status + ); + + /** + * Prepare a port for adaptive playback. This is based on the extension + * "OMX.google.android.index.prepareForAdaptivePlayback". + * + * @param[in] portIndex Index of the port. + * @param[in] enable Whether the adaptive playback is enabled or not. + * @param[in] maxFrameWidth Maximum frame width. + * @param[in] maxFrameHeight Maximum frame height. + * @param[out] status Status of the call. + */ + prepareForAdaptivePlayback( + uint32_t portIndex, + bool enable, + uint32_t maxFrameWidth, + uint32_t maxFrameHeight + ) generates ( + Status status + ); + + /** + * Configure a port for a tunneled playback mode. This is based on the + * extension "OMX.google.android.index.configureVideoTunnelMode". + * + * @param[in] portIndex Index of the port. + * @param[in] tunneled Whether the tunneled mode is used or not. + * @param[in] audioHwSync HW SYNC ID of the audio HAL output stream to sync + * the video with. + * @param[out] status Status of the call. + * @param[out] sidebandHandle Codec-allocated sideband window handle. + */ + configureVideoTunnelMode( + uint32_t portIndex, + bool tunneled, + uint32_t audioHwSync + ) generates ( + Status status, + handle sidebandHandle + ); + + /** + * Retrieve the buffer usage on a port. This is based on the extension + * "OMX.google.android.index.getAndroidNativeBufferUsage". + * + * @param[in] portIndex Index of the port. + * @param[out] status Status of the call. + * @param[out] usage Current graphic buffer usage. + */ + getGraphicBufferUsage( + uint32_t portIndex + ) generates ( + Status status, + uint32_t usage + ); + + /** + * Set up a listener to events related to the input surface. + * + * @param[in] bufferSource Listener object that implements + * IOmxBufferSource. + * @param[out] status Status of the call. + * + * @see IOmxBufferSource. + */ + setInputSurface( + IOmxBufferSource bufferSource + ) generates ( + Status status + ); + + /** + * Allocate an opaque buffer on a port as a native handle. + * + * @param[in] portIndex Index of the port. + * @param[in] size Desired size of the buffer. + * @param[out] status Status of the call. + * @param[out] buffer Id of the allocated buffer, which will be needed in + * other buffer-related functions. + * @param[out] nativeHandle Native handle of the allocated buffer. + * + * @see OMX_AllocateBuffer() in the OpenMax IL standard. + */ + allocateSecureBuffer( + uint32_t portIndex, + uint64_t size + ) generates ( + Status status, + BufferId buffer, + handle nativeHandle + ); + + /** + * Assign a buffer to a port. + * + * @param[in] portIndex Index of the port. + * @param[in] omxBuffer Buffer to be assigned to the port. + * @param[out] status Status of the call. + * @param[out] buffer Id of the assigned buffer, which will be needed in + * other buffer-related functions. + * + * @see OMX_UseBuffer() in the OpenMax IL standard. + */ + useBuffer( + uint32_t portIndex, + CodecBuffer omxBuffer + ) generates ( + Status status, + BufferId buffer + ); + + /** + * Free a buffer previously assigned to a port by allocateSecureBuffer() or + * useBuffer(). + * + * @param[in] portIndex Index of the port. + * @param[in] buffer Id of the buffer to be freed. + * @param[out] status Status of the call. + * + * @see OMX_FreeBuffer() in the OpenMax IL standard. + */ + freeBuffer( + uint32_t portIndex, + BufferId buffer + ) generates ( + Status status + ); + + /** + * Pass \p fence to the node if it supports fences. Otherwise, it waits on + * \p fence before calling OMX_FillThisBuffer(). The node will take + * ownership of the fence even if this call fails. + * + * If the port is in metadata mode, the buffer will be updated to point to + * the new buffer passed in via \p omxBuffer before OMX_FillThisBuffer() is + * called. Otherwise, \p omxBuffer is not used. + * + * @param[in] buffer Id of the buffer to fill. + * @param[in] omxBuffer New buffer information (in metadata mode). + * @param[in] fence Fence to wait for (if not null). + * @param[out] status Status of the call. + * + * @see OMX_FillThisBuffer() in the OpenMax IL standard. + */ + fillBuffer( + BufferId buffer, + CodecBuffer omxBuffer, + Fence fence + ) generates ( + Status status + ); + + /** + * Pass \p fence to the node if it supports fences. Otherwise, wait on + * \p fence before calling OMX_EmptyThisBuffer(). The node will take + * ownership of the fence even if this call fails. + * + * If the port is in metadata mode, the buffer will be updated to point to + * the new buffer passed in via \p omxBuffer before OMX_EmptyThisBuffer() is + * called. Otherwise, \p omxBuffer is not used. + * + * @param[in] buffer Id of the buffer to fill. + * @param[in] omxBuffer New buffer information (in metadata mode). + * @param[in] flags Flags to be passed to OMX_EmptyBuffer(). + * @param[in] timestampUs Timestamp OMX_EmptyBuffer(). + * @param[in] fence Fence to wait for (if not null). + * @param[out] status Status of the call. + * + * @see OMX_EmptyThisBuffer() in the OpenMax IL standard. + */ + emptyBuffer( + BufferId buffer, + CodecBuffer omxBuffer, + uint32_t flags, + uint64_t timestampUs, + Fence fence + ) generates ( + Status status + ); + + /** + * Request the node to translate an extension string to an index. + * + * @param[in] parameterName Requested extension string. + * @param[out] status Status of the call. + * @param[out] index Translated index. + * + * @see OMX_GetExtensionIndex() in the OpenMax IL standard. + */ + getExtensionIndex( + string parameterName + ) generates ( + Status status, + uint32_t index + ); + + /** + * Add an OMX message on the node's message queue. The instance of + * IOmxObserver that was obtained during the creation of the node will + * receive the message in batches by the callback + * IOmxObserver::onMessages(). + * + * @param[in] msg Message to send. + * @param[out] status Status of the call. + * + * @see IOmxObserver::onMessages(). + */ + dispatchMessage( + Message msg + ) generates ( + Status status + ); + + /** + * Set quirks. + * + * @param[in] quirks Quirks for the component, generally obtained from + * MediaCodecList::getQuirksFor(). + */ + oneway setQuirks( + uint32_t quirks + ); + +}; +
diff --git a/media/omx/1.0/IOmxObserver.hal b/media/omx/1.0/IOmxObserver.hal new file mode 100644 index 0000000..c26a937 --- /dev/null +++ b/media/omx/1.0/IOmxObserver.hal
@@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 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.media.omx@1.0; + +/** + * Ref: frameworks/av/include/media/IOMX.h: IOMXObserver + */ + +/** + * IOmxObserver is a listener interface for OMX messages sent from an IOmxNode + * stance. + */ +interface IOmxObserver { + + /** + * Invoked to process messages from an IOmxNode instance. Note that messages + * come in batches. + */ + oneway onMessages(vec<Message> messages); +}; +
diff --git a/media/omx/1.0/IOmxProducerListener.hal b/media/omx/1.0/IOmxProducerListener.hal new file mode 100644 index 0000000..7fde93b --- /dev/null +++ b/media/omx/1.0/IOmxProducerListener.hal
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 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.media.omx@1.0; + +/** + * Ref: frameworks/native/include/gui/IProducerListener.h: IProducerListener + * This is a wrapper/wrapped HAL interface for the actual binder interface. + */ +interface IOmxProducerListener { + oneway onBufferReleased(); + needsReleaseNotify() generates (bool result); +}; +
diff --git a/media/omx/1.0/types.hal b/media/omx/1.0/types.hal new file mode 100644 index 0000000..5413344 --- /dev/null +++ b/media/omx/1.0/types.hal
@@ -0,0 +1,277 @@ +/* + * Copyright (C) 2016 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.media.omx@1.0; + +import android.hardware.media@1.0::types; + +// Aliases +typedef uint32_t BufferId; + +/** + * Ref: system/core/include/utils/Errors.h + * Ref: bionic/libc/kernel/uapi/asm-generic/errno-base.h + * Ref: bionic/libc/kernel/uapi/asm-generic/errno.h + * Ref: frameworks/av/include/media/stagefright/MediaError.h + * Ref: frameworks/av/media/libstagefright/omx/OMXUtils.cpp: StatusFromOMXError + */ +enum Status : int32_t { + OK = 0, + NO_ERROR = 0, + + NAME_NOT_FOUND = -2, + WOULD_BLOCK = -11, + NO_MEMORY = -12, + NO_INIT = -19, + BAD_VALUE = -22, + DEAD_OBJECT = -32, + INVALID_OPERATION = -38, + TIMED_OUT = -110, + ERROR_UNSUPPORTED = -1010, + UNKNOWN_ERROR = -2147483648, + + BUFFER_NEEDS_REALLOCATION = 0x1, + RELEASE_ALL_BUFFERS = 0x2, +}; + +/** + * Ref: frameworks/av/include/media/IOMX.h: omx_message + * + * Data structure for an OMX message. This is essentially a union of different + * message types. + */ +struct Message { + + /** + * There are four main types of messages. + */ + enum Type : uint32_t { + EVENT, + EMPTY_BUFFER_DONE, + FILL_BUFFER_DONE, + FRAME_RENDERED, + }; + + /** + * @see OMX_EVENTTYPE in the OpenMax IL standard. + */ + struct EventData { + uint32_t event; // TODO: if there are common core events, convert to an enum or point to std + uint32_t data1; + uint32_t data2; + uint32_t data3; + uint32_t data4; + }; + + struct BufferData { + BufferId buffer; + }; + + struct ExtendedBufferData { + BufferId buffer; + uint32_t rangeOffset; + uint32_t rangeLength; + uint32_t flags; // TODO: if common flags exist, define an enum of point to std + uint64_t timestampUs; + }; + + struct RenderData { + uint64_t timestampUs; + int64_t systemTimeNs; + }; + + union Data { + // if type == EVENT + EventData eventData; + + // if type == EMPTY_BUFFER_DONE + BufferData bufferData; + + // if type == FILL_BUFFER_DONE + ExtendedBufferData extendedBufferData; + + // if type == FRAME_RENDERED + RenderData renderData; + }; + + /** + * The type of the message. + */ + Type type; + + /** + * The fence associated with the message. + */ + Fence fence; + + /** + * The union of data, discriminated by type. + */ + Data data; +}; + +/** + * Ref: frameworks/native/include/ui/GraphicBuffer.h + * Ref: system/core/include/system/window.h + * Ref: frameworks/native/include/binder/IMemory.h + * Ref: frameworks/native/libs/binder/IMemory.cpp + * Ref: frameworks/av/include/media/OMXBuffer.h + * + * Data structure for buffer information. This is essentially a union of + * different buffer types. + */ +struct CodecBuffer { + + /** + * There are four main types of buffers. + */ + enum Type : int32_t { + INVALID = 0, + PRESET, + SHARED_MEM, + ANW_BUFFER, + NATIVE_HANDLE, + }; + + struct PresetAttributes { + uint32_t rangeOffset; + uint32_t rangeLength; + }; + + union Attributes { + // if bufferType == PRESET + PresetAttributes preset; + + // if bufferType == SHARED_MEM + // No additional attributes. + + // if bufferType == ANW_BUFFER + AnwBufferAttributes anwBuffer; + + // if bufferType == NATIVE_HANDLE + // No additional attributes. + }; + + /** + * Type of the buffer. + */ + Type type; + + /** + * Attributes that can be put into a union. + */ + Attributes attr; + + /** + * Used only for types ANW_BUFFER and NATIVE_HANDLE. + * + * (A native handle cannot be put into a union as HIDL currently does not + * support discriminated unions.) + */ + handle nativeHandle; + + /** + * Used only for type SHARED_MEM. + */ + memory sharedMemory; + +}; + +/** + * Ref: frameworks/av/include/media/IOMX.h + * + * Enumeration of port modes. + */ +enum PortMode : int32_t { + PRESET_START = 0, + PRESET_BYTE_BUFFER, + PRESET_ANW_BUFFER, + PRESET_SECURE_BUFFER, + PRESET_END, + DYNAMIC_START = 100, + DYNAMIC_ANW_BUFFER, + DYNAMIC_NATIVE_HANDLE, + DYNAMIC_END +}; + +/** + * Ref: frameworks/native/include/media/hardware/VideoAPI.h + * + * Framework defined color aspects. These are based mainly on ISO 23001-8 spec. As this standard + * continues to evolve, new values may be defined in the future. Use OTHER for these future values + * as well as for values not listed here, as those are not supported by the framework. + */ +struct ColorAspects { + enum Range : uint32_t { + UNSPECIFIED, // Unspecified + FULL, // Full range + LIMITED, // Limited range (if defined), or not full range + + OTHER = 0xff, // Not one of the above values + }; + + // Color primaries + enum Primaries : uint32_t { + UNSPECIFIED, // Unspecified + BT709_5, // Rec.ITU-R BT.709-5 or equivalent + BT470_6M, // Rec.ITU-R BT.470-6 System M or equivalent + BT601_6_625, // Rec.ITU-R BT.601-6 625 or equivalent + BT601_6_525, // Rec.ITU-R BT.601-6 525 or equivalent + GENERIC_FILM, // Generic Film + BT2020, // Rec.ITU-R BT.2020 or equivalent + + OTHER = 0xff, // Not one of the above values + }; + + // Transfer characteristics + enum Transfer : uint32_t { + UNSPECIFIED, // Unspecified + LINEAR, // Linear transfer characteristics + SRGB, // sRGB or equivalent + SMPTE170M, // SMPTE 170M or equivalent (e.g. BT.601/709/2020) + GAMMA22, // Assumed display gamma 2.2 + GAMMA28, // Assumed display gamma 2.8 + ST2084, // SMPTE ST 2084 for 10/12/14/16 bit systems + HLG, // ARIB STD-B67 hybrid-log-gamma + + // values unlikely to be required by Android follow here + SMPTE240M = 0x40, // SMPTE 240M + XVYCC, // IEC 61966-2-4 + BT1361, // Rec.ITU-R BT.1361 extended gamut + ST428, // SMPTE ST 428-1 + + OTHER = 0xff, // Not one of the above values + }; + + // YUV <-> RGB conversion + enum MatrixCoeffs : uint32_t { + UNSPECIFIED, // Unspecified + BT709_5, // Rec.ITU-R BT.709-5 or equivalent + BT470_6M, // KR=0.30, KB=0.11 or equivalent + BT601_6, // Rec.ITU-R BT.601-6 625 or equivalent + SMPTE240M, // SMPTE 240M or equivalent + BT2020, // Rec.ITU-R BT.2020 non-constant luminance + BT2020CONSTANT, // Rec.ITU-R BT.2020 constant luminance + + OTHER = 0xff, // Not one of the above values + }; + + Range range; + Primaries primaries; + Transfer transfer; + MatrixCoeffs matrixCoeffs; +}; +
diff --git a/memtrack/1.0/Android.bp b/memtrack/1.0/Android.bp new file mode 100644 index 0000000..9f4c7f6 --- /dev/null +++ b/memtrack/1.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.memtrack@1.0_hal", + srcs: [ + "types.hal", + "IMemtrack.hal", + ], +} + +genrule { + name: "android.hardware.memtrack@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.memtrack@1.0", + srcs: [ + ":android.hardware.memtrack@1.0_hal", + ], + out: [ + "android/hardware/memtrack/1.0/types.cpp", + "android/hardware/memtrack/1.0/MemtrackAll.cpp", + ], +} + +genrule { + name: "android.hardware.memtrack@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.memtrack@1.0", + srcs: [ + ":android.hardware.memtrack@1.0_hal", + ], + out: [ + "android/hardware/memtrack/1.0/types.h", + "android/hardware/memtrack/1.0/IMemtrack.h", + "android/hardware/memtrack/1.0/IHwMemtrack.h", + "android/hardware/memtrack/1.0/BnHwMemtrack.h", + "android/hardware/memtrack/1.0/BpHwMemtrack.h", + "android/hardware/memtrack/1.0/BsMemtrack.h", + ], +} + +cc_library_shared { + name: "android.hardware.memtrack@1.0", + generated_sources: ["android.hardware.memtrack@1.0_genc++"], + generated_headers: ["android.hardware.memtrack@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.memtrack@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/memtrack/1.0/Android.mk b/memtrack/1.0/Android.mk new file mode 100644 index 0000000..62bee97 --- /dev/null +++ b/memtrack/1.0/Android.mk
@@ -0,0 +1,232 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.memtrack@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (MemtrackFlag) +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::types.MemtrackFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MemtrackRecord) +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackRecord.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::types.MemtrackRecord + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MemtrackStatus) +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::types.MemtrackStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MemtrackType) +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::types.MemtrackType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IMemtrack.hal +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/IMemtrack.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IMemtrack.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::IMemtrack + +$(GEN): $(LOCAL_PATH)/IMemtrack.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.memtrack@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (MemtrackFlag) +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackFlag.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::types.MemtrackFlag + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MemtrackRecord) +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackRecord.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::types.MemtrackRecord + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MemtrackStatus) +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::types.MemtrackStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MemtrackType) +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/MemtrackType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::types.MemtrackType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IMemtrack.hal +# +GEN := $(intermediates)/android/hardware/memtrack/V1_0/IMemtrack.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IMemtrack.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.memtrack@1.0::IMemtrack + +$(GEN): $(LOCAL_PATH)/IMemtrack.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/memtrack/1.0/IMemtrack.hal b/memtrack/1.0/IMemtrack.hal new file mode 100644 index 0000000..ae9d960 --- /dev/null +++ b/memtrack/1.0/IMemtrack.hal
@@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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.memtrack@1.0; + +/* + * The Memory Tracker HAL is designed to return information about + * device-specific memory usage. + * The primary goal is to be able to track memory that is not + * trackable in any other way, for example texture memory that is allocated by + * a process, but not mapped in to that process's address space. + * A secondary goal is to be able to categorize memory used by a process into + * GL, graphics, etc. All memory sizes must be in real memory usage, + * accounting for stride, bit depth, rounding up to page size, etc. + * + * Constructor for the interface should be used to perform memtrack management + * setup actions and is called once before any calls to getMemory(). + */ +interface IMemtrack { + /* + * getMemory() populates MemtrackRecord vector with the sizes of memory + * plus associated flags for that memory. + * + * This function must be thread-safe, it may get called from multiple + * threads at the same time. + * + * A process collecting memory statistics will call getMemory for each + * combination of pid and memory type. For each memory type that it + * recognizes, the HAL must fill out an array of memtrack_record + * structures breaking down the statistics of that memory type as much as + * possible. For example, + * getMemory(<pid>, GL) might return: + * { { 4096, ACCOUNTED | PRIVATE | SYSTEM }, + * { 40960, UNACCOUNTED | PRIVATE | SYSTEM }, + * { 8192, ACCOUNTED | PRIVATE | DEDICATED }, + * { 8192, UNACCOUNTED | PRIVATE | DEDICATED } } + * If the HAL cannot differentiate between SYSTEM and DEDICATED memory, it + * could return: + * { { 12288, ACCOUNTED | PRIVATE }, + * { 49152, UNACCOUNTED | PRIVATE } } + * + * Memory must not overlap between types. For example, a graphics buffer + * that has been mapped into the GPU as a surface must show up when + * GRAPHICS is requested and not when GL + * is requested. + * + * @param pid process for which memory information is requested + * @param type memory type that information is being requested about + * @return records vector of MemtrackRecord containing memory information + * @return retval SUCCESS on success, TYPE_NOT_FOUND if the type is not + * supported. + */ + getMemory(int32_t pid, MemtrackType type) + generates (MemtrackStatus retval, vec<MemtrackRecord> records); +};
diff --git a/memtrack/1.0/default/Android.bp b/memtrack/1.0/default/Android.bp new file mode 100644 index 0000000..76d7fc8 --- /dev/null +++ b/memtrack/1.0/default/Android.bp
@@ -0,0 +1,53 @@ +// Copyright (C) 2016 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. + +cc_library_shared { + name: "android.hardware.memtrack@1.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["Memtrack.cpp"], + + shared_libs: [ + "libbase", + "liblog", + "libhidlbase", + "libhidltransport", + "libhardware", + "libutils", + "android.hardware.memtrack@1.0", + ], + +} + +cc_binary { + relative_install_path: "hw", + defaults: ["hidl_defaults"], + proprietary: true, + name: "android.hardware.memtrack@1.0-service", + init_rc: ["android.hardware.memtrack@1.0-service.rc"], + srcs: ["service.cpp"], + + shared_libs: [ + "liblog", + "libbase", + "libdl", + "libutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "android.hardware.memtrack@1.0", + ], + +}
diff --git a/memtrack/1.0/default/Memtrack.cpp b/memtrack/1.0/default/Memtrack.cpp new file mode 100644 index 0000000..33a6906 --- /dev/null +++ b/memtrack/1.0/default/Memtrack.cpp
@@ -0,0 +1,102 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.memtrack@1.0-impl" + +#include <log/log.h> + +#include <hardware/hardware.h> +#include <hardware/memtrack.h> + +#include "Memtrack.h" + +namespace android { +namespace hardware { +namespace memtrack { +namespace V1_0 { +namespace implementation { + +Memtrack::Memtrack(const memtrack_module_t *module) : mModule(module) { + if (mModule) + mModule->init(mModule); +} + +Memtrack::~Memtrack() { + delete(mModule); +} + +Return<void> Memtrack::getMemory(int32_t pid, MemtrackType type, + getMemory_cb _hidl_cb) { + hidl_vec<MemtrackRecord> records; + size_t temp = 0; + size_t *size = &temp; + int ret = 0; + + if (mModule->getMemory == nullptr) + { + _hidl_cb(MemtrackStatus::SUCCESS, records); + return Void(); + } + ret = mModule->getMemory(mModule, pid, static_cast<memtrack_type>(type), + NULL, size); + if (ret == 0) + { + memtrack_record *legacy_records = new memtrack_record[*size]; + ret = mModule->getMemory(mModule, pid, + static_cast<memtrack_type>(type), legacy_records, size); + if (ret == 0) + { + records.resize(*size); + for(size_t i = 0; i < *size; i++) + { + records[i].sizeInBytes = legacy_records[i].size_in_bytes; + records[i].flags = legacy_records[i].flags; + } + } + delete[] legacy_records; + } + _hidl_cb(MemtrackStatus::SUCCESS, records); + return Void(); +} + + +IMemtrack* HIDL_FETCH_IMemtrack(const char* /* name */) { + const hw_module_t* hw_module = nullptr; + const memtrack_module_t* memtrack_module = nullptr; + int err = hw_get_module(MEMTRACK_HARDWARE_MODULE_ID, &hw_module); + if (err) { + ALOGE ("hw_get_module %s failed: %d", MEMTRACK_HARDWARE_MODULE_ID, err); + return nullptr; + } + + if (!hw_module->methods || !hw_module->methods->open) { + memtrack_module = reinterpret_cast<const memtrack_module_t*>(hw_module); + } else { + err = hw_module->methods->open(hw_module, MEMTRACK_HARDWARE_MODULE_ID, + reinterpret_cast<hw_device_t**>(const_cast<memtrack_module_t**>(&memtrack_module))); + if (err) { + ALOGE("Passthrough failed to load legacy HAL."); + return nullptr; + } + } + return new Memtrack(memtrack_module); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace memtrack +} // namespace hardware +} // namespace android
diff --git a/memtrack/1.0/default/Memtrack.h b/memtrack/1.0/default/Memtrack.h new file mode 100644 index 0000000..0adba76 --- /dev/null +++ b/memtrack/1.0/default/Memtrack.h
@@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_MEMTRACK_V1_0_MEMTRACK_H +#define ANDROID_HARDWARE_MEMTRACK_V1_0_MEMTRACK_H + +#include <android/hardware/memtrack/1.0/IMemtrack.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace memtrack { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::memtrack::V1_0::IMemtrack; +using ::android::hardware::memtrack::V1_0::MemtrackRecord; +using ::android::hardware::memtrack::V1_0::MemtrackStatus; +using ::android::hardware::memtrack::V1_0::MemtrackType; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Memtrack : public IMemtrack { + Memtrack(const memtrack_module_t* module); + ~Memtrack(); + Return<void> getMemory(int32_t pid, MemtrackType type, getMemory_cb _hidl_cb) override; + + private: + const memtrack_module_t* mModule; +}; + +extern "C" IMemtrack* HIDL_FETCH_IMemtrack(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace memtrack +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_MEMTRACK_V1_0_MEMTRACK_H
diff --git a/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc new file mode 100644 index 0000000..c975a18 --- /dev/null +++ b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
@@ -0,0 +1,4 @@ +service memtrack-hal-1-0 /vendor/bin/hw/android.hardware.memtrack@1.0-service + class hal + user system + group system
diff --git a/memtrack/1.0/default/service.cpp b/memtrack/1.0/default/service.cpp new file mode 100644 index 0000000..f079743 --- /dev/null +++ b/memtrack/1.0/default/service.cpp
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.memtrack@1.0-service" + +#include <android/hardware/memtrack/1.0/IMemtrack.h> +#include <hidl/LegacySupport.h> + +using android::hardware::memtrack::V1_0::IMemtrack; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IMemtrack>(); +}
diff --git a/memtrack/1.0/types.hal b/memtrack/1.0/types.hal new file mode 100644 index 0000000..3d702b3 --- /dev/null +++ b/memtrack/1.0/types.hal
@@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 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.memtrack@1.0; + +/* + * SMAPS_ACCOUNTED/SMAPS_UNACCOUNTED + * Flags to differentiate memory that can already be accounted for in + * /proc/<pid>/smaps, + * (Shared_Clean + Shared_Dirty + Private_Clean + Private_Dirty = Size). + * In general, memory mapped in to a userspace process is accounted unless + * it was mapped with remap_pfn_range. + * Exactly one of these must be set. + * + * SHARED/SHARED_PSS/PRIVATE + * Flags to differentiate memory shared across multiple processes vs. memory + * used by a single process. + * If SHARED_PSS flags is used, the memory must be divided by the number of + * processes holding reference to it (shared / num_processes). + * Only zero or one of these may be set in a record. + * If none are set, record is assumed to count shared + private memory. + * + * SYSTEM/DEDICATED + * Flags to differentiate memory taken from the kernel's allocation pool vs. + * memory that is dedicated to non-kernel allocations, for example a carveout + * or separate video memory. Only zero or one of these may be set in a record. + * If none are set, record is assumed to count system + dedicated memory. + * + * NONSECURE/SECURE + * Flags to differentiate memory accessible by the CPU in non-secure mode vs. + * memory that is protected. Only zero or one of these may be set in a record. + * If none are set, record is assumed to count secure + nonsecure memory. + */ +enum MemtrackFlag : uint32_t { + SMAPS_ACCOUNTED = 1 << 1, + SMAPS_UNACCOUNTED = 1 << 2, + SHARED = 1 << 3, + SHARED_PSS = 1 << 4, + PRIVATE = 1 << 5, + SYSTEM = 1 << 6, + DEDICATED = 1 << 7, + NONSECURE = 1 << 8, + SECURE = 1 << 9, +}; + +/* Tags which define the usage of the memory buffers. */ +enum MemtrackType : uint32_t { + OTHER = 0, + GL = 1, + GRAPHICS = 2, + MULTIMEDIA = 3, + CAMERA = 4, + NUM_TYPES, +}; + +enum MemtrackStatus : uint32_t { + SUCCESS = 0, + MEMORY_TRACKING_NOT_SUPPORTED = 1, + TYPE_NOT_SUPPORTED = 2, +}; + +/* A vector of MemtrackRecord is returned by the function getMemory(). + * Each record consists of the size of the memory used by the process and + * flags indicate the all the MemtrackFlag that are valid for this record. + * see getMemory() comments for further details. + */ +struct MemtrackRecord { + uint64_t sizeInBytes; + /* + * This is the bitfield for the MemtrackFlag indicating all the flags that + * are valid for this record. + */ + uint32_t flags; +};
diff --git a/memtrack/1.0/vts/functional/Android.bp b/memtrack/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..71e6111 --- /dev/null +++ b/memtrack/1.0/vts/functional/Android.bp
@@ -0,0 +1,35 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalMemtrackV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalMemtrackV1_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhardware", + "libhidlbase", + "libutils", + "android.hardware.memtrack@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ] +}
diff --git a/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp b/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp new file mode 100644 index 0000000..a8d8aea --- /dev/null +++ b/memtrack/1.0/vts/functional/VtsHalMemtrackV1_0TargetTest.cpp
@@ -0,0 +1,165 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "memtrack_hidl_hal_test" +#include <android-base/logging.h> +#include <android-base/unique_fd.h> + +#include <android/hardware/memtrack/1.0/IMemtrack.h> + +#include <VtsHalHidlTargetTestBase.h> + +#include <algorithm> +#include <vector> + +using ::android::hardware::memtrack::V1_0::IMemtrack; +using ::android::hardware::memtrack::V1_0::MemtrackRecord; +using ::android::hardware::memtrack::V1_0::MemtrackFlag; +using ::android::hardware::memtrack::V1_0::MemtrackType; +using ::android::hardware::memtrack::V1_0::MemtrackStatus; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::sp; +using ::android::base::unique_fd; +using std::vector; +using std::count_if; + +class MemtrackHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + memtrack = ::testing::VtsHalHidlTargetTestBase::getService<IMemtrack>(); + ASSERT_NE(memtrack, nullptr); + } + + virtual void TearDown() override {} + + sp<IMemtrack> memtrack; +}; + +/* Returns true if flags contains at least min, and no more than max, + * of the flags in flagSet. Returns false otherwise. + */ +bool rightFlagCount(uint32_t flags, vector<MemtrackFlag> flagSet, uint32_t min, + uint32_t max) { + uint32_t count = + count_if(flagSet.begin(), flagSet.end(), + [&](MemtrackFlag f) { return flags & (uint32_t)f; }); + return (min <= count && count <= max); +} + +/* Returns true when passed a valid, defined status, false otherwise. + */ +bool validStatus(MemtrackStatus s) { + vector<MemtrackStatus> statusVec = { + MemtrackStatus::SUCCESS, MemtrackStatus::MEMORY_TRACKING_NOT_SUPPORTED, + MemtrackStatus::TYPE_NOT_SUPPORTED}; + return std::find(statusVec.begin(), statusVec.end(), s) != statusVec.end(); +} + +auto generate_cb(MemtrackStatus *s, hidl_vec<MemtrackRecord> *v) { + return [=](MemtrackStatus status, hidl_vec<MemtrackRecord> vec) { + *s = status; + *v = vec; + }; +} + +/* Sanity check results when getMemory() is passed a negative PID + */ +TEST_F(MemtrackHidlTest, BadPidTest) { + MemtrackStatus s; + hidl_vec<MemtrackRecord> v; + auto cb = generate_cb(&s, &v); + for (uint32_t i = 0; i < static_cast<uint32_t>(MemtrackType::NUM_TYPES); + i++) { + Return<void> ret = + memtrack->getMemory(-1, static_cast<MemtrackType>(i), cb); + ASSERT_TRUE(ret.isOk()); + ASSERT_TRUE(validStatus(s)); + } +} + +/* Sanity check results when getMemory() is passed a bad memory usage type + */ +TEST_F(MemtrackHidlTest, BadTypeTest) { + MemtrackStatus s; + hidl_vec<MemtrackRecord> v; + auto cb = generate_cb(&s, &v); + Return<void> ret = memtrack->getMemory(getpid(), MemtrackType::NUM_TYPES, cb); + ASSERT_TRUE(ret.isOk()); + ASSERT_TRUE(validStatus(s)); +} + +/* Call memtrack on this process and check that the results are reasonable + * for all memory types, including valid flag combinations for every + * MemtrackRecord returned. + */ +TEST_F(MemtrackHidlTest, GetMemoryTest) { + /* Opening this device causes the kernel to provide memtrack with memory + * info for this process. + */ + unique_fd fd(open("/dev/kgsl-3d0", O_RDWR)); + + MemtrackStatus s; + hidl_vec<MemtrackRecord> v; + auto cb = generate_cb(&s, &v); + uint32_t unsupportedCount = 0; + for (uint32_t i = 0; i < static_cast<uint32_t>(MemtrackType::NUM_TYPES); + i++) { + Return<void> ret = + memtrack->getMemory(getpid(), static_cast<MemtrackType>(i), cb); + ASSERT_TRUE(ret.isOk()); + + switch (s) { + case MemtrackStatus::MEMORY_TRACKING_NOT_SUPPORTED: + unsupportedCount++; + break; + case MemtrackStatus::TYPE_NOT_SUPPORTED: + break; + case MemtrackStatus::SUCCESS: { + for (uint32_t j = 0; j < v.size(); j++) { + // Enforce flag constraints + vector<MemtrackFlag> smapFlags = {MemtrackFlag::SMAPS_ACCOUNTED, + MemtrackFlag::SMAPS_UNACCOUNTED}; + EXPECT_TRUE(rightFlagCount(v[j].flags, smapFlags, 1, 1)); + vector<MemtrackFlag> shareFlags = {MemtrackFlag::SHARED, + MemtrackFlag::SHARED_PSS, + MemtrackFlag::PRIVATE}; + EXPECT_TRUE(rightFlagCount(v[j].flags, shareFlags, 0, 1)); + vector<MemtrackFlag> systemFlags = {MemtrackFlag::SYSTEM, + MemtrackFlag::DEDICATED}; + EXPECT_TRUE(rightFlagCount(v[j].flags, systemFlags, 0, 1)); + vector<MemtrackFlag> secureFlags = {MemtrackFlag::SECURE, + MemtrackFlag::NONSECURE}; + EXPECT_TRUE(rightFlagCount(v[j].flags, secureFlags, 0, 1)); + } + break; + } + default: + FAIL(); + } + } + // If tracking is not supported this should be returned for all types. + ASSERT_TRUE(unsupportedCount == 0 || + unsupportedCount == + static_cast<uint32_t>(MemtrackType::NUM_TYPES)); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +}
diff --git a/memtrack/Android.bp b/memtrack/Android.bp new file mode 100644 index 0000000..ed19a37 --- /dev/null +++ b/memtrack/Android.bp
@@ -0,0 +1,6 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/default", + "1.0/vts/functional", +]
diff --git a/power/1.0/Android.bp b/power/1.0/Android.bp new file mode 100644 index 0000000..453d525 --- /dev/null +++ b/power/1.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.power@1.0_hal", + srcs: [ + "types.hal", + "IPower.hal", + ], +} + +genrule { + name: "android.hardware.power@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.power@1.0", + srcs: [ + ":android.hardware.power@1.0_hal", + ], + out: [ + "android/hardware/power/1.0/types.cpp", + "android/hardware/power/1.0/PowerAll.cpp", + ], +} + +genrule { + name: "android.hardware.power@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.power@1.0", + srcs: [ + ":android.hardware.power@1.0_hal", + ], + out: [ + "android/hardware/power/1.0/types.h", + "android/hardware/power/1.0/IPower.h", + "android/hardware/power/1.0/IHwPower.h", + "android/hardware/power/1.0/BnHwPower.h", + "android/hardware/power/1.0/BpHwPower.h", + "android/hardware/power/1.0/BsPower.h", + ], +} + +cc_library_shared { + name: "android.hardware.power@1.0", + generated_sources: ["android.hardware.power@1.0_genc++"], + generated_headers: ["android.hardware.power@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.power@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/power/1.0/Android.mk b/power/1.0/Android.mk new file mode 100644 index 0000000..98d95a8 --- /dev/null +++ b/power/1.0/Android.mk
@@ -0,0 +1,270 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.power@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (Feature) +# +GEN := $(intermediates)/android/hardware/power/V1_0/Feature.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.Feature + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PowerHint) +# +GEN := $(intermediates)/android/hardware/power/V1_0/PowerHint.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.PowerHint + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PowerStatePlatformSleepState) +# +GEN := $(intermediates)/android/hardware/power/V1_0/PowerStatePlatformSleepState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.PowerStatePlatformSleepState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PowerStateVoter) +# +GEN := $(intermediates)/android/hardware/power/V1_0/PowerStateVoter.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.PowerStateVoter + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/power/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IPower.hal +# +GEN := $(intermediates)/android/hardware/power/V1_0/IPower.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IPower.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::IPower + +$(GEN): $(LOCAL_PATH)/IPower.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.power@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (Feature) +# +GEN := $(intermediates)/android/hardware/power/V1_0/Feature.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.Feature + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PowerHint) +# +GEN := $(intermediates)/android/hardware/power/V1_0/PowerHint.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.PowerHint + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PowerStatePlatformSleepState) +# +GEN := $(intermediates)/android/hardware/power/V1_0/PowerStatePlatformSleepState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.PowerStatePlatformSleepState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PowerStateVoter) +# +GEN := $(intermediates)/android/hardware/power/V1_0/PowerStateVoter.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.PowerStateVoter + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/power/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IPower.hal +# +GEN := $(intermediates)/android/hardware/power/V1_0/IPower.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IPower.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.power@1.0::IPower + +$(GEN): $(LOCAL_PATH)/IPower.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/power/1.0/IPower.hal b/power/1.0/IPower.hal new file mode 100644 index 0000000..6cba42a --- /dev/null +++ b/power/1.0/IPower.hal
@@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016 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.power@1.0; + +/* + * Constructor for the interface performs power management setup actions at + * runtime startup, such as to set default cpufreq parameters. + */ +interface IPower { + /* + * setInteractive() performs power management actions upon the + * system entering interactive state (that is, the system is awake + * and ready for interaction, often with UI devices such as + * display and touchscreen enabled) or non-interactive state (the + * system appears asleep, display usually turned off). The + * non-interactive state may be entered after a period of + * inactivity in order to conserve battery power during + * such inactive periods. + * + * Typical actions are to turn on or off devices and adjust + * cpufreq parameters. This function may also call the + * appropriate interfaces to allow the kernel to suspend the + * system to low-power sleep state when entering non-interactive + * state, and to disallow low-power suspend when the system is in + * interactive state. When low-power suspend state is allowed, the + * kernel may suspend the system whenever no wakelocks are held. + * + * For example, + * This function can be called to enter non-interactive state after + * turning off the screen (if present) and called to enter + * interactive state prior to turning on the screen. + * + * @param interactive is true when the system is transitioning to an + * interactive state and false when transitioning to a + * non-interactive state. + */ + setInteractive(bool interactive); + + /* + * powerHint() is called to pass hints on power requirements which + * may result in adjustment of power/performance parameters of the + * cpufreq governor and other controls. + * + * A particular platform may choose to ignore any hint. + * + * @param hint PowerHint which is passed + * @param data contains additional information about the hint + * and is described along with the comments for each of the hints. + */ + powerHint(PowerHint hint, int32_t data); + + /* + * setFeature() is called to turn on or off a particular feature + * depending on the state parameter. + * + * @param feature Feature which needs to be set + * @param activate true/false to enable/disable the feature + */ + setFeature(Feature feature, bool activate); + + /* + * Platform-level sleep state stats: + * Report cumulative info on the statistics on platform-level sleep states + * since boot. + * + * Higher the index in the returned <states> vector deeper the state is + * i.e. lesser steady-state power is consumed by the platform to be + * resident in that state. + * + * @return states of power states the device supports + * @return retval SUCCESS on success or FILESYSTEM_ERROR on filesystem + * nodes access error. + */ + getPlatformLowPowerStats() + generates (vec<PowerStatePlatformSleepState> states, Status retval); +};
diff --git a/power/1.0/default/Android.bp b/power/1.0/default/Android.bp new file mode 100644 index 0000000..4f43b95 --- /dev/null +++ b/power/1.0/default/Android.bp
@@ -0,0 +1,61 @@ +// Copyright (C) 2016 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. + +cc_library_shared { + name: "android.hardware.power@1.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["Power.cpp"], + + cflags: [ + "-Wall", + "-Werror", + ], + + shared_libs: [ + "liblog", + "libhardware", + "libhidlbase", + "libhidltransport", + "libutils", + "android.hardware.power@1.0", + ], + +} + +cc_binary { + proprietary: true, + defaults: ["hidl_defaults"], + relative_install_path: "hw", + name: "android.hardware.power@1.0-service", + init_rc: ["android.hardware.power@1.0-service.rc"], + srcs: ["service.cpp"], + + cflags: [ + "-Wall", + "-Werror", + ], + + shared_libs: [ + "liblog", + "libdl", + "libutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "android.hardware.power@1.0", + ], + +}
diff --git a/power/1.0/default/Power.cpp b/power/1.0/default/Power.cpp new file mode 100644 index 0000000..6ea9167 --- /dev/null +++ b/power/1.0/default/Power.cpp
@@ -0,0 +1,173 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.power@1.0-impl" + +#include <log/log.h> + +#include <hardware/hardware.h> +#include <hardware/power.h> + +#include "Power.h" + +namespace android { +namespace hardware { +namespace power { +namespace V1_0 { +namespace implementation { + +Power::Power(power_module_t *module) : mModule(module) { + if (mModule) + mModule->init(mModule); +} + +Power::~Power() { + delete(mModule); +} + +// Methods from ::android::hardware::power::V1_0::IPower follow. +Return<void> Power::setInteractive(bool interactive) { + if (mModule->setInteractive) + mModule->setInteractive(mModule, interactive ? 1 : 0); + return Void(); +} + +Return<void> Power::powerHint(PowerHint hint, int32_t data) { + int32_t param = data; + if (mModule->powerHint) { + if (data) + mModule->powerHint(mModule, static_cast<power_hint_t>(hint), ¶m); + else + mModule->powerHint(mModule, static_cast<power_hint_t>(hint), NULL); + } + return Void(); +} + +Return<void> Power::setFeature(Feature feature, bool activate) { + if (mModule->setFeature) + mModule->setFeature(mModule, static_cast<feature_t>(feature), + activate ? 1 : 0); + return Void(); +} + +Return<void> Power::getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) { + hidl_vec<PowerStatePlatformSleepState> states; + ssize_t number_platform_modes; + size_t *voters = nullptr; + power_state_platform_sleep_state_t *legacy_states = nullptr; + int ret; + + if (mModule->get_number_of_platform_modes == nullptr || + mModule->get_voter_list == nullptr || + mModule->get_platform_low_power_stats == nullptr) + { + _hidl_cb(states, Status::SUCCESS); + return Void(); + } + + number_platform_modes = mModule->get_number_of_platform_modes(mModule); + if (number_platform_modes) + { + if ((ssize_t) (SIZE_MAX / sizeof(size_t)) <= number_platform_modes) // overflow + goto done; + voters = new (std::nothrow) size_t [number_platform_modes]; + if (voters == nullptr) + goto done; + + ret = mModule->get_voter_list(mModule, voters); + if (ret != 0) + goto done; + + if ((ssize_t) (SIZE_MAX / sizeof(power_state_platform_sleep_state_t)) + <= number_platform_modes) // overflow + goto done; + legacy_states = new (std::nothrow) + power_state_platform_sleep_state_t [number_platform_modes]; + if (legacy_states == nullptr) + goto done; + + for (int i = 0; i < number_platform_modes; i++) + { + legacy_states[i].voters = nullptr; + legacy_states[i].voters = new power_state_voter_t [voters[i]]; + if (legacy_states[i].voters == nullptr) + goto done; + } + + ret = mModule->get_platform_low_power_stats(mModule, legacy_states); + if (ret != 0) + goto done; + + states.resize(number_platform_modes); + for (int i = 0; i < number_platform_modes; i++) + { + power_state_platform_sleep_state_t& legacy_state = legacy_states[i]; + PowerStatePlatformSleepState& state = states[i]; + state.name = legacy_state.name; + state.residencyInMsecSinceBoot = legacy_state.residency_in_msec_since_boot; + state.totalTransitions = legacy_state.total_transitions; + state.supportedOnlyInSuspend = legacy_state.supported_only_in_suspend; + state.voters.resize(voters[i]); + for(size_t j = 0; j < voters[i]; j++) + { + state.voters[j].name = legacy_state.voters[j].name; + state.voters[j].totalTimeInMsecVotedForSinceBoot = legacy_state.voters[j].total_time_in_msec_voted_for_since_boot; + state.voters[j].totalNumberOfTimesVotedSinceBoot = legacy_state.voters[j].total_number_of_times_voted_since_boot; + } + } + } +done: + if (legacy_states) + { + for (int i = 0; i < number_platform_modes; i++) + { + if(legacy_states[i].voters) + delete(legacy_states[i].voters); + } + } + delete[] legacy_states; + delete[] voters; + _hidl_cb(states, Status::SUCCESS); + return Void(); +} + +IPower* HIDL_FETCH_IPower(const char* /* name */) { + int ret = 0; + const hw_module_t* hw_module = NULL; + power_module_t *power_module; + ret = hw_get_module(POWER_HARDWARE_MODULE_ID, &hw_module); + if (ret == 0 && hw_module->methods->open) { + ret = hw_module->methods->open(hw_module, POWER_HARDWARE_MODULE_ID, + reinterpret_cast<hw_device_t**>(&power_module)); + if (ret == 0) { + return new Power(power_module); + } + else { + ALOGE("Passthrough failed to load legacy power HAL."); + return nullptr; + } + } + else { + ALOGE ("hw_get_module %s failed: %d", POWER_HARDWARE_MODULE_ID, ret); + return nullptr; + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace power +} // namespace hardware +} // namespace android
diff --git a/power/1.0/default/Power.h b/power/1.0/default/Power.h new file mode 100644 index 0000000..a43aefb --- /dev/null +++ b/power/1.0/default/Power.h
@@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_POWER_V1_0_POWER_H +#define ANDROID_HARDWARE_POWER_V1_0_POWER_H + +#include <android/hardware/power/1.0/IPower.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace power { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::power::V1_0::Feature; +using ::android::hardware::power::V1_0::IPower; +using ::android::hardware::power::V1_0::PowerHint; +using ::android::hardware::power::V1_0::PowerStatePlatformSleepState; +using ::android::hardware::power::V1_0::Status; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Power : public IPower { + Power(power_module_t* module); + ~Power(); + Return<void> setInteractive(bool interactive) override; + Return<void> powerHint(PowerHint hint, int32_t data) override; + Return<void> setFeature(Feature feature, bool activate) override; + Return<void> getPlatformLowPowerStats(getPlatformLowPowerStats_cb _hidl_cb) override; + + private: + power_module_t* mModule; +}; + +extern "C" IPower* HIDL_FETCH_IPower(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace power +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_POWER_V1_0_POWER_H
diff --git a/power/1.0/default/android.hardware.power@1.0-service.rc b/power/1.0/default/android.hardware.power@1.0-service.rc new file mode 100644 index 0000000..1777e90 --- /dev/null +++ b/power/1.0/default/android.hardware.power@1.0-service.rc
@@ -0,0 +1,4 @@ +service power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service + class hal + user system + group system
diff --git a/power/1.0/default/service.cpp b/power/1.0/default/service.cpp new file mode 100644 index 0000000..e8618b8 --- /dev/null +++ b/power/1.0/default/service.cpp
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.power@1.0-service" + +#include <android/hardware/power/1.0/IPower.h> +#include <hidl/LegacySupport.h> + +using android::hardware::power::V1_0::IPower; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IPower>(); +}
diff --git a/power/1.0/types.hal b/power/1.0/types.hal new file mode 100644 index 0000000..debdc35 --- /dev/null +++ b/power/1.0/types.hal
@@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 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.power@1.0; + +/* Power hint identifiers passed to powerHint() */ +enum PowerHint : uint32_t { + /* + * Foreground app has started or stopped requesting a VSYNC pulse + * from SurfaceFlinger. If the app has started requesting VSYNC + * then CPU and GPU load is expected soon, and it may be appropriate + * to raise speeds of CPU, memory bus, etc. The data parameter is + * non-zero to indicate VSYNC pulse is now requested, or zero for + * VSYNC pulse no longer requested. + */ + VSYNC = 0x00000001, + + + /* + * User is interacting with the device, for example, touchscreen + * events are incoming. CPU and GPU load may be expected soon, + * and it may be appropriate to raise speeds of CPU, memory bus, + * etc. The data parameter is the estimated length of the interaction + * in milliseconds, or 0 if unknown. + */ + INTERACTION = 0x00000002, + + + /* DO NOT USE VIDEO_ENCODE/_DECODE! They will be removed in + * KLP. + */ + VIDEO_ENCODE = 0x00000003, + VIDEO_DECODE = 0x00000004, + + /* + * Low power mode is activated or deactivated. Low power mode + * is intended to save battery at the cost of performance. The data + * parameter is non-zero when low power mode is activated, and zero + * when deactivated. + */ + LOW_POWER = 0x00000005, + + /* + * Sustained Performance mode is actived or deactivated. Sustained + * performance mode is intended to provide a consistent level of + * performance for a prolonged amount of time. The data parameter is + * non-zero when sustained performance mode is activated, and zero + * when deactivated. + */ + SUSTAINED_PERFORMANCE = 0x00000006, + + /* + * VR Mode is activated or deactivated. VR mode is intended to + * provide minimum guarantee for performance for the amount of time the + * device can sustain it. The data parameter is non-zero when the mode + * is activated and zero when deactivated. + */ + VR_MODE = 0x00000007, + + /* + * This hint indicates that an application has been launched. Can be used + * for device specific optimizations during application launch. The data + * parameter is non-zero when the application starts to launch and zero when + * it has been launched. + */ + LAUNCH = 0x00000008, +}; + +enum Feature : uint32_t { + /* + * Enabling/Disabling this feature will allow/disallow the system + * to wake up by tapping the screen twice. + */ + POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 0x00000001 +}; + +enum Status : uint32_t { + SUCCESS = 0, + FILESYSTEM_ERROR = 1 +}; +/* + * Platform-level sleep state stats: + * PowerStateVoter struct is useful for describing the individual voters + * when a Platform-level sleep state is chosen by aggregation of votes from + * multiple clients/system conditions. + * + * This helps in attirbuting what in the device is blocking the device from + * entering the lowest Platform-level sleep state. + */ +struct PowerStateVoter { + /* + * Name of the voter. + */ + string name; + + /* + * Total time in msec the voter voted for the platform sleep state since + * boot. + */ + uint64_t totalTimeInMsecVotedForSinceBoot; + + /* + * Number of times the voter voted for the platform sleep state since boot. + */ + uint64_t totalNumberOfTimesVotedSinceBoot; +}; + +/* + * Platform-level sleep state stats: + * PowerStatePlatformSleepState represents the Platform-level sleep state + * the device is capable of getting into. + * + * SoCs usually have more than one Platform-level sleep state. + */ +struct PowerStatePlatformSleepState { + /* + * Platform-level Sleep state name. + */ + string name; + + /* + * Time spent in msec at this platform-level sleep state since boot. + */ + uint64_t residencyInMsecSinceBoot; + + /* + * Total number of times system entered this state. + */ + uint64_t totalTransitions; + + /* + * This platform-level sleep state can only be reached during system suspend + */ + bool supportedOnlyInSuspend; + + /* + * voters is useful if the Platform-level sleep state + * is chosen by aggregation votes from multiple clients/system conditions. + * All the voters have to say yes or all the system conditions need to be + * met to enter a platform-level sleep state. + * + * Vector of size zero implies either the info is not available + * or the system does not follow a voting mechanism to choose this + * Platform-level sleep state. + */ + vec<PowerStateVoter> voters; +};
diff --git a/radio/1.0/vts/Android.mk b/power/1.0/vts/Android.mk similarity index 100% copy from radio/1.0/vts/Android.mk copy to power/1.0/vts/Android.mk
diff --git a/power/1.0/vts/functional/Android.bp b/power/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..5ab1eb4 --- /dev/null +++ b/power/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalPowerV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalPowerV1_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.power@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ] +}
diff --git a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp new file mode 100644 index 0000000..cd1a261 --- /dev/null +++ b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
@@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "power_hidl_hal_test" +#include <android-base/logging.h> + +#include <cutils/properties.h> + +#include <android-base/unique_fd.h> +#include <android/hardware/power/1.0/IPower.h> + +#include <VtsHalHidlTargetTestBase.h> + +#include <algorithm> + +using ::android::hardware::power::V1_0::IPower; +using ::android::hardware::power::V1_0::Feature; +using ::android::hardware::power::V1_0::PowerHint; +using ::android::hardware::power::V1_0::PowerStatePlatformSleepState; +using ::android::hardware::power::V1_0::Status; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::sp; +using ::android::base::unique_fd; + +using std::vector; + +#define CPU_GOVERNOR_PATH \ + "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" +#define AVAILABLE_GOVERNORS_PATH \ + "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors" + +class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(); + ASSERT_NE(power, nullptr); + } + + virtual void TearDown() override {} + + sp<IPower> power; +}; + +// Sanity check Power::setInteractive. +TEST_F(PowerHidlTest, SetInteractive) { + Return<void> ret; + + ret = power->setInteractive(true); + ASSERT_TRUE(ret.isOk()); + + ret = power->setInteractive(false); + ASSERT_TRUE(ret.isOk()); +} + +// Test Power::setInteractive and Power::powerHint(Launch) +// with each available CPU governor, if available +TEST_F(PowerHidlTest, TryDifferentGovernors) { + Return<void> ret; + + unique_fd fd1(open(CPU_GOVERNOR_PATH, O_RDWR)); + unique_fd fd2(open(AVAILABLE_GOVERNORS_PATH, O_RDONLY)); + if (fd1 < 0 || fd2 < 0) { + // Files don't exist, so skip the rest of the test case + SUCCEED(); + } + + char old_governor[80]; + ASSERT_LE(0, read(fd1, old_governor, 80)); + + char governors[1024]; + unsigned len = read(fd2, governors, 1024); + ASSERT_LE(0u, len); + governors[len] = '\0'; + + char *saveptr; + char *name = strtok_r(governors, " \n", &saveptr); + while (name) { + ASSERT_LE(0, write(fd1, name, strlen(name))); + ret = power->setInteractive(true); + ASSERT_TRUE(ret.isOk()); + + ret = power->setInteractive(false); + ASSERT_TRUE(ret.isOk()); + + ret = power->setInteractive(false); + ASSERT_TRUE(ret.isOk()); + + power->powerHint(PowerHint::LAUNCH, 1); + power->powerHint(PowerHint::LAUNCH, 0); + + name = strtok_r(NULL, " \n", &saveptr); + } + + ASSERT_LE(0, write(fd1, old_governor, strlen(old_governor))); +} + +// Sanity check Power::powerHint on good and bad inputs. +TEST_F(PowerHidlTest, PowerHint) { + PowerHint badHint = static_cast<PowerHint>(0xA); + auto hints = {PowerHint::VSYNC, PowerHint::INTERACTION, + PowerHint::VIDEO_ENCODE, PowerHint::VIDEO_DECODE, + PowerHint::LOW_POWER, PowerHint::SUSTAINED_PERFORMANCE, + PowerHint::VR_MODE, PowerHint::LAUNCH, + badHint}; + Return<void> ret; + for (auto hint : hints) { + ret = power->powerHint(hint, 30000); + ASSERT_TRUE(ret.isOk()); + + ret = power->powerHint(hint, 0); + ASSERT_TRUE(ret.isOk()); + } + + // Turning these hints on in different orders triggers different code paths, + // so iterate over possible orderings. + std::vector<PowerHint> hints2 = {PowerHint::LAUNCH, PowerHint::VR_MODE, + PowerHint::SUSTAINED_PERFORMANCE, + PowerHint::INTERACTION}; + auto compareHints = [](PowerHint l, PowerHint r) { + return static_cast<uint32_t>(l) < static_cast<uint32_t>(r); + }; + std::sort(hints2.begin(), hints2.end(), compareHints); + do { + for (auto iter = hints2.begin(); iter != hints2.end(); iter++) { + ret = power->powerHint(*iter, 0); + ASSERT_TRUE(ret.isOk()); + } + for (auto iter = hints2.begin(); iter != hints2.end(); iter++) { + ret = power->powerHint(*iter, 30000); + ASSERT_TRUE(ret.isOk()); + } + } while (std::next_permutation(hints2.begin(), hints2.end(), compareHints)); +} + +// Sanity check Power::setFeature() on good and bad inputs. +TEST_F(PowerHidlTest, SetFeature) { + Return<void> ret; + ret = power->setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, true); + ASSERT_TRUE(ret.isOk()); + ret = power->setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, false); + ASSERT_TRUE(ret.isOk()); + + Feature badFeature = static_cast<Feature>(0x2); + ret = power->setFeature(badFeature, true); + ASSERT_TRUE(ret.isOk()); + ret = power->setFeature(badFeature, false); + ASSERT_TRUE(ret.isOk()); +} + +// Sanity check Power::getPlatformLowPowerStats(). +TEST_F(PowerHidlTest, GetPlatformLowPowerStats) { + hidl_vec<PowerStatePlatformSleepState> vec; + Status s; + auto cb = [&vec, &s](hidl_vec<PowerStatePlatformSleepState> states, + Status status) { + vec = states; + s = status; + }; + Return<void> ret = power->getPlatformLowPowerStats(cb); + ASSERT_TRUE(ret.isOk()); + ASSERT_TRUE(s == Status::SUCCESS || s == Status::FILESYSTEM_ERROR); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +}
diff --git a/power/Android.bp b/power/Android.bp new file mode 100644 index 0000000..ed19a37 --- /dev/null +++ b/power/Android.bp
@@ -0,0 +1,6 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/default", + "1.0/vts/functional", +]
diff --git a/sensors/1.0/Android.bp b/sensors/1.0/Android.bp new file mode 100644 index 0000000..8357dbe --- /dev/null +++ b/sensors/1.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.sensors@1.0_hal", + srcs: [ + "types.hal", + "ISensors.hal", + ], +} + +genrule { + name: "android.hardware.sensors@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.sensors@1.0", + srcs: [ + ":android.hardware.sensors@1.0_hal", + ], + out: [ + "android/hardware/sensors/1.0/types.cpp", + "android/hardware/sensors/1.0/SensorsAll.cpp", + ], +} + +genrule { + name: "android.hardware.sensors@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.sensors@1.0", + srcs: [ + ":android.hardware.sensors@1.0_hal", + ], + out: [ + "android/hardware/sensors/1.0/types.h", + "android/hardware/sensors/1.0/ISensors.h", + "android/hardware/sensors/1.0/IHwSensors.h", + "android/hardware/sensors/1.0/BnHwSensors.h", + "android/hardware/sensors/1.0/BpHwSensors.h", + "android/hardware/sensors/1.0/BsSensors.h", + ], +} + +cc_library_shared { + name: "android.hardware.sensors@1.0", + generated_sources: ["android.hardware.sensors@1.0_genc++"], + generated_headers: ["android.hardware.sensors@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.sensors@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/sensors/1.0/Android.mk b/sensors/1.0/Android.mk new file mode 100644 index 0000000..29f7c7e --- /dev/null +++ b/sensors/1.0/Android.mk
@@ -0,0 +1,40 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.sensors@1.0-java-constants +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +# +GEN := $(intermediates)/android/hardware/sensors/V1_0/Constants.java +$(GEN): $(HIDL) +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/ISensors.hal + +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava-constants \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.sensors@1.0 + +$(GEN): + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +# Avoid dependency cycle of framework.jar -> this-library -> framework.jar +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj + +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/sensors/1.0/ISensors.hal b/sensors/1.0/ISensors.hal new file mode 100644 index 0000000..5c8301a --- /dev/null +++ b/sensors/1.0/ISensors.hal
@@ -0,0 +1,195 @@ +/* + * Copyright (C) 2016 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.sensors@1.0; + +interface ISensors { + /** + * Enumerate all available (static) sensors. + */ + getSensorsList() generates (vec<SensorInfo> list); + + /** + * Place the module in a specific mode. The following modes are defined + * + * SENSOR_HAL_NORMAL_MODE - Normal operation. Default state of the module. + * + * SENSOR_HAL_DATA_INJECTION_MODE - Loopback mode. + * Data is injected for the supported sensors by the sensor service in + * this mode. + * + * @return OK on success + * BAD_VALUE if requested mode is not supported + * PERMISSION_DENIED if operation is not allowed + */ + setOperationMode(OperationMode mode) generates (Result result); + + /* Activate/de-activate one sensor. + * + * After sensor de-activation, existing sensor events that have not + * been picked up by poll() must be abandoned immediately so that + * subsequent activation will not get stale sensor events (events + * that are generated prior to the latter activation). + * + * @param sensorHandle is the handle of the sensor to change. + * @param enabled set to true to enable, or false to disable the sensor. + * + * @return result OK on success, BAD_VALUE if sensorHandle is invalid. + */ + activate(int32_t sensorHandle, bool enabled) generates (Result result); + + /** + * Generate a vector of sensor events containing at most "maxCount" + * entries. + * + * Additionally a vector of SensorInfos is returned for any dynamic sensors + * connected as notified by returned events of type DYNAMIC_SENSOR_META. + * + * If there is no sensor event when this function is being called, block + * until there are sensor events available. + * + * @param maxCount max number of samples can be returned, must be > 0. + * Actual number of events returned in data must be <= maxCount + * and > 0. + * @return result OK on success or BAD_VALUE if maxCount <= 0. + * @return data vector of Event contains sensor events. + * @return dynamicSensorsAdded vector of SensorInfo contains dynamic sensor + * added. Each element corresponds to a dynamic sensor meta events + * in data. + */ + poll(int32_t maxCount) + generates ( + Result result, + vec<Event> data, + vec<SensorInfo> dynamicSensorsAdded); + + /* + * Sets a sensor’s parameters, including sampling frequency and maximum + * report latency. This function can be called while the sensor is + * activated, in which case it must not cause any sensor measurements to + * be lost: transitioning from one sampling rate to the other cannot cause + * lost events, nor can transitioning from a high maximum report latency to + * a low maximum report latency. + * See the Batching sensor results page for details: + * http://source.android.com/devices/sensors/batching.html + * + * @param sensorHandle handle of sensor to be changed. + * @param samplingPeriodNs specifies sensor sample period in nanoseconds. + * @param maxReportLatencyNs allowed delay time before an event is sampled + * to time of report. + * @return result OK on success, BAD_VALUE if any parameters are invalid. + */ + batch(int32_t sensorHandle, + int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) generates (Result result); + + /* + * Trigger a flush of internal FIFO. + * + * Flush adds a FLUSH_COMPLETE metadata event to the end of the "batch mode" + * FIFO for the specified sensor and flushes the FIFO. If the FIFO is empty + * or if the sensor doesn't support batching (FIFO size zero), return + * SUCCESS and add a trivial FLUSH_COMPLETE event added to the event stream. + * This applies to all sensors other than one-shot sensors. If the sensor + * is a one-shot sensor, flush must return BAD_VALUE and not generate any + * flush complete metadata. If the sensor is not active at the time flush() + * is called, flush() return BAD_VALUE. + * + * @param sensorHandle handle of sensor to be flushed. + * @return result OK on success and BAD_VALUE if sensorHandle is invalid. + */ + flush(int32_t sensorHandle) generates (Result result); + + /* + * Inject a single sensor event or push operation environment parameters to + * device. + * + * When device is in NORMAL mode, this function is called to push operation + * environment data to device. In this operation, Event is always of + * SensorType::AdditionalInfo type. See operation evironment parameters + * section in AdditionalInfoType. + * + * When device is in DATA_INJECTION mode, this function is also used for + * injecting sensor events. + * + * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO + * type events should not be routed back to poll() function. + * + * @see AdditionalInfoType + * @see OperationMode + * @param event sensor event to be injected + * @return result OK on success; PERMISSION_DENIED if operation is not + * allowed; INVALID_OPERATION, if this functionality is + * unsupported; BAD_VALUE if sensor event cannot be injected. + */ + injectSensorData(Event event) generates (Result result); + + /* + * Register direct report channel. + * + * Register a direct channel with supplied shared memory information. Upon + * return, the sensor hardware is responsible for resetting the memory + * content to initial value (depending on memory format settings). + * + * @param mem shared memory info data structure. + * @return result OK on success; BAD_VALUE if shared memory information is + * not consistent; NO_MEMORY if shared memory cannot be used by + * sensor system; INVALID_OPERATION if functionality is not + * supported. + * @return channelHandle a positive integer used for referencing registered + * direct channel (>0) in configureDirectReport and + * unregisterDirectChannel if result is OK, -1 otherwise. + */ + registerDirectChannel(SharedMemInfo mem) + generates (Result result, int32_t channelHandle); + + /* + * Unregister direct report channel. + * + * Unregister a direct channel previously registered using + * registerDirectChannel, and remove all active sensor report configured in + * still active sensor report configured in the direct channel. + * + * @param channelHandle handle of direct channel to be unregistered. + * @return result OK if direct report is supported; INVALID_OPERATION + * otherwise. + */ + unregisterDirectChannel(int32_t channelHandle) generates (Result result); + + /* + * Configure direct sensor event report in direct channel. + * + * This function start, modify rate or stop direct report of a sensor in a + * certain direct channel. + * + * @param sensorHandle handle of sensor to be configured. When combined + * with STOP rate, sensorHandle can be -1 to denote all active + * sensors in the direct channel specified by channel Handle. + * @param channelHandle handle of direct channel to be configured. + * @param rate rate level, see RateLevel enum. + * + * @return result OK on success; BAD_VALUE if parameter is invalid (such as + * rate level is not supported by sensor, channelHandle does not + * exist, etc); INVALID_OPERATION if functionality is not + * supported. + * @return reportToken positive integer to identify multiple sensors of + * the same type in a single direct channel. Ignored if rate is + * STOP. See SharedMemFormat. + */ + configDirectReport( + int32_t sensorHandle, int32_t channelHandle, RateLevel rate) + generates (Result result, int32_t reportToken); +};
diff --git a/sensors/1.0/default/Android.bp b/sensors/1.0/default/Android.bp new file mode 100644 index 0000000..2ab1b90 --- /dev/null +++ b/sensors/1.0/default/Android.bp
@@ -0,0 +1,42 @@ +cc_library_shared { + name: "android.hardware.sensors@1.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["Sensors.cpp"], + shared_libs: [ + "liblog", + "libcutils", + "libhardware", + "libbase", + "libutils", + "libhidlbase", + "libhidltransport", + "android.hardware.sensors@1.0", + ], + static_libs: [ + "android.hardware.sensors@1.0-convert", + "multihal", + ], + local_include_dirs: ["include/sensors"], +} + +cc_library_static { + name: "android.hardware.sensors@1.0-convert", + defaults: ["hidl_defaults"], + srcs: ["convert.cpp"], + export_include_dirs: ["include"], + shared_libs: [ + "liblog", + "libcutils", + "libhardware", + "libbase", + "libutils", + "libhidlbase", + "libhidltransport", + "android.hardware.sensors@1.0", + ], + local_include_dirs: ["include/sensors"], +} + +
diff --git a/sensors/1.0/default/Android.mk b/sensors/1.0/default/Android.mk new file mode 100644 index 0000000..bc1cfbd --- /dev/null +++ b/sensors/1.0/default/Android.mk
@@ -0,0 +1,25 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.sensors@1.0-service +LOCAL_INIT_RC := android.hardware.sensors@1.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + +LOCAL_SHARED_LIBRARIES += \ + libhidlbase \ + libhidltransport \ + android.hardware.sensors@1.0 \ + +include $(BUILD_EXECUTABLE)
diff --git a/sensors/1.0/default/Sensors.cpp b/sensors/1.0/default/Sensors.cpp new file mode 100644 index 0000000..2457310 --- /dev/null +++ b/sensors/1.0/default/Sensors.cpp
@@ -0,0 +1,346 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "Sensors.h" +#include "convert.h" +#include "multihal.h" + +#include <android-base/logging.h> + +#include <sys/stat.h> + +namespace android { +namespace hardware { +namespace sensors { +namespace V1_0 { +namespace implementation { + +/* + * If a multi-hal configuration file exists in the proper location, + * return true indicating we need to use multi-hal functionality. + */ +static bool UseMultiHal() { + const std::string& name = MULTI_HAL_CONFIG_FILE_PATH; + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + +static Result ResultFromStatus(status_t err) { + switch (err) { + case OK: + return Result::OK; + case PERMISSION_DENIED: + return Result::PERMISSION_DENIED; + case NO_MEMORY: + return Result::NO_MEMORY; + case BAD_VALUE: + return Result::BAD_VALUE; + default: + return Result::INVALID_OPERATION; + } +} + +Sensors::Sensors() + : mInitCheck(NO_INIT), + mSensorModule(nullptr), + mSensorDevice(nullptr) { + status_t err = OK; + if (UseMultiHal()) { + mSensorModule = ::get_multi_hal_module_info(); + } else { + err = hw_get_module( + SENSORS_HARDWARE_MODULE_ID, + (hw_module_t const **)&mSensorModule); + } + if (mSensorModule == NULL) { + err = UNKNOWN_ERROR; + } + + if (err != OK) { + LOG(ERROR) << "Couldn't load " + << SENSORS_HARDWARE_MODULE_ID + << " module (" + << strerror(-err) + << ")"; + + mInitCheck = err; + return; + } + + err = sensors_open_1(&mSensorModule->common, &mSensorDevice); + + if (err != OK) { + LOG(ERROR) << "Couldn't open device for module " + << SENSORS_HARDWARE_MODULE_ID + << " (" + << strerror(-err) + << ")"; + + mInitCheck = err; + return; + } + + // Require all the old HAL APIs to be present except for injection, which + // is considered optional. + CHECK_GE(getHalDeviceVersion(), SENSORS_DEVICE_API_VERSION_1_3); + + mInitCheck = OK; +} + +status_t Sensors::initCheck() const { + return mInitCheck; +} + +Return<void> Sensors::getSensorsList(getSensorsList_cb _hidl_cb) { + sensor_t const *list; + size_t count = mSensorModule->get_sensors_list(mSensorModule, &list); + + hidl_vec<SensorInfo> out; + out.resize(count); + + for (size_t i = 0; i < count; ++i) { + const sensor_t *src = &list[i]; + SensorInfo *dst = &out[i]; + + convertFromSensor(*src, dst); + } + + _hidl_cb(out); + + return Void(); +} + +int Sensors::getHalDeviceVersion() const { + if (!mSensorDevice) { + return -1; + } + + return mSensorDevice->common.version; +} + +Return<Result> Sensors::setOperationMode(OperationMode mode) { + return ResultFromStatus(mSensorModule->set_operation_mode((uint32_t)mode)); +} + +Return<Result> Sensors::activate( + int32_t sensor_handle, bool enabled) { + return ResultFromStatus( + mSensorDevice->activate( + reinterpret_cast<sensors_poll_device_t *>(mSensorDevice), + sensor_handle, + enabled)); +} + +Return<void> Sensors::poll(int32_t maxCount, poll_cb _hidl_cb) { + + hidl_vec<Event> out; + hidl_vec<SensorInfo> dynamicSensorsAdded; + + std::unique_ptr<sensors_event_t[]> data; + int err = android::NO_ERROR; + + { // scope of reentry lock + + // This enforces a single client, meaning that a maximum of one client can call poll(). + // If this function is re-entred, it means that we are stuck in a state that may prevent + // the system from proceeding normally. + // + // Exit and let the system restart the sensor-hal-implementation hidl service. + // + // This function must not call _hidl_cb(...) or return until there is no risk of blocking. + std::unique_lock<std::mutex> lock(mPollLock, std::try_to_lock); + if(!lock.owns_lock()){ + // cannot get the lock, hidl service will go into deadlock if it is not restarted. + // This is guaranteed to not trigger in passthrough mode. + LOG(ERROR) << + "ISensors::poll() re-entry. I do not know what to do except killing myself."; + ::exit(-1); + } + + if (maxCount <= 0) { + err = android::BAD_VALUE; + } else { + int bufferSize = maxCount <= kPollMaxBufferSize ? maxCount : kPollMaxBufferSize; + data.reset(new sensors_event_t[bufferSize]); + err = mSensorDevice->poll( + reinterpret_cast<sensors_poll_device_t *>(mSensorDevice), + data.get(), bufferSize); + } + } + + if (err < 0) { + _hidl_cb(ResultFromStatus(err), out, dynamicSensorsAdded); + return Void(); + } + + const size_t count = (size_t)err; + + for (size_t i = 0; i < count; ++i) { + if (data[i].type != SENSOR_TYPE_DYNAMIC_SENSOR_META) { + continue; + } + + const dynamic_sensor_meta_event_t *dyn = &data[i].dynamic_sensor_meta; + + if (!dyn->connected) { + continue; + } + + CHECK(dyn->sensor != nullptr); + CHECK_EQ(dyn->sensor->handle, dyn->handle); + + SensorInfo info; + convertFromSensor(*dyn->sensor, &info); + + size_t numDynamicSensors = dynamicSensorsAdded.size(); + dynamicSensorsAdded.resize(numDynamicSensors + 1); + dynamicSensorsAdded[numDynamicSensors] = info; + } + + out.resize(count); + convertFromSensorEvents(err, data.get(), &out); + + _hidl_cb(Result::OK, out, dynamicSensorsAdded); + + return Void(); +} + +Return<Result> Sensors::batch( + int32_t sensor_handle, + int64_t sampling_period_ns, + int64_t max_report_latency_ns) { + return ResultFromStatus( + mSensorDevice->batch( + mSensorDevice, + sensor_handle, + 0, /*flags*/ + sampling_period_ns, + max_report_latency_ns)); +} + +Return<Result> Sensors::flush(int32_t sensor_handle) { + return ResultFromStatus(mSensorDevice->flush(mSensorDevice, sensor_handle)); +} + +Return<Result> Sensors::injectSensorData(const Event& event) { + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) { + return Result::INVALID_OPERATION; + } + + sensors_event_t out; + convertToSensorEvent(event, &out); + + return ResultFromStatus( + mSensorDevice->inject_sensor_data(mSensorDevice, &out)); +} + +Return<void> Sensors::registerDirectChannel( + const SharedMemInfo& mem, registerDirectChannel_cb _hidl_cb) { + if (mSensorDevice->register_direct_channel == nullptr + || mSensorDevice->config_direct_report == nullptr) { + // HAL does not support + _hidl_cb(Result::INVALID_OPERATION, -1); + return Void(); + } + + sensors_direct_mem_t m; + if (!convertFromSharedMemInfo(mem, &m)) { + _hidl_cb(Result::BAD_VALUE, -1); + return Void(); + } + + int err = mSensorDevice->register_direct_channel(mSensorDevice, &m, -1); + + if (err < 0) { + _hidl_cb(ResultFromStatus(err), -1); + } else { + int32_t channelHandle = static_cast<int32_t>(err); + _hidl_cb(Result::OK, channelHandle); + } + return Void(); +} + +Return<Result> Sensors::unregisterDirectChannel(int32_t channelHandle) { + if (mSensorDevice->register_direct_channel == nullptr + || mSensorDevice->config_direct_report == nullptr) { + // HAL does not support + return Result::INVALID_OPERATION; + } + + mSensorDevice->register_direct_channel(mSensorDevice, nullptr, channelHandle); + + return Result::OK; +} + +Return<void> Sensors::configDirectReport( + int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + configDirectReport_cb _hidl_cb) { + if (mSensorDevice->register_direct_channel == nullptr + || mSensorDevice->config_direct_report == nullptr) { + // HAL does not support + _hidl_cb(Result::INVALID_OPERATION, -1); + return Void(); + } + + sensors_direct_cfg_t cfg = { + .rate_level = convertFromRateLevel(rate) + }; + if (cfg.rate_level < 0) { + _hidl_cb(Result::BAD_VALUE, -1); + return Void(); + } + + int err = mSensorDevice->config_direct_report(mSensorDevice, + sensorHandle, channelHandle, &cfg); + + if (rate == RateLevel::STOP) { + _hidl_cb(ResultFromStatus(err), -1); + } else { + _hidl_cb(err > 0 ? Result::OK : ResultFromStatus(err), err); + } + return Void(); +} + +// static +void Sensors::convertFromSensorEvents( + size_t count, + const sensors_event_t *srcArray, + hidl_vec<Event> *dstVec) { + for (size_t i = 0; i < count; ++i) { + const sensors_event_t &src = srcArray[i]; + Event *dst = &(*dstVec)[i]; + + convertFromSensorEvent(src, dst); + } +} + +ISensors *HIDL_FETCH_ISensors(const char * /* hal */) { + Sensors *sensors = new Sensors; + if (sensors->initCheck() != OK) { + delete sensors; + sensors = nullptr; + + return nullptr; + } + + return sensors; +} + +} // namespace implementation +} // namespace V1_0 +} // namespace sensors +} // namespace hardware +} // namespace android
diff --git a/sensors/1.0/default/Sensors.h b/sensors/1.0/default/Sensors.h new file mode 100644 index 0000000..7d715e0 --- /dev/null +++ b/sensors/1.0/default/Sensors.h
@@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_SENSORS_H_ + +#define HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_SENSORS_H_ + +#include <android/hardware/sensors/1.0/ISensors.h> +#include <hardware/sensors.h> +#include <mutex> + +namespace android { +namespace hardware { +namespace sensors { +namespace V1_0 { +namespace implementation { + + +struct Sensors : public ::android::hardware::sensors::V1_0::ISensors { + Sensors(); + + status_t initCheck() const; + + Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override; + + Return<Result> setOperationMode(OperationMode mode) override; + + Return<Result> activate( + int32_t sensor_handle, bool enabled) override; + + Return<void> poll(int32_t maxCount, poll_cb _hidl_cb) override; + + Return<Result> batch( + int32_t sensor_handle, + int64_t sampling_period_ns, + int64_t max_report_latency_ns) override; + + Return<Result> flush(int32_t sensor_handle) override; + + Return<Result> injectSensorData(const Event& event) override; + + Return<void> registerDirectChannel( + const SharedMemInfo& mem, registerDirectChannel_cb _hidl_cb) override; + + Return<Result> unregisterDirectChannel(int32_t channelHandle) override; + + Return<void> configDirectReport( + int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + configDirectReport_cb _hidl_cb) override; + +private: + static constexpr int32_t kPollMaxBufferSize = 128; + status_t mInitCheck; + sensors_module_t *mSensorModule; + sensors_poll_device_1_t *mSensorDevice; + std::mutex mPollLock; + + int getHalDeviceVersion() const; + + static void convertFromSensorEvents( + size_t count, const sensors_event_t *src, hidl_vec<Event> *dst); + + DISALLOW_COPY_AND_ASSIGN(Sensors); +}; + +extern "C" ISensors *HIDL_FETCH_ISensors(const char *name); + +} // namespace implementation +} // namespace V1_0 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_SENSORS_H_
diff --git a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc new file mode 100644 index 0000000..2360863 --- /dev/null +++ b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
@@ -0,0 +1,4 @@ +service sensors-hal-1-0 /vendor/bin/hw/android.hardware.sensors@1.0-service + class main + user system + group system readproc
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp new file mode 100644 index 0000000..306d3a3 --- /dev/null +++ b/sensors/1.0/default/convert.cpp
@@ -0,0 +1,400 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "convert.h" + +#include <android-base/logging.h> + +namespace android { +namespace hardware { +namespace sensors { +namespace V1_0 { +namespace implementation { + +void convertFromSensor(const sensor_t &src, SensorInfo *dst) { + dst->name = src.name; + dst->vendor = src.vendor; + dst->version = src.version; + dst->sensorHandle = src.handle; + dst->type = (SensorType)src.type; + dst->maxRange = src.maxRange; + dst->resolution = src.resolution; + dst->power = src.power; + dst->minDelay = src.minDelay; + dst->fifoReservedEventCount = src.fifoReservedEventCount; + dst->fifoMaxEventCount = src.fifoMaxEventCount; + dst->typeAsString = src.stringType; + dst->requiredPermission = src.requiredPermission; + dst->maxDelay = src.maxDelay; + dst->flags = src.flags; +} + +void convertToSensor( + const ::android::hardware::sensors::V1_0::SensorInfo &src, + sensor_t *dst) { + dst->name = strdup(src.name.c_str()); + dst->vendor = strdup(src.vendor.c_str()); + dst->version = src.version; + dst->handle = src.sensorHandle; + dst->type = (int)src.type; + dst->maxRange = src.maxRange; + dst->resolution = src.resolution; + dst->power = src.power; + dst->minDelay = src.minDelay; + dst->fifoReservedEventCount = src.fifoReservedEventCount; + dst->fifoMaxEventCount = src.fifoMaxEventCount; + dst->stringType = strdup(src.typeAsString.c_str()); + dst->requiredPermission = strdup(src.requiredPermission.c_str()); + dst->maxDelay = src.maxDelay; + dst->flags = src.flags; + dst->reserved[0] = dst->reserved[1] = 0; +} + +void convertFromSensorEvent(const sensors_event_t &src, Event *dst) { + typedef ::android::hardware::sensors::V1_0::SensorType SensorType; + typedef ::android::hardware::sensors::V1_0::MetaDataEventType MetaDataEventType; + + dst->sensorHandle = src.sensor; + dst->sensorType = (SensorType)src.type; + dst->timestamp = src.timestamp; + + switch (dst->sensorType) { + case SensorType::META_DATA: + { + dst->u.meta.what = (MetaDataEventType)src.meta_data.what; + // Legacy HALs contain the handle reference in the meta data field. + // Copy that over to the handle of the event. In legacy HALs this + // field was expected to be 0. + dst->sensorHandle = src.meta_data.sensor; + break; + } + + case SensorType::ACCELEROMETER: + case SensorType::MAGNETIC_FIELD: + case SensorType::ORIENTATION: + case SensorType::GYROSCOPE: + case SensorType::GRAVITY: + case SensorType::LINEAR_ACCELERATION: + { + dst->u.vec3.x = src.acceleration.x; + dst->u.vec3.y = src.acceleration.y; + dst->u.vec3.z = src.acceleration.z; + dst->u.vec3.status = (SensorStatus)src.acceleration.status; + break; + } + + case SensorType::ROTATION_VECTOR: + case SensorType::GAME_ROTATION_VECTOR: + case SensorType::GEOMAGNETIC_ROTATION_VECTOR: + { + dst->u.vec4.x = src.data[0]; + dst->u.vec4.y = src.data[1]; + dst->u.vec4.z = src.data[2]; + dst->u.vec4.w = src.data[3]; + break; + } + + case SensorType::MAGNETIC_FIELD_UNCALIBRATED: + case SensorType::GYROSCOPE_UNCALIBRATED: + case SensorType::ACCELEROMETER_UNCALIBRATED: + { + dst->u.uncal.x = src.uncalibrated_gyro.x_uncalib; + dst->u.uncal.y = src.uncalibrated_gyro.y_uncalib; + dst->u.uncal.z = src.uncalibrated_gyro.z_uncalib; + dst->u.uncal.x_bias = src.uncalibrated_gyro.x_bias; + dst->u.uncal.y_bias = src.uncalibrated_gyro.y_bias; + dst->u.uncal.z_bias = src.uncalibrated_gyro.z_bias; + break; + } + + case SensorType::DEVICE_ORIENTATION: + case SensorType::LIGHT: + case SensorType::PRESSURE: + case SensorType::TEMPERATURE: + case SensorType::PROXIMITY: + case SensorType::RELATIVE_HUMIDITY: + case SensorType::AMBIENT_TEMPERATURE: + case SensorType::SIGNIFICANT_MOTION: + case SensorType::STEP_DETECTOR: + case SensorType::TILT_DETECTOR: + case SensorType::WAKE_GESTURE: + case SensorType::GLANCE_GESTURE: + case SensorType::PICK_UP_GESTURE: + case SensorType::WRIST_TILT_GESTURE: + case SensorType::STATIONARY_DETECT: + case SensorType::MOTION_DETECT: + case SensorType::HEART_BEAT: + { + dst->u.scalar = src.data[0]; + break; + } + + case SensorType::STEP_COUNTER: + { + dst->u.stepCount = src.u64.step_counter; + break; + } + + case SensorType::HEART_RATE: + { + dst->u.heartRate.bpm = src.heart_rate.bpm; + dst->u.heartRate.status = (SensorStatus)src.heart_rate.status; + break; + } + + case SensorType::POSE_6DOF: // 15 floats + { + for (size_t i = 0; i < 15; ++i) { + dst->u.pose6DOF[i] = src.data[i]; + } + break; + } + + case SensorType::DYNAMIC_SENSOR_META: + { + dst->u.dynamic.connected = src.dynamic_sensor_meta.connected; + dst->u.dynamic.sensorHandle = src.dynamic_sensor_meta.handle; + + memcpy(dst->u.dynamic.uuid.data(), + src.dynamic_sensor_meta.uuid, + 16); + + break; + } + + case SensorType::ADDITIONAL_INFO: + { + ::android::hardware::sensors::V1_0::AdditionalInfo *dstInfo = + &dst->u.additional; + + const additional_info_event_t &srcInfo = src.additional_info; + + dstInfo->type = + (::android::hardware::sensors::V1_0::AdditionalInfoType) + srcInfo.type; + + dstInfo->serial = srcInfo.serial; + + CHECK_EQ(sizeof(dstInfo->u), sizeof(srcInfo.data_int32)); + memcpy(&dstInfo->u, srcInfo.data_int32, sizeof(srcInfo.data_int32)); + break; + } + + default: + { + CHECK_GE((int32_t)dst->sensorType, + (int32_t)SensorType::DEVICE_PRIVATE_BASE); + + memcpy(dst->u.data.data(), src.data, 16 * sizeof(float)); + break; + } + } +} + +void convertToSensorEvent(const Event &src, sensors_event_t *dst) { + dst->version = sizeof(sensors_event_t); + dst->sensor = src.sensorHandle; + dst->type = (int32_t)src.sensorType; + dst->reserved0 = 0; + dst->timestamp = src.timestamp; + dst->flags = 0; + dst->reserved1[0] = dst->reserved1[1] = dst->reserved1[2] = 0; + + switch (src.sensorType) { + case SensorType::META_DATA: + { + // Legacy HALs expect the handle reference in the meta data field. + // Copy it over from the handle of the event. + dst->meta_data.what = (int32_t)src.u.meta.what; + dst->meta_data.sensor = src.sensorHandle; + // Set the sensor handle to 0 to maintain compatibility. + dst->sensor = 0; + break; + } + + case SensorType::ACCELEROMETER: + case SensorType::MAGNETIC_FIELD: + case SensorType::ORIENTATION: + case SensorType::GYROSCOPE: + case SensorType::GRAVITY: + case SensorType::LINEAR_ACCELERATION: + { + dst->acceleration.x = src.u.vec3.x; + dst->acceleration.y = src.u.vec3.y; + dst->acceleration.z = src.u.vec3.z; + dst->acceleration.status = (int8_t)src.u.vec3.status; + break; + } + + case SensorType::ROTATION_VECTOR: + case SensorType::GAME_ROTATION_VECTOR: + case SensorType::GEOMAGNETIC_ROTATION_VECTOR: + { + dst->data[0] = src.u.vec4.x; + dst->data[1] = src.u.vec4.y; + dst->data[2] = src.u.vec4.z; + dst->data[3] = src.u.vec4.w; + break; + } + + case SensorType::MAGNETIC_FIELD_UNCALIBRATED: + case SensorType::GYROSCOPE_UNCALIBRATED: + case SensorType::ACCELEROMETER_UNCALIBRATED: + { + dst->uncalibrated_gyro.x_uncalib = src.u.uncal.x; + dst->uncalibrated_gyro.y_uncalib = src.u.uncal.y; + dst->uncalibrated_gyro.z_uncalib = src.u.uncal.z; + dst->uncalibrated_gyro.x_bias = src.u.uncal.x_bias; + dst->uncalibrated_gyro.y_bias = src.u.uncal.y_bias; + dst->uncalibrated_gyro.z_bias = src.u.uncal.z_bias; + break; + } + + case SensorType::DEVICE_ORIENTATION: + case SensorType::LIGHT: + case SensorType::PRESSURE: + case SensorType::TEMPERATURE: + case SensorType::PROXIMITY: + case SensorType::RELATIVE_HUMIDITY: + case SensorType::AMBIENT_TEMPERATURE: + case SensorType::SIGNIFICANT_MOTION: + case SensorType::STEP_DETECTOR: + case SensorType::TILT_DETECTOR: + case SensorType::WAKE_GESTURE: + case SensorType::GLANCE_GESTURE: + case SensorType::PICK_UP_GESTURE: + case SensorType::WRIST_TILT_GESTURE: + case SensorType::STATIONARY_DETECT: + case SensorType::MOTION_DETECT: + case SensorType::HEART_BEAT: + { + dst->data[0] = src.u.scalar; + break; + } + + case SensorType::STEP_COUNTER: + { + dst->u64.step_counter = src.u.stepCount; + break; + } + + case SensorType::HEART_RATE: + { + dst->heart_rate.bpm = src.u.heartRate.bpm; + dst->heart_rate.status = (int8_t)src.u.heartRate.status; + break; + } + + case SensorType::POSE_6DOF: // 15 floats + { + for (size_t i = 0; i < 15; ++i) { + dst->data[i] = src.u.pose6DOF[i]; + } + break; + } + + case SensorType::DYNAMIC_SENSOR_META: + { + dst->dynamic_sensor_meta.connected = src.u.dynamic.connected; + dst->dynamic_sensor_meta.handle = src.u.dynamic.sensorHandle; + dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later + + memcpy(dst->dynamic_sensor_meta.uuid, + src.u.dynamic.uuid.data(), + 16); + + break; + } + + case SensorType::ADDITIONAL_INFO: + { + const ::android::hardware::sensors::V1_0::AdditionalInfo &srcInfo = + src.u.additional; + + additional_info_event_t *dstInfo = &dst->additional_info; + dstInfo->type = (int32_t)srcInfo.type; + dstInfo->serial = srcInfo.serial; + + CHECK_EQ(sizeof(srcInfo.u), sizeof(dstInfo->data_int32)); + + memcpy(dstInfo->data_int32, + &srcInfo.u, + sizeof(dstInfo->data_int32)); + + break; + } + + default: + { + CHECK_GE((int32_t)src.sensorType, + (int32_t)SensorType::DEVICE_PRIVATE_BASE); + + memcpy(dst->data, src.u.data.data(), 16 * sizeof(float)); + break; + } + } +} + +bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut) { + if (memOut == nullptr) { + return false; + } + + switch(memIn.type) { + case SharedMemType::ASHMEM: + memOut->type = SENSOR_DIRECT_MEM_TYPE_ASHMEM; + break; + case SharedMemType::GRALLOC: + memOut->type = SENSOR_DIRECT_MEM_TYPE_GRALLOC; + break; + default: + return false; + } + + switch(memIn.format) { + case SharedMemFormat::SENSORS_EVENT: + memOut->format = SENSOR_DIRECT_FMT_SENSORS_EVENT; + break; + default: + return false; + } + + memOut->size = memIn.size; + memOut->handle = memIn.memoryHandle; + return true; +} + +int convertFromRateLevel(RateLevel rate) { + switch(rate) { + case RateLevel::STOP: + return SENSOR_DIRECT_RATE_STOP; + case RateLevel::NORMAL: + return SENSOR_DIRECT_RATE_NORMAL; + case RateLevel::FAST: + return SENSOR_DIRECT_RATE_FAST; + case RateLevel::VERY_FAST: + return SENSOR_DIRECT_RATE_VERY_FAST; + default: + return -1; + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace sensors +} // namespace hardware +} // namespace android +
diff --git a/sensors/1.0/default/include/sensors/convert.h b/sensors/1.0/default/include/sensors/convert.h new file mode 100644 index 0000000..c3a0125 --- /dev/null +++ b/sensors/1.0/default/include/sensors/convert.h
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_INCLUDE_CONVERT_H_ + +#define HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_INCLUDE_CONVERT_H_ + +#include <android/hardware/sensors/1.0/ISensors.h> +#include <hardware/sensors.h> + +namespace android { +namespace hardware { +namespace sensors { +namespace V1_0 { +namespace implementation { + +void convertFromSensor(const sensor_t &src, SensorInfo *dst); +void convertToSensor(const SensorInfo &src, sensor_t *dst); + +void convertFromSensorEvent(const sensors_event_t &src, Event *dst); +void convertToSensorEvent(const Event &src, sensors_event_t *dst); + +bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut); +int convertFromRateLevel(RateLevel rate); + +} // namespace implementation +} // namespace V1_0 +} // namespace sensors +} // namespace hardware +} // namespace android + +#endif // HARDWARE_INTERFACES_SENSORS_V1_0_DEFAULT_INCLUDE_CONVERT_H_
diff --git a/sensors/1.0/default/service.cpp b/sensors/1.0/default/service.cpp new file mode 100644 index 0000000..65f6d81 --- /dev/null +++ b/sensors/1.0/default/service.cpp
@@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.sensors@1.0-service" + +#include <android/hardware/sensors/1.0/ISensors.h> +#include <hidl/LegacySupport.h> + +using android::hardware::sensors::V1_0::ISensors; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + /* Sensors framework service needs at least two threads. + * One thread blocks on a "poll" + * The second thread is needed for all other HAL methods. + */ + return defaultPassthroughServiceImplementation<ISensors>(2); +}
diff --git a/sensors/1.0/types.hal b/sensors/1.0/types.hal new file mode 100644 index 0000000..c0d8c5d --- /dev/null +++ b/sensors/1.0/types.hal
@@ -0,0 +1,1263 @@ +/* + * Copyright (C) 2016 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.sensors@1.0; + +/** + * Please see the Sensors section of source.android.com for an + * introduction to and detailed descriptions of Android sensor types: + * http://source.android.com/devices/sensors/index.html + */ + +/* Type enumerating various result codes returned from ISensors methods */ +enum Result : int32_t { + OK, + PERMISSION_DENIED = -1, + NO_MEMORY = -12, + BAD_VALUE = -22, + INVALID_OPERATION = -38, +}; + +/* + * Sensor HAL modes used in setOperationMode method + */ +@export(name="", value_prefix="SENSOR_HAL_", value_suffix="_MODE") +enum OperationMode : int32_t { + NORMAL = 0, + DATA_INJECTION = 1, +}; + +/* + * Sensor type + * + * Each sensor has a type which defines what this sensor measures and how + * measures are reported. See the Base sensors and Composite sensors lists + * for complete descriptions: + * http://source.android.com/devices/sensors/base_triggers.html + * http://source.android.com/devices/sensors/composite_sensors.html + * + * Device manufacturers (OEMs) can define their own sensor types, for + * their private use by applications or services provided by them. Such + * sensor types are specific to an OEM and can't be exposed in the SDK. + * These types must start at SensorType::DEVICE_PRIVATE_BASE. + * + * All sensors defined outside of the device private range must correspond to + * a type defined in this file, and must satisfy the characteristics listed in + * the description of the sensor type. + * + * Each sensor also has a "typeAsString". + * - string type of sensors defined in this file is overridden by Android to + * values defined in Android API with "android.sensor." prefix. + * Example: for an accelerometer, + * type = SensorType::Acclerometer + * typeAsString = "" (will be replace by "android.sensor.accelerometer" by + * Android frameowrk) + * - string type of sensors inside of the device private range MUST be prefixed + * by the sensor provider's or OEM reverse domain name. In particular, they + * cannot use the "android.sensor." prefix. + * + * When android introduces a new sensor type that can replace an OEM-defined + * sensor type, the OEM must use the official sensor type and stringType on + * versions of the HAL that support this new official sensor type. + * + * Example (made up): Suppose Google's Glass team wants to surface a sensor + * detecting that Glass is on a head. + * - Such a sensor is not officially supported in android KitKat + * - Glass devices launching on KitKat can implement a sensor with + * type = 0x10001 + * typeAsString = "com.google.glass.onheaddetector" + * - In L android release, if android decides to define + * SensorType::ON_HEAD_DETECTOR and STRING_SensorType::ON_HEAD_DETECTOR, + * those types should replace the Glass-team-specific types in all future + * launches. + * - When launching Glass on the L release, Google should now use the official + * type (SensorType::ON_HEAD_DETECTOR) and stringType. + * - This way, all applications can now use this sensor. + */ + +/* + * Wake up sensors. + * Each sensor may have either or both a wake-up and a non-wake variant. + * When registered in batch mode, wake-up sensors will wake up the AP when + * their FIFOs are full or when the batch timeout expires. A separate FIFO has + * to be maintained for wake up sensors and non wake up sensors. The non + * wake-up sensors need to overwrite their FIFOs when they are full till the AP + * wakes up and the wake-up sensors will wake-up the AP when their FIFOs are + * full or when the batch timeout expires without losing events. + * Wake-up and non wake-up variants of each sensor can be activated at + * different rates independently of each other. + * + * Note: Proximity sensor and significant motion sensor which were defined in + * previous releases are also wake-up sensors and must be treated as such. + * Wake-up one-shot sensors like SIGNIFICANT_MOTION cannot be batched, hence + * the text about batch above doesn't apply to them. See the definitions of + * SensorType::PROXIMITY and SensorType::SIGNIFICANT_MOTION for more info. + * + * Set SENSOR_FLAG_WAKE_UP flag for all wake-up sensors. + * + * For example, A device can have two sensors both of SensorType::ACCELEROMETER + * and one of them can be a wake_up sensor (with SENSOR_FLAG_WAKE_UP flag set) + * and the other can be a regular non wake_up sensor. Both of these sensors + * must be activated/deactivated independently of the other. + */ + +@export(name="", value_prefix="SENSOR_TYPE_") +enum SensorType : int32_t { + /* META_DATA is a special event type used to populate the MetaData + * structure. It doesn't correspond to a physical sensor. Events of this + * type exist only inside the HAL, their primary purpose is to signal the + * completion of a flush request. + */ + META_DATA = 0, + + /* + * ACCELEROMETER + * reporting-mode: continuous + * + * All values are in SI units (m/s^2) and measure the acceleration of the + * device minus the acceleration due to gravity. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + ACCELEROMETER = 1, + + /* + * MAGNETIC_FIELD + * reporting-mode: continuous + * + * All values are in micro-Tesla (uT) and measure the geomagnetic + * field in the X, Y and Z axis. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + MAGNETIC_FIELD = 2, + + /* + * ORIENTATION + * reporting-mode: continuous + * + * All values are angles in degrees. + * + * Orientation sensors return sensor events for all 3 axes at a constant + * rate defined by setDelay(). + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + ORIENTATION = 3, + + /* + * GYROSCOPE + * reporting-mode: continuous + * + * All values are in radians/second and measure the rate of rotation + * around the X, Y and Z axis. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + GYROSCOPE = 4, + + /* + * LIGHT + * reporting-mode: on-change + * + * The light sensor value is returned in SI lux units. + * + * Both wake-up and non wake-up versions are useful. + */ + LIGHT = 5, + + /* + * PRESSURE + * reporting-mode: continuous + * + * The pressure sensor return the athmospheric pressure in hectopascal (hPa) + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + PRESSURE = 6, + + /* TEMPERATURE is deprecated in the HAL */ + TEMPERATURE = 7, + + /* + * PROXIMITY + * reporting-mode: on-change + * + * The proximity sensor which turns the screen off and back on during calls + * is the wake-up proximity sensor. Implement wake-up proximity sensor + * before implementing a non wake-up proximity sensor. For the wake-up + * proximity sensor set the flag SENSOR_FLAG_WAKE_UP. + * The value corresponds to the distance to the nearest object in + * centimeters. + */ + PROXIMITY = 8, + + /* + * GRAVITY + * reporting-mode: continuous + * + * A gravity output indicates the direction of and magnitude of gravity in + * the devices's coordinates. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + GRAVITY = 9, + + /* + * LINEAR_ACCELERATION + * reporting-mode: continuous + * + * Indicates the linear acceleration of the device in device coordinates, + * not including gravity. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + LINEAR_ACCELERATION = 10, + + /* + * ROTATION_VECTOR + * reporting-mode: continuous + * + * The rotation vector symbolizes the orientation of the device relative to + * the East-North-Up coordinates frame. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + ROTATION_VECTOR = 11, + + /* + * RELATIVE_HUMIDITY + * reporting-mode: on-change + * + * A relative humidity sensor measures relative ambient air humidity and + * returns a value in percent. + * + * Both wake-up and non wake-up versions are useful. + */ + RELATIVE_HUMIDITY = 12, + + /* + * AMBIENT_TEMPERATURE + * reporting-mode: on-change + * + * The ambient (room) temperature in degree Celsius. + * + * Both wake-up and non wake-up versions are useful. + */ + AMBIENT_TEMPERATURE = 13, + + /* + * MAGNETIC_FIELD_UNCALIBRATED + * reporting-mode: continuous + * + * Similar to MAGNETIC_FIELD, but the hard iron calibration is + * reported separately instead of being included in the measurement. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + MAGNETIC_FIELD_UNCALIBRATED = 14, + + /* + * GAME_ROTATION_VECTOR + * reporting-mode: continuous + * + * Similar to ROTATION_VECTOR, but not using the geomagnetic + * field. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + GAME_ROTATION_VECTOR = 15, + + /* + * GYROSCOPE_UNCALIBRATED + * reporting-mode: continuous + * + * All values are in radians/second and measure the rate of rotation + * around the X, Y and Z axis. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + GYROSCOPE_UNCALIBRATED = 16, + + /* + * SIGNIFICANT_MOTION + * reporting-mode: one-shot + * + * A sensor of this type triggers an event each time significant motion + * is detected and automatically disables itself. + * For Significant Motion sensor to be useful, it must be defined as a + * wake-up sensor. (set SENSOR_FLAG_WAKE_UP). Implement the wake-up + * significant motion sensor. A non wake-up version is not useful. + * The only allowed value to return is 1.0. + */ + SIGNIFICANT_MOTION = 17, + + /* + * STEP_DETECTOR + * reporting-mode: special + * + * A sensor of this type triggers an event each time a step is taken + * by the user. The only allowed value to return is 1.0 and an event + * is generated for each step. + * + * Both wake-up and non wake-up versions are useful. + */ + STEP_DETECTOR = 18, + + /* + * STEP_COUNTER + * reporting-mode: on-change + * + * A sensor of this type returns the number of steps taken by the user since + * the last reboot while activated. The value is returned as a uint64_t and + * is reset to zero only on a system / android reboot. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + STEP_COUNTER = 19, + + /* + * GEOMAGNETIC_ROTATION_VECTOR + * reporting-mode: continuous + * + * Similar to ROTATION_VECTOR, but using a magnetometer instead + * of using a gyroscope. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + GEOMAGNETIC_ROTATION_VECTOR = 20, + + /* + * HEART_RATE + * reporting-mode: on-change + * + * A sensor of this type returns the current heart rate. + * The events contain the current heart rate in beats per minute (BPM) and + * the status of the sensor during the measurement. See "HeartRate" below + * for more details. + * + * Because this sensor is on-change, events must be generated when and only + * when heart_rate.bpm or heart_rate.status have changed since the last + * event. In particular, upon the first activation, unless the device is + * known to not be on the body, the status field of the first event must be + * set to SensorStatus::UNRELIABLE. The event should be generated no faster + * than every period_ns passed to setDelay() or to batch(). + * See the definition of the on-change reporting mode for more information. + * + * SensorInfo.requiredPermission must be set to + * SENSOR_PERMISSION_BODY_SENSORS. + * + * Both wake-up and non wake-up versions are useful. + */ + HEART_RATE = 21, + + /* + * WAKE_UP_TILT_DETECTOR + * reporting-mode: special (setDelay has no impact) + * + * A sensor of this type generates an event each time a tilt event is + * detected. A tilt event must be generated if the direction of the + * 2-seconds window average gravity changed by at least 35 degrees since the + * activation or the last trigger of the sensor. + * + * reference_estimated_gravity = average of accelerometer measurements over + * the first 1 second after activation or the estimated gravity at the last + * trigger. + * + * current_estimated_gravity = average of accelerometer measurements over + * the last 2 seconds. + * + * trigger when + * angle(reference_estimated_gravity, current_estimated_gravity) + * > 35 degrees + * + * Large accelerations without a change in phone orientation must not + * trigger a tilt event. + * For example, a sharp turn or strong acceleration while driving a car + * must not trigger a tilt event, even though the angle of the average + * acceleration might vary by more than 35 degrees. + * + * Typically, this sensor is implemented with the help of only an + * accelerometer. Other sensors can be used as well if they do not increase + * the power consumption significantly. This is a low power sensor that + * must allow the AP to go into suspend mode. Do not emulate this sensor + * in the HAL. + * Like other wake up sensors, the driver is expected to a hold a wake_lock + * with a timeout of 200 ms while reporting this event. The only allowed + * return value is 1.0. + * + * Implement only the wake-up version of this sensor. + */ + TILT_DETECTOR = 22, + + /* + * WAKE_GESTURE + * reporting-mode: one-shot + * + * A sensor enabling waking up the device based on a device specific motion. + * + * When this sensor triggers, the device behaves as if the power button was + * pressed, turning the screen on. This behavior (turning on the screen when + * this sensor triggers) might be deactivated by the user in the device + * settings. Changes in settings do not impact the behavior of the sensor: + * only whether the framework turns the screen on when it triggers. + * + * The actual gesture to be detected is not specified, and can be chosen by + * the manufacturer of the device. + * This sensor must be low power, as it is likely to be activated 24/7. + * The only allowed value to return is 1.0. + * + * Implement only the wake-up version of this sensor. + */ + WAKE_GESTURE = 23, + + /* + * GLANCE_GESTURE + * reporting-mode: one-shot + * + * A sensor enabling briefly turning the screen on to enable the user to + * glance content on screen based on a specific motion. The device must + * turn the screen off after a few moments. + * + * When this sensor triggers, the device turns the screen on momentarily + * to allow the user to glance notifications or other content while the + * device remains locked in a non-interactive state (dozing). This behavior + * (briefly turning on the screen when this sensor triggers) might be + * deactivated by the user in the device settings. + * Changes in settings do not impact the behavior of the sensor: only + * whether the framework briefly turns the screen on when it triggers. + * + * The actual gesture to be detected is not specified, and can be chosen by + * the manufacturer of the device. + * This sensor must be low power, as it is likely to be activated 24/7. + * The only allowed value to return is 1.0. + * + * Implement only the wake-up version of this sensor. + */ + GLANCE_GESTURE = 24, + + /** + * PICK_UP_GESTURE + * reporting-mode: one-shot + * + * A sensor of this type triggers when the device is picked up regardless of + * wherever is was before (desk, pocket, bag). The only allowed return value + * is 1.0. This sensor de-activates itself immediately after it triggers. + * + * Implement only the wake-up version of this sensor. + */ + PICK_UP_GESTURE = 25, + + /* + * WRIST_TILT_GESTURE + * trigger-mode: special + * wake-up sensor: yes + * + * A sensor of this type triggers an event each time a tilt of the + * wrist-worn device is detected. + * + * This sensor must be low power, as it is likely to be activated 24/7. + * The only allowed value to return is 1.0. + * + * Implement only the wake-up version of this sensor. + */ + WRIST_TILT_GESTURE = 26, + + /* + * DEVICE_ORIENTATION + * reporting-mode: on-change + * + * The current orientation of the device. The value is reported in + * the "scalar" element of the EventPayload in Event. The + * only values that can be reported are (please refer to Android Sensor + * Coordinate System to understand the X and Y axis direction with respect + * to default orientation): + * - 0: device is in default orientation (Y axis is vertical and points up) + * - 1: device is rotated 90 degrees counter-clockwise from default + * orientation (X axis is vertical and points up) + * - 2: device is rotated 180 degrees from default orientation (Y axis is + * vertical and points down) + * - 3: device is rotated 90 degrees clockwise from default orientation + * (X axis is vertical and points down) + * + * Moving the device to an orientation where the Z axis is vertical (either + * up or down) must not cause a new event to be reported. + * + * To improve the user experience of this sensor, it is recommended to + * implement some physical (i.e., rotation angle) and temporal (i.e., delay) + * hysteresis. In other words, minor or transient rotations must not cause + * a new event to be reported. + * + * This is a low power sensor that intended to reduce interrupts of + * application processor and thus allow it to go sleep. Use hardware + * implementation based on low power consumption sensors, such as + * accelerometer. Device must not emulate this sensor in the HAL. + * + * Both wake-up and non wake-up versions are useful. + */ + DEVICE_ORIENTATION = 27, + + /* + * POSE_6DOF + * trigger-mode: continuous + * + * A sensor of this type returns the pose of the device. + * Pose of the device is defined as the orientation of the device from a + * Earth Centered Earth Fixed frame and the translation from an arbitrary + * point at subscription. + * + * This sensor can be high power. It can use any and all of the following + * . Accelerometer + * . Gyroscope + * . Camera + * . Depth Camera + * + */ + POSE_6DOF = 28, + + /* + * STATIONARY_DETECT + * trigger mode: one shot + * + * A sensor of this type returns an event if the device is still/stationary + * for a while. The period of time to monitor for stationarity must be + * greater than 5 seconds. The latency must be less than 10 seconds. + * + * Stationarity here refers to absolute stationarity. eg: device on desk. + * + * The only allowed value to return is 1.0. + */ + STATIONARY_DETECT = 29, + + /* + * MOTION_DETECT + * trigger mode: one shot + * + * A sensor of this type returns an event if the device is not still for + * for a while. The period of time to monitor for stationarity must be + * greater than 5 seconds. The latency must be less than 10 seconds. + * + * Motion here refers to any mechanism in which the device is causes to be + * moved in its inertial frame. eg: Pickin up the device and walking with it + * to a nearby room may trigger motion wherewas keeping the device on a + * table on a smooth train moving at constant velocity may not trigger + * motion. + * + * The only allowed value to return is 1.0. + */ + MOTION_DETECT = 30, + + /* + * HEART_BEAT + * trigger mode: continuous + * + * A sensor of this type returns an event everytime a hear beat peak is + * detected. + * + * Peak here ideally corresponds to the positive peak in the QRS complex of + * and ECG signal. + * + * The sensor is not expected to be optimized for latency. As a guide, a + * latency of up to 10 seconds is acceptable. However, the timestamp attached + * to the event must be accuratly correspond to the time the peak occured. + * + * The sensor event contains a parameter for the confidence in the detection + * of the peak where 0.0 represent no information at all, and 1.0 represents + * certainty. + */ + HEART_BEAT = 31, + + /** + * DYNAMIC_SENSOR_META + * trigger-mode: special + * wake-up sensor: yes + * + * A sensor event of this type is received when a dynamic sensor is added to + * or removed from the system. At most one sensor of this type can be + * present in one sensor HAL implementation and presence of a sensor of this + * type in sensor HAL implementation indicates that this sensor HAL supports + * dynamic sensor feature. Operations, such as batch, activate and setDelay, + * to this special purpose sensor must be treated as no-op and return + * successful; flush() also has to generate flush complete event as if this + * is a sensor that does not support batching. + * + * A dynamic sensor connection indicates connection of a physical device or + * instantiation of a virtual sensor backed by algorithm; and a dynamic + * sensor disconnection indicates the the opposite. A sensor event of + * DYNAMIC_SENSOR_META type should be delivered regardless of + * the activation status of the sensor in the event of dynamic sensor + * connection and disconnection. In the sensor event, besides the common + * data entries, "dynamic_sensor_meta", which includes fields for connection + * status, handle of the sensor involved, pointer to sensor_t structure and + * a uuid field, must be populated. + * + * At a dynamic sensor connection event, fields of sensor_t structure + * referenced by a pointer in dynamic_sensor_meta must be filled as if it + * was regular sensors. Sensor HAL is responsible for recovery of memory if + * the corresponding data is dynamicially allocated. However, the the + * pointer must be valid until the first activate call to the sensor + * reported in this connection event. At a dynamic sensor disconnection, + * the sensor_t pointer must be NULL. + * + * The sensor handle assigned to dynamic sensors must never be the same as + * that of any regular static sensors, and must be unique until next boot. + * In another word, if a handle h is used for a dynamic sensor A, that same + * number cannot be used for the same dynamic sensor A or another dynamic + * sensor B even after disconnection of A until reboot. + * + * The UUID field will be used for identifying the sensor in addition to + * name, vendor and version and type. For physical sensors of the same + * model, all sensors will have the same values in sensor_t, but the UUID + * must be unique and persistent for each individual unit. An all zero + * UUID indicates it is not possible to differentiate individual sensor + * unit. + * + */ + DYNAMIC_SENSOR_META = 32, + + /** + * ADDITIONAL_INFO + * reporting-mode: N/A + * + * This sensor type is for delivering additional sensor information aside + * from sensor event data. + * Additional information may include sensor front-end group delay, internal + * calibration parameters, noise level metrics, device internal temperature, + * etc. + * + * This type will never bind to a sensor. In other words, no sensor in the + * sensor list can have the type SENSOR_TYPE_ADDITIONAL_INFO. If a + * sensor HAL supports sensor additional information feature, it reports + * sensor_event_t with "sensor" field set to handle of the reporting sensor + * and "type" field set to ADDITIONAL_INFO. Delivery of + * additional information events is triggered under two conditions: an + * enable activate() call or a flush() call to the corresponding sensor. + * Besides, time varying parameters can update infrequently without being + * triggered. Device is responsible to control update rate. The recommend + * update rate is less than 1/1000 of sensor event rate or less than once + * per minute in average. + * + * A single additional information report consists of multiple frames. + * Sequences of these frames are ordered using timestamps, which means the + * timestamps of sequential frames have to be at least 1 nanosecond apart + * from each other. Each frame is a sensor_event_t delivered through the HAL + * interface, with related data stored in the "additional_info" field, which + * is of type additional_info_event_t. + * The "type" field of additional_info_event_t denotes the nature of the + * payload data (see additional_info_type_t). + * The "serial" field is used to keep the sequence of payload data that + * spans multiple frames. The first frame of the entire report is always of + * type AINFO_BEGIN, and the last frame is always AINFO_END. + * + * If flush() was triggering the report, all additional information frames + * must be delivered after flush complete event. + */ + ADDITIONAL_INFO = 33, + + /* + * LOW_LATENCY_OFFBODY_DETECT + * trigger-mode: on-change + * wake-up sensor: yes + * + * A sensor of this type is defined for devices that are supposed to be worn + * by the user in the normal use case (such as a watch, wristband, etc) and + * is not yet defined for other device. + * + * A sensor of this type triggers an event each time the wearable device + * is removed from the body and each time it's put back onto the body. + * It must be low-latency and be able to detect the on-body to off-body + * transition within one second (event delivery time included), + * and 3-second latency to determine the off-body to on-body transition + * (event delivery time included). + * + * There are only two valid event values for the sensor to return : + * 0.0 for off-body + * 1.0 for on-body + * + */ + LOW_LATENCY_OFFBODY_DETECT = 34, + + /* + * ACCELEROMETER_UNCALIBRATED + * reporting-mode: continuous + * + * All values are in SI units (m/s^2) and measure the acceleration of the + * device minus the acceleration due to gravity. + * + * Implement the non-wake-up version of this sensor and implement the + * wake-up version if the system possesses a wake up fifo. + */ + ACCELEROMETER_UNCALIBRATED = 35, + + /* + * Base for device manufacturers private sensor types. + * These sensor types can't be exposed in the SDK. + */ + DEVICE_PRIVATE_BASE = 0x10000 +}; + +@export(name="", value_prefix="SENSOR_FLAG_") +enum SensorFlagBits : uint32_t { + /* + * Whether this sensor wakes up the AP from suspend mode when data is + * available. Whenever sensor events are delivered from a wake_up sensor, + * the driver needs to hold a wake_lock till the events are read by the + * SensorService i.e till ISensors::poll() is called the next time. + * Once poll is called again it means events have been read by the + * SensorService, the driver can safely release the wake_lock. SensorService + * will continue to hold a wake_lock till the app actually reads the events. + */ + WAKE_UP = 1, + + /* + * Reporting modes for various sensors. Each sensor will have exactly one of + * these modes set. + * The least significant 2nd, 3rd and 4th bits are used to represent four + * possible reporting modes. + */ + CONTINUOUS_MODE = 0, + ON_CHANGE_MODE = 2, + ONE_SHOT_MODE = 4, + SPECIAL_REPORTING_MODE = 6, + + /* + * Set this flag if the sensor supports data_injection mode and allows data + * to be injected from the SensorService. When in data_injection ONLY + * sensors with this flag set are injected sensor data and only sensors with + * this flag set are activated. Eg: Accelerometer and Step Counter sensors + * can be set with this flag and SensorService will inject accelerometer + * data and read the corresponding step counts. + */ + DATA_INJECTION = 0x10, + + /* + * Set this flag if the sensor is a dynamically connected sensor. See + * DynamicSensorInfo and DYNAMIC_SENSOR_META for details. + */ + DYNAMIC_SENSOR = 0x20, + + /* + * Set this flag if sensor additional information is supported. + * See ADDITIONAL_INFO and AdditionalInfo for details. + */ + ADDITIONAL_INFO = 0x40, + + /* + * Set this flag if sensor suppor direct channel backed by ashmem. + * See SharedMemType and registerDirectChannel for more details. + */ + DIRECT_CHANNEL_ASHMEM = 0x400, + + /* + * Set this flag if sensor suppor direct channel backed by gralloc HAL memory. + * See SharedMemType and registerDirectChannel for more details. + */ + DIRECT_CHANNEL_GRALLOC = 0x800, + + /* + * Flags mask for reporting mode of sensor. + */ + MASK_REPORTING_MODE = 0xE, + + /* + * Flags mask for direct report maximum rate level support. + * See RateLevel. + */ + MASK_DIRECT_REPORT = 0x380, + + /* + * Flags mask for all direct channel support bits. + * See SharedMemType. + */ + MASK_DIRECT_CHANNEL = 0xC00, +}; + +@export(name="sensor_flag_shift_t", value_prefix="SENSOR_FLAG_SHIFT_") +enum SensorFlagShift : uint8_t { + REPORTING_MODE = 1, + DATA_INJECTION = 4, + DYNAMIC_SENSOR = 5, + ADDITIONAL_INFO = 6, + DIRECT_REPORT = 7, + DIRECT_CHANNEL = 10, +}; + +struct SensorInfo { + /* handle that identifies this sensors. This handle is used to reference + * this sensor throughout the HAL API. + */ + int32_t sensorHandle; + + /* Name of this sensor. + * All sensors of the same "type" must have a different "name". + */ + string name; + + /* vendor of the hardware part */ + string vendor; + + /* version of the hardware part + driver. The value of this field + * must increase when the driver is updated in a way that changes the + * output of this sensor. This is important for fused sensors when the + * fusion algorithm is updated. + */ + int32_t version; + + /* this sensor's type. */ + SensorType type; + + /* type of this sensor as a string. + * + * When defining an OEM specific sensor or sensor manufacturer specific + * sensor, use your reserve domain name as a prefix. + * e.g. com.google.glass.onheaddetector + * + * For sensors of known type defined in SensorType (value < + * SensorType::DEVICE_PRIVATE_BASE), this can be an empty string. + */ + string typeAsString; + + /* maximum range of this sensor's value in SI units */ + float maxRange; + + /* smallest difference between two values reported by this sensor */ + float resolution; + + /* rough estimate of this sensor's power consumption in mA */ + float power; + + /* this value depends on the reporting mode: + * + * continuous: minimum sample period allowed in microseconds + * on-change : 0 + * one-shot :-1 + * special : 0, unless otherwise noted + */ + int32_t minDelay; + + /* number of events reserved for this sensor in the batch mode FIFO. + * If there is a dedicated FIFO for this sensor, then this is the + * size of this FIFO. If the FIFO is shared with other sensors, + * this is the size reserved for that sensor and it can be zero. + */ + uint32_t fifoReservedEventCount; + + /* maximum number of events of this sensor that could be batched. + * This is especially relevant when the FIFO is shared between + * several sensors; this value is then set to the size of that FIFO. + */ + uint32_t fifoMaxEventCount; + + /* permission required to see this sensor, register to it and receive data. + * Set to "" if no permission is required. Some sensor types like the + * heart rate monitor have a mandatory require_permission. + * For sensors that always require a specific permission, like the heart + * rate monitor, the android framework might overwrite this string + * automatically. + */ + string requiredPermission; + + /* This value is defined only for continuous mode and on-change sensors. + * It is the delay between two sensor events corresponding to the lowest + * frequency that this sensor supports. When lower frequencies are requested + * through batch()/setDelay() the events will be generated at this frequency + * instead. + * It can be used by the framework or applications to estimate when the + * batch FIFO may be full. + * + * NOTE: periodNs is in nanoseconds where as maxDelay/minDelay are in + * microseconds. + * + * continuous, on-change: maximum sampling period allowed in + * microseconds. + * + * one-shot, special : 0 + */ + int32_t maxDelay; + + /* Bitmask of SensorFlagBits */ + bitfield<SensorFlagBits> flags; +}; + +@export(name="", value_prefix="SENSOR_STATUS_") +enum SensorStatus : int8_t { + NO_CONTACT = -1, + UNRELIABLE = 0, + ACCURACY_LOW = 1, + ACCURACY_MEDIUM = 2, + ACCURACY_HIGH = 3, +}; + +struct Vec3 { + float x; + float y; + float z; + SensorStatus status; +}; + +struct Vec4 { + float x; + float y; + float z; + float w; +}; + +struct Uncal { + float x; + float y; + float z; + float x_bias; + float y_bias; + float z_bias; +}; + +struct HeartRate { + /* Heart rate in beats per minute. + * Set to 0 when status is SensorStatus::UNRELIABLE or + * SensorStatus::NO_CONTACT + */ + float bpm; + + /* Status of the heart rate sensor for this reading. */ + SensorStatus status; +}; + +@export(name="") +enum MetaDataEventType : uint32_t { + META_DATA_FLUSH_COMPLETE = 1, +}; + +struct MetaData { + MetaDataEventType what; +}; + +struct DynamicSensorInfo { + bool connected; + int32_t sensorHandle; + + /* UUID of a dynamic sensor (using RFC 4122 byte order) + * For UUID 12345678-90AB-CDEF-1122-334455667788 the uuid field is + * initialized as: + * {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x11, ...} + */ + uint8_t[16] uuid; +}; + +@export(name="additional_info_type_t") +enum AdditionalInfoType : uint32_t { + /* Marks the beginning of additional information frames */ + AINFO_BEGIN = 0, + + /* Marks the end of additional information frames */ + AINFO_END = 1, + + /* Estimation of the delay that is not tracked by sensor timestamps. This + * includes delay introduced by sensor front-end filtering, data transport, + * etc. + * float[2]: delay in seconds, standard deviation of estimated value + */ + AINFO_UNTRACKED_DELAY = 0x10000, + + /* float: Celsius temperature */ + AINFO_INTERNAL_TEMPERATURE, + + /* First three rows of a homogeneous matrix, which represents calibration to + * a three-element vector raw sensor reading. + * float[12]: 3x4 matrix in row major order + */ + AINFO_VEC3_CALIBRATION, + + /* Location and orientation of sensor element in the device frame: origin is + * the geometric center of the mobile device screen surface; the axis + * definition corresponds to Android sensor definitions. + * float[12]: 3x4 matrix in row major order + */ + AINFO_SENSOR_PLACEMENT, + + /* float[2]: raw sample period in seconds, + * standard deviation of sampling period + */ + AINFO_SAMPLING, + + // Sampling channel modeling information section + + /* int32_t: noise type + * float[n]: parameters + */ + AINFO_CHANNEL_NOISE = 0x20000, + + /* float[3]: sample period, standard deviation of sample period, + * quantization unit + */ + AINFO_CHANNEL_SAMPLER, + + /* Represents a filter: + * \sum_j a_j y[n-j] == \sum_i b_i x[n-i] + * + * int32_t[3]: number of feedforward coeffients M, + * number of feedback coefficients N (for FIR filter, N = 1). + * bit mask that represents which element the filter is applied + * to. (bit 0==1 means this filter applies to vector element 0). + * float[M+N]: filter coefficients (b0, b1, ..., b_{M-1}), then + * (a0, a1, ..., a_{N-1}), a0 is always 1. + * + * Multiple frames may be needed for higher number of taps. + */ + AINFO_CHANNEL_FILTER, + + /* int32_t[2]: size in (row, column) ... 1st frame + * float[n]: matrix element values in row major order. + */ + AINFO_CHANNEL_LINEAR_TRANSFORM, + + /* int32_t[2]: extrapolate method, interpolate method + * float[n]: mapping key points in pairs, (in, out)... + * (may be used to model saturation). + */ + AINFO_CHANNEL_NONLINEAR_MAP, + + /* int32_t: resample method (0-th order, 1st order...) + * float[1]: resample ratio (upsampling if < 1.0, downsampling if > 1.0). + */ + AINFO_CHANNEL_RESAMPLER, + + /* Operation environment parameters section + * Types in the following section is sent down (instead of reported from) + * device as additional information to aid sensor operation. Data is sent + * via injectSensorData() function to sensor handle -1 denoting all sensors + * in device. + */ + + /* Local geomagnetic field information based on device geo location. This + * type is primarily for for magnetic field calibration and rotation vector + * sensor fusion. + * float[3]: strength (uT), declination and inclination angle (rad). + */ + AINFO_LOCAL_GEOMAGNETIC_FIELD = 0x30000, + + /* Local gravitational acceleration strength at device geo location. + * float: gravitational acceleration norm in m/s^2. + */ + AINFO_LOCAL_GRAVITY, + + /* Device dock state. + * int32_t: dock state following Android API Intent.EXTRA_DOCK_STATE + * definition, undefined value is ignored. + */ + AINFO_DOCK_STATE, + + /* High performance mode hint. Device is able to use up more power and take + * more reources to improve throughput and latency in high performance mode. + * One possible use case is virtual reality, when sensor latency need to be + * carefully controlled. + * int32_t: 1 or 0, denote if device is in/out of high performance mode, + * other values is ignored. + */ + AINFO_HIGH_PERFORMANCE_MODE, + + /* Magnetic field calibration hint. Device is notified when manually + * triggered magnetic field calibration procedure is started or stopped. The + * calibration procedure is assumed timed out after 1 minute from start, + * even if an explicit stop is not received. + * + * int32_t: 1 for start, 0 for stop, other value is ignored. + */ + AINFO_MAGNETIC_FIELD_CALIBRATION, + + /* Custom information */ + AINFO_CUSTOM_START = 0x10000000, + + /* Debugging */ + AINFO_DEBUGGING_START = 0x40000000, +}; + +struct AdditionalInfo { + /* type of payload data, see AdditionalInfoType */ + AdditionalInfoType type; + + /* sequence number of this frame for this type */ + int32_t serial; + + union Payload { + int32_t[14] data_int32; + float[14] data_float; + } u; +}; + +/* acceleration values are in meter per second per second (m/s^2) + * magnetic vector values are in micro-Tesla (uT) + * orientation values are in degrees + * gyroscope values are in rad/s + * temperature is in degrees centigrade (Celsius) + * distance in centimeters + * light in SI lux units + * pressure in hectopascal (hPa) + * relative humidity in percent + */ +union EventPayload { + /* SensorType::ACCELEROMETER, SensorType::MAGNETIC_FIELD, + * SensorType::ORIENTATION, SensorType::GYROSCOPE, SensorType::GRAVITY, + * SensorType::LINEAR_ACCELERATION + */ + Vec3 vec3; + + /* SensorType::ROTATION_VECTOR, SensorType::GAME_ROTATION_VECTOR, + * SensorType::GEOMAGNETIC_ROTATION_VECTOR + */ + Vec4 vec4; + + /* SensorType::MAGNETIC_FIELD_UNCALIBRATED, + * SensorType::GYROSCOPE_UNCALIBRATED + * SensorType::ACCELEROMETER_UNCALIBRATED + */ + Uncal uncal; + + /* SensorType::META_DATA */ + MetaData meta; + + /* SensorType::DEVICE_ORIENTATION, SensorType::LIGHT, SensorType::PRESSURE, + * SensorType::TEMPERATURE, SensorType::PROXIMITY, + * SensorType::RELATIVE_HUMIDITY, SensorType::AMBIENT_TEMPERATURE, + * SensorType::SIGNIFICANT_MOTION, SensorType::STEP_DETECTOR, + * SensorType::TILT_DETECTOR, SensorType::WAKE_GESTURE, + * SensorType::GLANCE_GESTURE, SensorType::PICK_UP_GESTURE, + * SensorType::WRIST_TILT_GESTURE, SensorType::STATIONARY_DETECT, + * SensorType::MOTION_DETECT, SensorType::HEART_BEAT + */ + float scalar; + + /* SensorType::STEP_COUNTER */ + uint64_t stepCount; + + /* SensorType::HEART_RATE */ + HeartRate heartRate; + + /* SensorType::POSE_6DOF */ + float[15] pose6DOF; + + /* SensorType::DYNAMIC_SENSOR_META */ + DynamicSensorInfo dynamic; + + /* SensorType::ADDITIONAL_INFO */ + AdditionalInfo additional; + + /* undefined/custom sensor type >= SensorType::DEVICE_PRIVATE_BASE */ + float[16] data; +}; + +struct Event { + /* Time measured in nanoseconds, in "elapsedRealtimeNano()'s" timebase. */ + int64_t timestamp; + + /* sensor identifier */ + int32_t sensorHandle; + + SensorType sensorType; + + /* Union discriminated on sensorType */ + EventPayload u; +}; + +/** + * Direct report rate level definition. Except for SENSOR_DIRECT_RATE_STOP, each + * rate level covers the range (55%, 220%] * nominal report rate. For example, + * if config direct report specify a rate level SENSOR_DIRECT_RATE_FAST, it is + * legal for sensor hardware to report event at a rate greater than 110Hz, and + * less or equal to 440Hz. Note that rate has to remain steady without variation + * before new rate level is configured, i.e. if a sensor is configured to + * SENSOR_DIRECT_RATE_FAST and starts to report event at 256Hz, it cannot + * change rate to 128Hz after a few seconds of running even if 128Hz is also in + * the legal range of SENSOR_DIRECT_RATE_FAST. Thus, it is recommended to + * associate report rate with RateLvel statically for single sensor. + */ +@export(name="direct_rate_level_t", value_prefix="SENSOR_DIRECT_RATE_") +enum RateLevel : int32_t { + STOP, // stop + NORMAL, // nominal 50Hz + FAST, // nominal 200Hz + VERY_FAST, // nominal 800Hz +}; + +/** + * Direct channel shared memory types. See struct SharedMemInfo. + */ +@export(name="direct_mem_type_t", value_prefix="SENSOR_DIRECT_MEM_TYPE_") +enum SharedMemType : int32_t { + // handle contains 1 fd (ashmem handle) and 0 int. + ASHMEM = 1, + // handle definition matches gralloc HAL. + GRALLOC +}; + + +/** + * Direct channel lock-free queue format, this defines how the shared memory is + * interpreted by both sensor hardware and application. + * + * @see SharedMemInfo. + */ +@export(name="direct_format_t", value_prefix="SENSOR_DIRECT_FMT_") +enum SharedMemFormat : int32_t { + SENSORS_EVENT = 1, // shared memory is formated as an array of data + // elements. See SensorsEventFormatOffset for details. + // Upon return of channel registration call, the + // shared memory space must be formated to all 0 by HAL. +}; + +enum SensorsEventFormatOffset : uint16_t { + // offset type name + //----------------------------------- + // 0x0000 int32_t size (always 104) + // 0x0004 int32_t sensor report token + // 0x0008 int32_t type (see SensorType) + // 0x000C uint32_t atomic counter + // 0x0010 int64_t timestamp (see Event) + // 0x0018 float[16]/ data + // int64_t[8] + // 0x0058 int32_t[4] reserved (set to zero) + SIZE_FIELD = 0x0, + REPORT_TOKEN = 0x4, + SENSOR_TYPE = 0x8, + ATOMIC_COUNTER = 0xC, + TIMESTAMP = 0x10, + DATA = 0x18, + RESERVED = 0x58, + TOTAL_LENGTH = 0x68 +}; + +/** + * Shared memory information for a direct channel + */ +struct SharedMemInfo { + SharedMemType type; // shared memory type + SharedMemFormat format; + uint32_t size; // size of the memory region, in bytes + handle memoryHandle; // shared memory handle, it is interpreted + // depending on type field, see SharedMemType. +};
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..af149ba --- /dev/null +++ b/sensors/1.0/vts/functional/Android.bp
@@ -0,0 +1,34 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalSensorsV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalSensorsV1_0TargetTest.cpp"], + shared_libs: [ + "android.hardware.sensors@1.0", + "libcutils", + "libhidlbase", + "liblog", + "libutils", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +} +
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp new file mode 100644 index 0000000..1298e16 --- /dev/null +++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -0,0 +1,1006 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "sensors_hidl_hal_test" +#include <android-base/logging.h> +#include <android/hardware/sensors/1.0/ISensors.h> +#include <android/hardware/sensors/1.0/types.h> +#include <android/log.h> +#include <cutils/ashmem.h> +#include <VtsHalHidlTargetTestBase.h> +#include <hardware/sensors.h> // for sensor type strings + +#include <algorithm> +#include <cinttypes> +#include <cmath> +#include <memory> +#include <mutex> +#include <thread> +#include <unordered_set> +#include <vector> + +#include <sys/mman.h> +#include <unistd.h> + +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_string; +using ::android::sp; +using namespace ::android::hardware::sensors::V1_0; + +// Test environment for sensors +class SensorsHidlEnvironment : public ::testing::Environment { + public: + // get the test environment singleton + static SensorsHidlEnvironment* Instance() { + static SensorsHidlEnvironment* instance = new SensorsHidlEnvironment; + return instance; + } + + // sensors hidl service + sp<ISensors> sensors; + + virtual void SetUp(); + virtual void TearDown(); + + // Get and clear all events collected so far (like "cat" shell command). + // If output is nullptr, it clears all collected events. + void catEvents(std::vector<Event>* output); + + // set sensor event collection status + void setCollection(bool enable); + + private: + SensorsHidlEnvironment() {} + + void addEvent(const Event& ev); + void startPollingThread(); + static void pollingThread(SensorsHidlEnvironment* env, std::shared_ptr<bool> stop); + + bool collectionEnabled; + std::shared_ptr<bool> stopThread; + std::thread pollThread; + std::vector<Event> events; + std::mutex events_mutex; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironment); +}; + +void SensorsHidlEnvironment::SetUp() { + sensors = ::testing::VtsHalHidlTargetTestBase::getService<ISensors>(); + ALOGI_IF(sensors, "sensors is not nullptr, %p", sensors.get()); + ASSERT_NE(sensors, nullptr); + + collectionEnabled = false; + startPollingThread(); + + // In case framework just stopped for test and there is sensor events in the pipe, + // wait some time for those events to be cleared to avoid them messing up the test. + std::this_thread::sleep_for(std::chrono::seconds(3)); +} + +void SensorsHidlEnvironment::TearDown() { + ALOGI("TearDown SensorsHidlEnvironement"); + + if (stopThread) { + *stopThread = true; + } + pollThread.detach(); +} + +void SensorsHidlEnvironment::catEvents(std::vector<Event>* output) { + std::lock_guard<std::mutex> lock(events_mutex); + if (output) { + output->insert(output->end(), events.begin(), events.end()); + } + events.clear(); +} + +void SensorsHidlEnvironment::setCollection(bool enable) { + std::lock_guard<std::mutex> lock(events_mutex); + collectionEnabled = enable; +} + +void SensorsHidlEnvironment::addEvent(const Event& ev) { + std::lock_guard<std::mutex> lock(events_mutex); + if (collectionEnabled) { + events.push_back(ev); + } +} + +void SensorsHidlEnvironment::startPollingThread() { + stopThread = std::shared_ptr<bool>(new bool(false)); + pollThread = std::thread(pollingThread, this, stopThread); + events.reserve(128); +} + +void SensorsHidlEnvironment::pollingThread( + SensorsHidlEnvironment* env, std::shared_ptr<bool> stop) { + ALOGD("polling thread start"); + bool needExit = *stop; + + while(!needExit) { + env->sensors->poll(1, + [&](auto result, const auto &events, const auto &dynamicSensorsAdded) { + if (result != Result::OK + || (events.size() == 0 && dynamicSensorsAdded.size() == 0) + || *stop) { + needExit = true; + return; + } + + if (events.size() > 0) { + env->addEvent(events[0]); + } + }); + } + ALOGD("polling thread end"); +} + +class SensorsTestSharedMemory { + public: + static SensorsTestSharedMemory* create(SharedMemType type, size_t size); + SharedMemInfo getSharedMemInfo() const; + char * getBuffer() const; + std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const; + virtual ~SensorsTestSharedMemory(); + private: + SensorsTestSharedMemory(SharedMemType type, size_t size); + + SharedMemType mType; + native_handle_t* mNativeHandle; + size_t mSize; + char* mBuffer; + + DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory); +}; + +SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const { + SharedMemInfo mem = { + .type = mType, + .format = SharedMemFormat::SENSORS_EVENT, + .size = static_cast<uint32_t>(mSize), + .memoryHandle = mNativeHandle + }; + return mem; +} + +char * SensorsTestSharedMemory::getBuffer() const { + return mBuffer; +} + +std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const { + + constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH); + constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD); + constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN); + constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE); + constexpr size_t kOffsetAtomicCounter = + static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER); + constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP); + constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA); + + std::vector<Event> events; + std::vector<float> data(16); + + while (offset + kEventSize <= mSize) { + int64_t atomicCounter = *reinterpret_cast<uint32_t *>(mBuffer + offset + kOffsetAtomicCounter); + if (atomicCounter <= lastCounter) { + break; + } + + int32_t size = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetSize); + if (size != kEventSize) { + // unknown error, events parsed may be wrong, remove all + events.clear(); + break; + } + + int32_t token = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetToken); + int32_t type = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetType); + int64_t timestamp = *reinterpret_cast<int64_t *>(mBuffer + offset + kOffsetTimestamp); + + ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32 ", timestamp %" PRId64, + offset, atomicCounter, token, type, timestamp); + + Event event = { + .timestamp = timestamp, + .sensorHandle = token, + .sensorType = static_cast<SensorType>(type), + }; + event.u.data = android::hardware::hidl_array<float, 16> + (reinterpret_cast<float*>(mBuffer + offset + kOffsetData)); + + events.push_back(event); + + lastCounter = atomicCounter; + offset += kEventSize; + } + + return events; +} + +SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size) + : mType(type), mSize(0), mBuffer(nullptr) { + native_handle_t *handle = nullptr; + char *buffer = nullptr; + switch(type) { + case SharedMemType::ASHMEM: { + int fd; + handle = ::native_handle_create(1 /*nFds*/, 0/*nInts*/); + if (handle != nullptr) { + handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size); + if (handle->data[0] > 0) { + // memory is pinned by default + buffer = static_cast<char *> + (::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + if (buffer != reinterpret_cast<char*>(MAP_FAILED)) { + break; + } + ::native_handle_close(handle); + } + ::native_handle_delete(handle); + handle = nullptr; + } + break; + } + default: + break; + } + + if (buffer != nullptr) { + mNativeHandle = handle; + mSize = size; + mBuffer = buffer; + } +} + +SensorsTestSharedMemory::~SensorsTestSharedMemory() { + switch(mType) { + case SharedMemType::ASHMEM: { + if (mSize != 0) { + ::munmap(mBuffer, mSize); + mBuffer = nullptr; + + ::native_handle_close(mNativeHandle); + ::native_handle_delete(mNativeHandle); + + mNativeHandle = nullptr; + mSize = 0; + } + break; + } + default: { + if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) { + ALOGE("SensorsTestSharedMemory %p not properly destructed: " + "type %d, native handle %p, size %zu, buffer %p", + this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer); + } + break; + } + } +} + +SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) { + constexpr size_t kMaxSize = 128*1024*1024; // sensor test should not need more than 128M + if (size == 0 || size >= kMaxSize) { + return nullptr; + } + + auto m = new SensorsTestSharedMemory(type, size); + if (m->mSize != size || m->mBuffer == nullptr) { + delete m; + m = nullptr; + } + return m; +} + +// The main test class for SENSORS HIDL HAL. +class SensorsHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + } + + virtual void TearDown() override { + // stop all sensors + for (auto s : mSensorHandles) { + S()->activate(s, false); + } + mSensorHandles.clear(); + + // stop all direct report and channels + for (auto c : mDirectChannelHandles) { + // disable all reports + S()->configDirectReport(-1, c, RateLevel::STOP, [] (auto, auto){}); + S()->unregisterDirectChannel(c); + } + mDirectChannelHandles.clear(); + } + + protected: + SensorInfo defaultSensorByType(SensorType type); + std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit, + bool clearBeforeStart = true, bool changeCollection = true); + + // implementation wrapper + Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) { + return S()->getSensorsList(_hidl_cb); + } + + Return<Result> activate( + int32_t sensorHandle, bool enabled); + + Return<Result> batch( + int32_t sensorHandle, + int64_t samplingPeriodNs, + int64_t maxReportLatencyNs) { + return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs); + } + + Return<Result> flush(int32_t sensorHandle) { + return S()->flush(sensorHandle); + } + + Return<Result> injectSensorData(const Event& event) { + return S()->injectSensorData(event); + } + + Return<void> registerDirectChannel( + const SharedMemInfo& mem, ISensors::registerDirectChannel_cb _hidl_cb); + + Return<Result> unregisterDirectChannel(int32_t channelHandle) { + return S()->unregisterDirectChannel(channelHandle); + } + + Return<void> configDirectReport( + int32_t sensorHandle, int32_t channelHandle, RateLevel rate, + ISensors::configDirectReport_cb _hidl_cb) { + return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb); + } + + inline sp<ISensors>& S() { + return SensorsHidlEnvironment::Instance()->sensors; + } + + inline static SensorFlagBits extractReportMode(uint64_t flag) { + return (SensorFlagBits) (flag + & ((uint64_t) SensorFlagBits::CONTINUOUS_MODE + | (uint64_t) SensorFlagBits::ON_CHANGE_MODE + | (uint64_t) SensorFlagBits::ONE_SHOT_MODE + | (uint64_t) SensorFlagBits::SPECIAL_REPORTING_MODE)); + } + + inline static bool isMetaSensorType(SensorType type) { + return (type == SensorType::META_DATA + || type == SensorType::DYNAMIC_SENSOR_META + || type == SensorType::ADDITIONAL_INFO); + } + + inline static bool isValidType(SensorType type) { + return (int32_t) type > 0; + } + + static bool typeMatchStringType(SensorType type, const hidl_string& stringType); + static bool typeMatchReportMode(SensorType type, SensorFlagBits reportMode); + static bool delayMatchReportMode(int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode); + static SensorFlagBits expectedReportModeForType(SensorType type); + + // all sensors and direct channnels used + std::unordered_set<int32_t> mSensorHandles; + std::unordered_set<int32_t> mDirectChannelHandles; +}; + + +Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) { + // If activating a sensor, add the handle in a set so that when test fails it can be turned off. + // The handle is not removed when it is deactivating on purpose so that it is not necessary to + // check the return value of deactivation. Deactivating a sensor more than once does not have + // negative effect. + if (enabled) { + mSensorHandles.insert(sensorHandle); + } + return S()->activate(sensorHandle, enabled); +} + +Return<void> SensorsHidlTest::registerDirectChannel( + const SharedMemInfo& mem, ISensors::registerDirectChannel_cb cb) { + // If registeration of a channel succeeds, add the handle of channel to a set so that it can be + // unregistered when test fails. Unregister a channel does not remove the handle on purpose. + // Unregistering a channel more than once should not have negative effect. + S()->registerDirectChannel(mem, + [&] (auto result, auto channelHandle) { + if (result == Result::OK) { + mDirectChannelHandles.insert(channelHandle); + } + cb(result, channelHandle); + }); + return Void(); +} + +std::vector<Event> SensorsHidlTest::collectEvents(useconds_t timeLimitUs, size_t nEventLimit, + bool clearBeforeStart, bool changeCollection) { + std::vector<Event> events; + constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //gradularity 100 ms + + ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", + nEventLimit, timeLimitUs, clearBeforeStart); + + if (changeCollection) { + SensorsHidlEnvironment::Instance()->setCollection(true); + } + if (clearBeforeStart) { + SensorsHidlEnvironment::Instance()->catEvents(nullptr); + } + + while (timeLimitUs > 0) { + useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs); + usleep(duration); + timeLimitUs -= duration; + + SensorsHidlEnvironment::Instance()->catEvents(&events); + if (events.size() >= nEventLimit) { + break; + } + ALOGV("time to go = %d, events to go = %d", + (int)timeLimitUs, (int)(nEventLimit - events.size())); + } + + if (changeCollection) { + SensorsHidlEnvironment::Instance()->setCollection(false); + } + return events; +} + +bool SensorsHidlTest::typeMatchStringType(SensorType type, const hidl_string& stringType) { + + if (type >= SensorType::DEVICE_PRIVATE_BASE) { + return true; + } + + bool res = true; + switch (type) { +#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \ + case SensorType::type: res = stringType == SENSOR_STRING_TYPE_ ## type;\ + break;\ + + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO); + CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT); + default: + ALOGW("Type %d is not checked, stringType = %s", (int)type, stringType.c_str()); +#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE + } + return res; +} + +bool SensorsHidlTest::typeMatchReportMode(SensorType type, SensorFlagBits reportMode) { + if (type >= SensorType::DEVICE_PRIVATE_BASE) { + return true; + } + + SensorFlagBits expected = expectedReportModeForType(type); + + return expected == (SensorFlagBits)-1 || expected == reportMode; +} + +bool SensorsHidlTest::delayMatchReportMode( + int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode) { + bool res = true; + switch(reportMode) { + case SensorFlagBits::CONTINUOUS_MODE: + res = (minDelay > 0) && (maxDelay >= 0); + break; + case SensorFlagBits::ON_CHANGE_MODE: + //TODO: current implementation does not satisfy minDelay == 0 on Proximity + res = (minDelay >= 0) && (maxDelay >= 0); + //res = (minDelay == 0) && (maxDelay >= 0); + break; + case SensorFlagBits::ONE_SHOT_MODE: + res = (minDelay == -1) && (maxDelay == 0); + break; + case SensorFlagBits::SPECIAL_REPORTING_MODE: + res = (minDelay == 0) && (maxDelay == 0); + break; + default: + res = false; + } + + return res; +} + +SensorFlagBits SensorsHidlTest::expectedReportModeForType(SensorType type) { + switch (type) { + case SensorType::ACCELEROMETER: + case SensorType::GYROSCOPE: + case SensorType::MAGNETIC_FIELD: + case SensorType::ORIENTATION: + case SensorType::PRESSURE: + case SensorType::TEMPERATURE: + case SensorType::GRAVITY: + case SensorType::LINEAR_ACCELERATION: + case SensorType::ROTATION_VECTOR: + case SensorType::MAGNETIC_FIELD_UNCALIBRATED: + case SensorType::GAME_ROTATION_VECTOR: + case SensorType::GYROSCOPE_UNCALIBRATED: + case SensorType::GEOMAGNETIC_ROTATION_VECTOR: + case SensorType::POSE_6DOF: + case SensorType::HEART_BEAT: + return SensorFlagBits::CONTINUOUS_MODE; + + case SensorType::LIGHT: + case SensorType::PROXIMITY: + case SensorType::RELATIVE_HUMIDITY: + case SensorType::AMBIENT_TEMPERATURE: + case SensorType::HEART_RATE: + case SensorType::DEVICE_ORIENTATION: + case SensorType::MOTION_DETECT: + case SensorType::STEP_COUNTER: + return SensorFlagBits::ON_CHANGE_MODE; + + case SensorType::SIGNIFICANT_MOTION: + case SensorType::WAKE_GESTURE: + case SensorType::GLANCE_GESTURE: + case SensorType::PICK_UP_GESTURE: + return SensorFlagBits::ONE_SHOT_MODE; + + case SensorType::STEP_DETECTOR: + case SensorType::TILT_DETECTOR: + case SensorType::WRIST_TILT_GESTURE: + case SensorType::DYNAMIC_SENSOR_META: + return SensorFlagBits::SPECIAL_REPORTING_MODE; + + default: + ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type); + return (SensorFlagBits)-1; + } +} + +SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) { + SensorInfo ret; + + ret.type = (SensorType) -1; + S()->getSensorsList( + [&] (const auto &list) { + const size_t count = list.size(); + for (size_t i = 0; i < count; ++i) { + if (list[i].type == type) { + ret = list[i]; + return; + } + } + }); + + return ret; +} + +// Test if sensor list returned is valid +TEST_F(SensorsHidlTest, SensorListValid) { + S()->getSensorsList( + [&] (const auto &list) { + const size_t count = list.size(); + for (size_t i = 0; i < count; ++i) { + auto &s = list[i]; + ALOGV("\t%zu: handle=%#08x type=%d name=%s", + i, s.sensorHandle, (int)s.type, s.name.c_str()); + + // Test non-empty type string + ASSERT_FALSE(s.typeAsString.empty()); + + // Test defined type matches defined string type + ASSERT_TRUE(typeMatchStringType(s.type, s.typeAsString)); + + // Test if all sensor has name and vendor + ASSERT_FALSE(s.name.empty()); + ASSERT_FALSE(s.vendor.empty()); + + // Test power > 0, maxRange > 0 + ASSERT_GE(s.power, 0); + ASSERT_GT(s.maxRange, 0); + + // Info type, should have no sensor + ASSERT_FALSE( + s.type == SensorType::ADDITIONAL_INFO + || s.type == SensorType::META_DATA); + + // Test fifoMax >= fifoReserved + ALOGV("max reserve = %d, %d", s.fifoMaxEventCount, s.fifoReservedEventCount); + ASSERT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount); + + // Test Reporting mode valid + ASSERT_TRUE(typeMatchReportMode(s.type, extractReportMode(s.flags))); + + // Test min max are in the right order + ASSERT_LE(s.minDelay, s.maxDelay); + // Test min/max delay matches reporting mode + ASSERT_TRUE(delayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags))); + } + }); +} + +// Test if sensor hal can do normal accelerometer streaming properly +TEST_F(SensorsHidlTest, NormalAccelerometerStreamingOperation) { + + std::vector<Event> events; + + constexpr int64_t samplingPeriodInNs = 20ull*1000*1000; // 20ms + constexpr int64_t batchingPeriodInNs = 0; // no batching + constexpr useconds_t minTimeUs = 5*1000*1000; // 5 s + constexpr size_t minNEvent = 100; // at lease 100 events + constexpr SensorType type = SensorType::ACCELEROMETER; + + SensorInfo sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + int32_t handle = sensor.sensorHandle; + + ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/); + ASSERT_EQ(activate(handle, 0), Result::OK); + + ALOGI("Collected %zu samples", events.size()); + + ASSERT_GT(events.size(), 0u); + + size_t nRealEvent = 0; + for (auto & e : events) { + if (e.sensorType == type) { + + ASSERT_EQ(e.sensorHandle, handle); + + Vec3 acc = e.u.vec3; + + double gravityNorm = std::sqrt(acc.x * acc.x + acc.y * acc.y + acc.z * acc.z); + ALOGV("Norm = %f", gravityNorm); + + // assert this is earth gravity + ASSERT_TRUE(std::fabs(gravityNorm - GRAVITY_EARTH) < 1); + + ++ nRealEvent; + } else { + ALOGI("Event type %d, handle %d", (int) e.sensorType, (int) e.sensorHandle); + // Only meta types are allowed besides the subscribed sensor + ASSERT_TRUE(isMetaSensorType(e.sensorType)); + } + } + + ASSERT_GE(nRealEvent, minNEvent / 2); // make sure returned events are not all meta +} + +// Test if sensor hal can do gyroscope streaming properly +TEST_F(SensorsHidlTest, NormalGyroscopeStreamingOperation) { + std::vector<Event> events; + + constexpr int64_t samplingPeriodInNs = 10ull*1000*1000; // 10ms + constexpr int64_t batchingPeriodInNs = 0; // no batching + constexpr useconds_t minTimeUs = 5*1000*1000; // 5 s + constexpr size_t minNEvent = 200; + constexpr SensorType type = SensorType::GYROSCOPE; + + SensorInfo sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + int32_t handle = sensor.sensorHandle; + + ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/); + ASSERT_EQ(activate(handle, 0), Result::OK); + + ALOGI("Collected %zu samples", events.size()); + + ASSERT_GT(events.size(), 0u); + + size_t nRealEvent = 0; + for (auto & e : events) { + if (e.sensorType == type) { + + ASSERT_EQ(e.sensorHandle, handle); + + Vec3 gyro = e.u.vec3; + + double gyroNorm = std::sqrt(gyro.x * gyro.x + gyro.y * gyro.y + gyro.z * gyro.z); + ALOGV("Gyro Norm = %f", gyroNorm); + + // assert not drifting + ASSERT_TRUE(gyroNorm < 0.1); // < ~5 degree/s + + ++ nRealEvent; + } else { + ALOGI("Event type %d, handle %d", (int) e.sensorType, (int) e.sensorHandle); + // Only meta types are allowed besides the subscribed sensor + ASSERT_TRUE(isMetaSensorType(e.sensorType)); + } + } + + ASSERT_GE(nRealEvent, minNEvent / 2); // make sure returned events are not all meta +} + +// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active +TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) { + std::vector<Event> events1, events2; + + constexpr int64_t batchingPeriodInNs = 0; // no batching + constexpr size_t minNEvent = 50; + constexpr SensorType type = SensorType::ACCELEROMETER; + + SensorInfo sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + int32_t handle = sensor.sensorHandle; + int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; + int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll; + + if (minSamplingPeriodInNs == maxSamplingPeriodInNs) { + // only support single rate + return; + } + + ASSERT_EQ(batch(handle, minSamplingPeriodInNs, batchingPeriodInNs), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + + usleep(500000); // sleep 0.5 sec to wait for change rate to happen + events1 = collectEvents(sensor.minDelay * minNEvent, minNEvent, true /*clearBeforeStart*/); + + ASSERT_EQ(batch(handle, maxSamplingPeriodInNs, batchingPeriodInNs), Result::OK); + + usleep(500000); // sleep 0.5 sec to wait for change rate to happen + events2 = collectEvents(sensor.maxDelay * minNEvent, minNEvent, true /*clearBeforeStart*/); + + ASSERT_EQ(activate(handle, 0), Result::OK); + + ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size()); + + ASSERT_GT(events1.size(), 0u); + ASSERT_GT(events2.size(), 0u); + + int64_t minDelayAverageInterval, maxDelayAverageInterval; + + size_t nEvent = 0; + int64_t prevTimestamp = -1; + int64_t timestampInterval = 0; + for (auto & e : events1) { + if (e.sensorType == type) { + ASSERT_EQ(e.sensorHandle, handle); + if (prevTimestamp > 0) { + timestampInterval += e.timestamp - prevTimestamp; + } + prevTimestamp = e.timestamp; + ++ nEvent; + } + } + ASSERT_GT(nEvent, 2u); + minDelayAverageInterval = timestampInterval / (nEvent - 1); + + nEvent = 0; + prevTimestamp = -1; + timestampInterval = 0; + for (auto & e : events2) { + if (e.sensorType == type) { + ASSERT_EQ(e.sensorHandle, handle); + if (prevTimestamp > 0) { + timestampInterval += e.timestamp - prevTimestamp; + } + prevTimestamp = e.timestamp; + ++ nEvent; + } + } + ASSERT_GT(nEvent, 2u); + maxDelayAverageInterval = timestampInterval / (nEvent - 1); + + // change of rate is significant. + ASSERT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10); + + // fastest rate sampling time is close to spec + ALOGI("minDelayAverageInterval = %" PRId64, minDelayAverageInterval); + ASSERT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs), + minSamplingPeriodInNs / 10); +} + +// Test if sensor hal can do normal accelerometer batching properly +TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) { + std::vector<Event> events; + + constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000; + constexpr SensorType type = SensorType::ACCELEROMETER; + constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000; + + SensorInfo sensor = defaultSensorByType(type); + + if (!isValidType(sensor.type)) { + // no default sensor of this type + return; + } + + int32_t handle = sensor.sensorHandle; + int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll; + uint32_t minFifoCount = sensor.fifoReservedEventCount; + int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs; + + if (batchingPeriodInNs < oneSecondInNs) { + // batching size too small to test reliably + return; + } + + batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs); + + ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000)); + + int64_t allowedBatchDeliverTimeNs = + std::max(oneSecondInNs, batchingPeriodInNs / 10); + + ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK); + ASSERT_EQ(activate(handle, 1), Result::OK); + + usleep(500000); // sleep 0.5 sec to wait for initialization + ASSERT_EQ(flush(handle), Result::OK); + + // wait for 80% of the reserved batching period + // there should not be any significant amount of events + // since collection is not enabled all events will go down the drain + usleep(batchingPeriodInNs / 1000 * 8 / 10); + + SensorsHidlEnvironment::Instance()->setCollection(true); + // 0.8 + 0.3 times the batching period + // plus some time for the event to deliver + events = collectEvents( + batchingPeriodInNs / 1000 * 3 / 10, + minFifoCount, true /*clearBeforeStart*/, false /*change collection*/); + + ASSERT_EQ(flush(handle), Result::OK); + + events = collectEvents(allowedBatchDeliverTimeNs / 1000, + minFifoCount, true /*clearBeforeStart*/, false /*change collection*/); + + SensorsHidlEnvironment::Instance()->setCollection(false); + ASSERT_EQ(activate(handle, 0), Result::OK); + + size_t nEvent = 0; + for (auto & e : events) { + if (e.sensorType == type && e.sensorHandle == handle) { + ++ nEvent; + } + } + + // at least reach 90% of advertised capacity + ASSERT_GT(nEvent, (size_t)(batchingPeriodInNs / minSamplingPeriodInNs * 9 / 10)); +} + +// Test sensor event direct report with ashmem for gyro sensor +TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReport) { + + constexpr SensorType type = SensorType::GYROSCOPE; + constexpr size_t kEventSize = 104; + constexpr size_t kNEvent = 500; + constexpr size_t kMemSize = kEventSize * kNEvent; + + SensorInfo sensor = defaultSensorByType(type); + + if (!(sensor.flags | SensorFlagBits::MASK_DIRECT_REPORT) + || !(sensor.flags | SensorFlagBits::DIRECT_CHANNEL_ASHMEM)) { + // does not declare support + return; + } + + std::unique_ptr<SensorsTestSharedMemory> + mem(SensorsTestSharedMemory::create(SharedMemType::ASHMEM, kMemSize)); + ASSERT_NE(mem, nullptr); + + char* buffer = mem->getBuffer(); + // fill memory with data + for (size_t i = 0; i < kMemSize; ++i) { + buffer[i] = '\xcc'; + } + + int32_t channelHandle; + registerDirectChannel(mem->getSharedMemInfo(), + [&channelHandle] (auto result, auto channelHandle_) { + ASSERT_EQ(result, Result::OK); + channelHandle = channelHandle_; + }); + + // check memory is zeroed + for (size_t i = 0; i < kMemSize; ++i) { + ASSERT_EQ(buffer[i], '\0'); + } + + int32_t eventToken; + configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::NORMAL, + [&eventToken] (auto result, auto token) { + ASSERT_EQ(result, Result::OK); + eventToken = token; + }); + + usleep(1500000); // sleep 1 sec for data, plus 0.5 sec for initialization + auto events = mem->parseEvents(); + + // allowed to be 55% of nominal freq (50Hz) + ASSERT_GT(events.size(), 50u / 2u); + ASSERT_LT(events.size(), static_cast<size_t>(110*1.5)); + + int64_t lastTimestamp = 0; + for (auto &e : events) { + ASSERT_EQ(e.sensorType, type); + ASSERT_EQ(e.sensorHandle, eventToken); + ASSERT_GT(e.timestamp, lastTimestamp); + + Vec3 gyro = e.u.vec3; + double gyroNorm = std::sqrt(gyro.x * gyro.x + gyro.y * gyro.y + gyro.z * gyro.z); + // assert not drifting + ASSERT_TRUE(gyroNorm < 0.1); // < ~5 degree/sa + + lastTimestamp = e.timestamp; + } + + // stop sensor and unregister channel + configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP, + [&eventToken] (auto result, auto) { + ASSERT_EQ(result, Result::OK); + }); + ASSERT_EQ(unregisterDirectChannel(channelHandle), Result::OK); +} + +int main(int argc, char **argv) { + ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} +// vim: set ts=2 sw=2
diff --git a/sensors/Android.bp b/sensors/Android.bp new file mode 100644 index 0000000..ed19a37 --- /dev/null +++ b/sensors/Android.bp
@@ -0,0 +1,6 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/default", + "1.0/vts/functional", +]
diff --git a/soundtrigger/2.0/Android.bp b/soundtrigger/2.0/Android.bp new file mode 100644 index 0000000..4d2bb1a --- /dev/null +++ b/soundtrigger/2.0/Android.bp
@@ -0,0 +1,71 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.soundtrigger@2.0_hal", + srcs: [ + "types.hal", + "ISoundTriggerHw.hal", + "ISoundTriggerHwCallback.hal", + ], +} + +genrule { + name: "android.hardware.soundtrigger@2.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.soundtrigger@2.0", + srcs: [ + ":android.hardware.soundtrigger@2.0_hal", + ], + out: [ + "android/hardware/soundtrigger/2.0/types.cpp", + "android/hardware/soundtrigger/2.0/SoundTriggerHwAll.cpp", + "android/hardware/soundtrigger/2.0/SoundTriggerHwCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.soundtrigger@2.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.soundtrigger@2.0", + srcs: [ + ":android.hardware.soundtrigger@2.0_hal", + ], + out: [ + "android/hardware/soundtrigger/2.0/types.h", + "android/hardware/soundtrigger/2.0/ISoundTriggerHw.h", + "android/hardware/soundtrigger/2.0/IHwSoundTriggerHw.h", + "android/hardware/soundtrigger/2.0/BnHwSoundTriggerHw.h", + "android/hardware/soundtrigger/2.0/BpHwSoundTriggerHw.h", + "android/hardware/soundtrigger/2.0/BsSoundTriggerHw.h", + "android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h", + "android/hardware/soundtrigger/2.0/IHwSoundTriggerHwCallback.h", + "android/hardware/soundtrigger/2.0/BnHwSoundTriggerHwCallback.h", + "android/hardware/soundtrigger/2.0/BpHwSoundTriggerHwCallback.h", + "android/hardware/soundtrigger/2.0/BsSoundTriggerHwCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.soundtrigger@2.0", + generated_sources: ["android.hardware.soundtrigger@2.0_genc++"], + generated_headers: ["android.hardware.soundtrigger@2.0_genc++_headers"], + export_generated_headers: ["android.hardware.soundtrigger@2.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.audio.common@2.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.audio.common@2.0", + "android.hidl.base@1.0", + ], +}
diff --git a/soundtrigger/2.0/Android.mk b/soundtrigger/2.0/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/soundtrigger/2.0/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/soundtrigger/2.0/ISoundTriggerHw.hal b/soundtrigger/2.0/ISoundTriggerHw.hal new file mode 100644 index 0000000..cf35ef1 --- /dev/null +++ b/soundtrigger/2.0/ISoundTriggerHw.hal
@@ -0,0 +1,243 @@ +/* + * Copyright 2016 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.soundtrigger@2.0; + +import android.hardware.audio.common@2.0; + +import ISoundTriggerHwCallback; + +interface ISoundTriggerHw { + + /* + * Sound trigger implementation descriptor read by the framework via + * getProperties(). Used by SoundTrigger service to report to applications + * and manage concurrency and policy. + */ + struct Properties { + /* Implementor name */ + string implementor; + /* Implementation description */ + string description; + /* Implementation version */ + uint32_t version; + /* Unique implementation ID. The UUID must change with each version of + the engine implementation */ + Uuid uuid; + /* Maximum number of concurrent sound models loaded */ + uint32_t maxSoundModels; + /* Maximum number of key phrases */ + uint32_t maxKeyPhrases; + /* Maximum number of concurrent users detected */ + uint32_t maxUsers; + /* All supported modes. e.g RecognitionMode.VOICE_TRIGGER */ + uint32_t recognitionModes; + /* Supports seamless transition from detection to capture */ + bool captureTransition; + /* Maximum buffering capacity in ms if captureTransition is true */ + uint32_t maxBufferMs; + /* Supports capture by other use cases while detection is active */ + bool concurrentCapture; + /* Returns the trigger capture in event */ + bool triggerInEvent; + /* Rated power consumption when detection is active with TDB + * silence/sound/speech ratio */ + uint32_t powerConsumptionMw; + }; + + + /* + * Base sound model descriptor. This struct is the header of a larger block + * passed to loadSoundModel() and contains the binary data of the + * sound model. + */ + struct SoundModel { + /* Model type. e.g. SoundModelType.KEYPHRASE */ + SoundModelType type; + /* Unique sound model ID. */ + Uuid uuid; + /* Unique vendor ID. Identifies the engine the sound model + * was build for */ + Uuid vendorUuid; + /* Opaque data transparent to Android framework */ + vec<uint8_t> data; + }; + + /* Key phrase descriptor */ + struct Phrase { + /* Unique keyphrase ID assigned at enrollment time */ + uint32_t id; + /* Recognition modes supported by this key phrase */ + uint32_t recognitionModes; + /* List of users IDs associated with this key phrase */ + vec<uint32_t> users; + /* Locale - Java Locale style (e.g. en_US) */ + string locale; + /* Phrase text in UTF-8 format. */ + string text; + }; + + /* + * Specialized sound model for key phrase detection. + * Proprietary representation of key phrases in binary data must match + * information indicated by phrases field + */ + struct PhraseSoundModel { + /* Common part of sound model descriptor */ + SoundModel common; + /* List of descriptors for key phrases supported by this sound model */ + vec<Phrase> phrases; + }; + + /* + * Configuration for sound trigger capture session passed to + * startRecognition() method + */ + struct RecognitionConfig { + /* IO handle that will be used for capture. N/A if captureRequested + * is false */ + AudioIoHandle captureHandle; + /* Input device requested for detection capture */ + AudioDevice captureDevice; + /* Capture and buffer audio for this recognition instance */ + bool captureRequested; + /* Configuration for each key phrase */ + vec<PhraseRecognitionExtra> phrases; + /* Opaque capture configuration data transparent to the framework */ + vec<uint8_t> data; + }; + + + /* + * Retrieve implementation properties. + * @return retval Operation completion status: 0 in case of success, + * -ENODEV in case of initialization error. + * @return properties A Properties structure containing implementation + * description and capabilities. + */ + getProperties() generates (int32_t retval, Properties properties); + + /* + * Load a sound model. Once loaded, recognition of this model can be + * started and stopped. Only one active recognition per model at a time. + * The SoundTrigger service must handle concurrent recognition requests by + * different users/applications on the same model. + * The implementation returns a unique handle used by other functions + * (unloadSoundModel(), startRecognition(), etc... + * @param soundModel A SoundModel structure describing the sound model to + * load. + * @param callback The callback interface on which the soundmodelCallback() + * method will be called upon completion. + * @param cookie The value of the cookie argument passed to the completion + * callback. This unique context information is assigned and + * used only by the framework. + * @return retval Operation completion status: 0 in case of success, + * -EINVAL in case of invalid sound model (e.g 0 data size), + * -ENOSYS in case of invalid operation (e.g max number of + * models exceeded), + * -ENOMEM in case of memory allocation failure, + * -ENODEV in case of initialization error. + * @return modelHandle A unique handle assigned by the HAL for use by the + * framework when controlling activity for this sound model. + */ + loadSoundModel(SoundModel soundModel, + ISoundTriggerHwCallback callback, + CallbackCookie cookie) + generates (int32_t retval, SoundModelHandle modelHandle); + + /* + * Load a key phrase sound model. Once loaded, recognition of this model can + * be started and stopped. Only one active recognition per model at a time. + * The SoundTrigger service must handle concurrent recognition requests by + * different users/applications on the same model. + * The implementation returns a unique handle used by other functions + * (unloadSoundModel(), startRecognition(), etc... + * @param soundModel A PhraseSoundModel structure describing the sound model + * to load. + * @param callback The callback interface on which the soundmodelCallback() + * method will be called upon completion. + * @param cookie The value of the cookie argument passed to the completion + * callback. This unique context information is assigned and + * used only by the framework. + * @return retval Operation completion status: 0 in case of success, + * -EINVAL in case of invalid sound model (e.g 0 data size), + * -ENOSYS in case of invalid operation (e.g max number of + * models exceeded), + * -ENOMEM in case of memory allocation failure, + * -ENODEV in case of initialization error. + * @return modelHandle A unique handle assigned by the HAL for use by the + * framework when controlling activity for this sound model. + */ + loadPhraseSoundModel(PhraseSoundModel soundModel, + ISoundTriggerHwCallback callback, + CallbackCookie cookie) + generates (int32_t retval, SoundModelHandle modelHandle); + + /* + * Unload a sound model. A sound model may be unloaded to make room for a + * new one to overcome implementation limitations. + * @param modelHandle the handle of the sound model to unload + * @return retval Operation completion status: 0 in case of success, + * -ENOSYS if the model is not loaded, + * -ENODEV in case of initialization error. + */ + unloadSoundModel(SoundModelHandle modelHandle) + generates (int32_t retval); + + /* + * Start recognition on a given model. Only one recognition active + * at a time per model. Once recognition succeeds of fails, the callback + * is called. + * @param modelHandle the handle of the sound model to use for recognition + * @param config A RecognitionConfig structure containing attributes of the + * recognition to perform + * @param callback The callback interface on which the recognitionCallback() + * method must be called upon recognition. + * @param cookie The value of the cookie argument passed to the recognition + * callback. This unique context information is assigned and + * used only by the framework. + * @return retval Operation completion status: 0 in case of success, + * -EINVAL in case of invalid recognition attributes, + * -ENOSYS in case of invalid model handle, + * -ENOMEM in case of memory allocation failure, + * -ENODEV in case of initialization error. + */ + startRecognition(SoundModelHandle modelHandle, + RecognitionConfig config, + ISoundTriggerHwCallback callback, + CallbackCookie cookie) + generates (int32_t retval); + + /* + * Stop recognition on a given model. + * The implementation must not call the recognition callback when stopped + * via this method. + * @param modelHandle The handle of the sound model to use for recognition + * @return retval Operation completion status: 0 in case of success, + * -ENOSYS in case of invalid model handle, + * -ENODEV in case of initialization error. + */ + stopRecognition(SoundModelHandle modelHandle) + generates (int32_t retval); + + /* + * Stop recognition on all models. + * @return retval Operation completion status: 0 in case of success, + * -ENODEV in case of initialization error. + */ + stopAllRecognitions() + generates (int32_t retval); +};
diff --git a/soundtrigger/2.0/ISoundTriggerHwCallback.hal b/soundtrigger/2.0/ISoundTriggerHwCallback.hal new file mode 100644 index 0000000..c6555f6 --- /dev/null +++ b/soundtrigger/2.0/ISoundTriggerHwCallback.hal
@@ -0,0 +1,114 @@ +/* + * Copyright 2016 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.soundtrigger@2.0; + +import android.hardware.audio.common@2.0; + +interface ISoundTriggerHwCallback { + enum RecognitionStatus : uint32_t { + SUCCESS = 0, + ABORT = 1, + FAILURE = 2, + }; + + enum SoundModelStatus : uint32_t { + UPDATED = 0, + }; + + /* + * Generic recognition event sent via recognition callback + */ + struct RecognitionEvent { + /* Recognition status e.g. SUCCESS */ + RecognitionStatus status; + /* Sound model type for this event. e.g SoundModelType.TYPE_KEYPHRASE */ + SoundModelType type; + /* Handle of loaded sound model which triggered the event */ + SoundModelHandle model; + /* It is possible to capture audio from this */ + /* utterance buffered by the implementation */ + bool captureAvailable; + /* Audio session ID. framework use */ + int32_t captureSession; + /* Delay in ms between end of model detection and start of audio + /* available for capture. A negative value is possible + * (e.g. if key phrase is also available for capture */ + int32_t captureDelayMs; + /* Duration in ms of audio captured before the start of the trigger. + * 0 if none. */ + int32_t capturePreambleMs; + /* The opaque data is the capture of the trigger sound */ + bool triggerInData; + /* Audio format of either the trigger in event data or to use for + * capture of the rest of the utterance */ + AudioConfig audioConfig; + /* Opaque event data */ + vec<uint8_t> data; + }; + + /* + * Specialized recognition event for key phrase recognitions + */ + struct PhraseRecognitionEvent { + /* Common part of the recognition event */ + RecognitionEvent common; + /* List of descriptors for each recognized key phrase */ + vec<PhraseRecognitionExtra> phraseExtras; + }; + + /* + * Event sent via load sound model callback + */ + struct ModelEvent { + /* Sound model status e.g. SoundModelStatus.UPDATED */ + SoundModelStatus status; + /* Loaded sound model that triggered the event */ + SoundModelHandle model; + /* Opaque event data, passed transparently by the framework */ + vec<uint8_t> data; + }; + + typedef int32_t CallbackCookie; + + /* + * Callback method called by the HAL when the sound recognition triggers + * @param event A RecognitionEvent structure containing detailed results + * of the recognition triggered + * @param cookie The cookie passed by the framework when recognition was + * started (see ISoundtriggerHw.startRecognition() + */ + recognitionCallback(RecognitionEvent event, CallbackCookie cookie); + + /* + * Callback method called by the HAL when the sound recognition triggers + * for a key phrase sound model. + * @param event A RecognitionEvent structure containing detailed results + * of the recognition triggered + * @param cookie The cookie passed by the framework when recognition was + * started (see ISoundtriggerHw.startRecognition() + */ + phraseRecognitionCallback(PhraseRecognitionEvent event, + CallbackCookie cookie); + /* + * Callback method called by the HAL when the sound model loading completes + * @param event A ModelEvent structure containing detailed results of the + * model loading operation + * @param cookie The cookie passed by the framework when loading was + * initiated (see ISoundtriggerHw.loadSoundModel() + */ + soundModelCallback(ModelEvent event, CallbackCookie cookie); +};
diff --git a/soundtrigger/2.0/default/Android.mk b/soundtrigger/2.0/default/Android.mk new file mode 100644 index 0000000..068c6b4 --- /dev/null +++ b/soundtrigger/2.0/default/Android.mk
@@ -0,0 +1,43 @@ +# +# Copyright (C) 2016 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. + + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.soundtrigger@2.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + SoundTriggerHalImpl.cpp + +LOCAL_SHARED_LIBRARIES := \ + libhidlbase \ + libhidltransport \ + liblog \ + libutils \ + libhardware \ + android.hardware.soundtrigger@2.0 \ + android.hardware.audio.common@2.0 + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) + +ifeq ($(strip $(AUDIOSERVER_MULTILIB)),) +LOCAL_MULTILIB := 32 +else +LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB) +endif + +include $(BUILD_SHARED_LIBRARY)
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp new file mode 100644 index 0000000..b0aef4b --- /dev/null +++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
@@ -0,0 +1,595 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "SoundTriggerHalImpl" +//#define LOG_NDEBUG 0 + +#include <android/log.h> +#include "SoundTriggerHalImpl.h" + + +namespace android { +namespace hardware { +namespace soundtrigger { +namespace V2_0 { +namespace implementation { + +// static +void SoundTriggerHalImpl::soundModelCallback(struct sound_trigger_model_event *halEvent, + void *cookie) +{ + if (halEvent == NULL) { + ALOGW("soundModelCallback called with NULL event"); + return; + } + sp<SoundModelClient> client = + wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote(); + if (client == 0) { + ALOGW("soundModelCallback called on stale client"); + return; + } + if (halEvent->model != client->mHalHandle) { + ALOGW("soundModelCallback call with wrong handle %d on client with handle %d", + (int)halEvent->model, (int)client->mHalHandle); + return; + } + + ISoundTriggerHwCallback::ModelEvent event; + convertSoundModelEventFromHal(&event, halEvent); + event.model = client->mId; + + client->mCallback->soundModelCallback(event, client->mCookie); +} + +// static +void SoundTriggerHalImpl::recognitionCallback(struct sound_trigger_recognition_event *halEvent, + void *cookie) +{ + if (halEvent == NULL) { + ALOGW("recognitionCallback call NULL event"); + return; + } + sp<SoundModelClient> client = + wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote(); + if (client == 0) { + ALOGW("soundModelCallback called on stale client"); + return; + } + + ISoundTriggerHwCallback::RecognitionEvent *event = convertRecognitionEventFromHal(halEvent); + event->model = client->mId; + if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { + client->mCallback->phraseRecognitionCallback( + *(reinterpret_cast<ISoundTriggerHwCallback::PhraseRecognitionEvent *>(event)), + client->mCookie); + } else { + client->mCallback->recognitionCallback(*event, client->mCookie); + } + delete event; +} + + + +// Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow. +Return<void> SoundTriggerHalImpl::getProperties(getProperties_cb _hidl_cb) +{ + ALOGV("getProperties() mHwDevice %p", mHwDevice); + int ret; + struct sound_trigger_properties halProperties; + ISoundTriggerHw::Properties properties; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + ret = mHwDevice->get_properties(mHwDevice, &halProperties); + + convertPropertiesFromHal(&properties, &halProperties); + + ALOGV("getProperties implementor %s recognitionModes %08x", + properties.implementor.c_str(), properties.recognitionModes); + +exit: + _hidl_cb(ret, properties); + return Void(); +} + +int SoundTriggerHalImpl::doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel, + const sp<ISoundTriggerHwCallback>& callback, + ISoundTriggerHwCallback::CallbackCookie cookie, + uint32_t *modelId) +{ + int32_t ret = 0; + struct sound_trigger_sound_model *halSoundModel; + *modelId = 0; + sp<SoundModelClient> client; + + ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size()); + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + halSoundModel = convertSoundModelToHal(&soundModel); + if (halSoundModel == NULL) { + ret = -EINVAL; + goto exit; + } + + { + AutoMutex lock(mLock); + do { + *modelId = nextUniqueId(); + } while (mClients.valueFor(*modelId) != 0 && *modelId != 0); + } + LOG_ALWAYS_FATAL_IF(*modelId == 0, + "wrap around in sound model IDs, num loaded models %zu", mClients.size()); + + client = new SoundModelClient(*modelId, callback, cookie); + + ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback, + client.get(), &client->mHalHandle); + + free(halSoundModel); + + if (ret != 0) { + goto exit; + } + + { + AutoMutex lock(mLock); + mClients.add(*modelId, client); + } + +exit: + return ret; +} + +Return<void> SoundTriggerHalImpl::loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel, + const sp<ISoundTriggerHwCallback>& callback, + ISoundTriggerHwCallback::CallbackCookie cookie, + loadSoundModel_cb _hidl_cb) +{ + uint32_t modelId = 0; + int32_t ret = doLoadSoundModel(soundModel, callback, cookie, &modelId); + + _hidl_cb(ret, modelId); + return Void(); +} + +Return<void> SoundTriggerHalImpl::loadPhraseSoundModel( + const ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<ISoundTriggerHwCallback>& callback, + ISoundTriggerHwCallback::CallbackCookie cookie, + ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) +{ + uint32_t modelId = 0; + int32_t ret = doLoadSoundModel((const ISoundTriggerHw::SoundModel&)soundModel, + callback, cookie, &modelId); + + _hidl_cb(ret, modelId); + return Void(); +} + +Return<int32_t> SoundTriggerHalImpl::unloadSoundModel(SoundModelHandle modelHandle) +{ + int32_t ret; + sp<SoundModelClient> client; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + ret = mHwDevice->unload_sound_model(mHwDevice, client->mHalHandle); + + mClients.removeItem(modelHandle); + +exit: + return ret; +} + +Return<int32_t> SoundTriggerHalImpl::startRecognition(SoundModelHandle modelHandle, + const ISoundTriggerHw::RecognitionConfig& config, + const sp<ISoundTriggerHwCallback>& callback __unused, + ISoundTriggerHwCallback::CallbackCookie cookie __unused) +{ + int32_t ret; + sp<SoundModelClient> client; + struct sound_trigger_recognition_config *halConfig; + + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + + halConfig = convertRecognitionConfigToHal(&config); + + if (halConfig == NULL) { + ret = -EINVAL; + goto exit; + } + ret = mHwDevice->start_recognition(mHwDevice, client->mHalHandle, halConfig, + recognitionCallback, client.get()); + + free(halConfig); + +exit: + return ret; +} + +Return<int32_t> SoundTriggerHalImpl::stopRecognition(SoundModelHandle modelHandle) +{ + int32_t ret; + sp<SoundModelClient> client; + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + { + AutoMutex lock(mLock); + client = mClients.valueFor(modelHandle); + if (client == 0) { + ret = -ENOSYS; + goto exit; + } + } + + ret = mHwDevice->stop_recognition(mHwDevice, client->mHalHandle); + +exit: + return ret; +} + +Return<int32_t> SoundTriggerHalImpl::stopAllRecognitions() +{ + int32_t ret; + if (mHwDevice == NULL) { + ret = -ENODEV; + goto exit; + } + + if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 && + mHwDevice->stop_all_recognitions) { + ret = mHwDevice->stop_all_recognitions(mHwDevice); + } else { + ret = -ENOSYS; + } +exit: + return ret; +} + +SoundTriggerHalImpl::SoundTriggerHalImpl(const char *moduleName) + : mModuleName(moduleName), mHwDevice(NULL), mNextModelId(1) +{ +} + +void SoundTriggerHalImpl::onFirstRef() +{ + const hw_module_t *mod; + int rc; + + if (mModuleName == NULL || strlen(mModuleName) == 0) { + mModuleName = "primary"; + } + rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod); + if (rc != 0) { + ALOGE("couldn't load sound trigger module %s.%s (%s)", + SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc)); + return; + } + rc = sound_trigger_hw_device_open(mod, &mHwDevice); + if (rc != 0) { + ALOGE("couldn't open sound trigger hw device in %s.%s (%s)", + SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc)); + mHwDevice = NULL; + return; + } + if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 || + mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) { + ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version); + sound_trigger_hw_device_close(mHwDevice); + mHwDevice = NULL; + return; + } + + ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice); +} + +SoundTriggerHalImpl::~SoundTriggerHalImpl() +{ + if (mHwDevice != NULL) { + sound_trigger_hw_device_close(mHwDevice); + } +} + +uint32_t SoundTriggerHalImpl::nextUniqueId() +{ + return (uint32_t) atomic_fetch_add_explicit(&mNextModelId, + (uint_fast32_t) 1, memory_order_acq_rel); +} + +void SoundTriggerHalImpl::convertUuidFromHal(Uuid *uuid, + const sound_trigger_uuid_t *halUuid) +{ + uuid->timeLow = halUuid->timeLow; + uuid->timeMid = halUuid->timeMid; + uuid->versionAndTimeHigh = halUuid->timeHiAndVersion; + uuid->variantAndClockSeqHigh = halUuid->clockSeq; + memcpy(&uuid->node[0], &halUuid->node[0], 6); +} + +void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t *halUuid, + const Uuid *uuid) +{ + halUuid->timeLow = uuid->timeLow; + halUuid->timeMid = uuid->timeMid; + halUuid->timeHiAndVersion = uuid->versionAndTimeHigh; + halUuid->clockSeq = uuid->variantAndClockSeqHigh; + memcpy(&halUuid->node[0], &uuid->node[0], 6); +} + +void SoundTriggerHalImpl::convertPropertiesFromHal( + ISoundTriggerHw::Properties *properties, + const struct sound_trigger_properties *halProperties) +{ + properties->implementor = halProperties->implementor; + properties->description = halProperties->description; + properties->version = halProperties->version; + convertUuidFromHal(&properties->uuid, &halProperties->uuid); + properties->maxSoundModels = halProperties->max_sound_models; + properties->maxKeyPhrases = halProperties->max_key_phrases; + properties->maxUsers = halProperties->max_users; + properties->recognitionModes = halProperties->recognition_modes; + properties->captureTransition = halProperties->capture_transition; + properties->maxBufferMs = halProperties->max_buffer_ms; + properties->concurrentCapture = halProperties->concurrent_capture; + properties->triggerInEvent = halProperties->trigger_in_event; + properties->powerConsumptionMw = halProperties->power_consumption_mw; + +} + +void SoundTriggerHalImpl::convertTriggerPhraseToHal( + struct sound_trigger_phrase *halTriggerPhrase, + const ISoundTriggerHw::Phrase *triggerPhrase) +{ + halTriggerPhrase->id = triggerPhrase->id; + halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes; + unsigned int i; + for (i = 0; i < triggerPhrase->users.size(); i++) { + halTriggerPhrase->users[i] = triggerPhrase->users[i]; + } + halTriggerPhrase->num_users = i; + + strlcpy(halTriggerPhrase->locale, + triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN); + strlcpy(halTriggerPhrase->text, + triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN); +} + +struct sound_trigger_sound_model *SoundTriggerHalImpl::convertSoundModelToHal( + const ISoundTriggerHw::SoundModel *soundModel) +{ + struct sound_trigger_sound_model *halModel = NULL; + if (soundModel->type == SoundModelType::KEYPHRASE) { + size_t allocSize = + sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size(); + struct sound_trigger_phrase_sound_model *halKeyPhraseModel = + static_cast<struct sound_trigger_phrase_sound_model *>(malloc(allocSize)); + LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL, + "malloc failed for size %zu in convertSoundModelToHal PHRASE", allocSize); + + const ISoundTriggerHw::PhraseSoundModel *keyPhraseModel = + reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel *>(soundModel); + + size_t i; + for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { + convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], + &keyPhraseModel->phrases[i]); + } + halKeyPhraseModel->num_phrases = (unsigned int)i; + halModel = reinterpret_cast<struct sound_trigger_sound_model *>(halKeyPhraseModel); + halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model); + } else { + size_t allocSize = + sizeof(struct sound_trigger_sound_model) + soundModel->data.size(); + halModel = static_cast<struct sound_trigger_sound_model *>(malloc(allocSize)); + LOG_ALWAYS_FATAL_IF(halModel == NULL, + "malloc failed for size %zu in convertSoundModelToHal GENERIC", + allocSize); + + halModel->data_offset = sizeof(struct sound_trigger_sound_model); + } + halModel->type = (sound_trigger_sound_model_type_t)soundModel->type; + convertUuidToHal(&halModel->uuid, &soundModel->uuid); + convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid); + halModel->data_size = soundModel->data.size(); + uint8_t *dst = reinterpret_cast<uint8_t *>(halModel) + halModel->data_offset; + const uint8_t *src = reinterpret_cast<const uint8_t *>(&soundModel->data[0]); + memcpy(dst, src, soundModel->data.size()); + + return halModel; +} + +void SoundTriggerHalImpl::convertPhraseRecognitionExtraToHal( + struct sound_trigger_phrase_recognition_extra *halExtra, + const PhraseRecognitionExtra *extra) +{ + halExtra->id = extra->id; + halExtra->recognition_modes = extra->recognitionModes; + halExtra->confidence_level = extra->confidenceLevel; + + unsigned int i; + for (i = 0; i < extra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) { + halExtra->levels[i].user_id = extra->levels[i].userId; + halExtra->levels[i].level = extra->levels[i].levelPercent; + } + halExtra->num_levels = i; +} + +struct sound_trigger_recognition_config *SoundTriggerHalImpl::convertRecognitionConfigToHal( + const ISoundTriggerHw::RecognitionConfig *config) +{ + size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size(); + struct sound_trigger_recognition_config *halConfig = + static_cast<struct sound_trigger_recognition_config *>(malloc(allocSize)); + + LOG_ALWAYS_FATAL_IF(halConfig == NULL, + "malloc failed for size %zu in convertRecognitionConfigToHal", + allocSize); + + halConfig->capture_handle = (audio_io_handle_t)config->captureHandle; + halConfig->capture_device = (audio_devices_t)config->captureDevice; + halConfig->capture_requested = config->captureRequested; + + unsigned int i; + for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) { + convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], + &config->phrases[i]); + } + halConfig->num_phrases = i; + + halConfig->data_offset = sizeof(struct sound_trigger_recognition_config); + halConfig->data_size = config->data.size(); + uint8_t *dst = reinterpret_cast<uint8_t *>(halConfig) + halConfig->data_offset; + const uint8_t *src = reinterpret_cast<const uint8_t *>(&config->data[0]); + memcpy(dst, src, config->data.size()); + return halConfig; +} + +// static +void SoundTriggerHalImpl::convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event, + const struct sound_trigger_model_event *halEvent) +{ + event->status = (ISoundTriggerHwCallback::SoundModelStatus)halEvent->status; + // event->model to be remapped by called + event->data.setToExternal( + const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset, + halEvent->data_size); +} + +// static +ISoundTriggerHwCallback::RecognitionEvent *SoundTriggerHalImpl::convertRecognitionEventFromHal( + const struct sound_trigger_recognition_event *halEvent) +{ + ISoundTriggerHwCallback::RecognitionEvent * event; + + if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) { + const struct sound_trigger_phrase_recognition_event *halPhraseEvent = + reinterpret_cast<const struct sound_trigger_phrase_recognition_event *>(halEvent); + ISoundTriggerHwCallback::PhraseRecognitionEvent *phraseEvent = + new ISoundTriggerHwCallback::PhraseRecognitionEvent(); + + PhraseRecognitionExtra *phraseExtras = + new PhraseRecognitionExtra[halPhraseEvent->num_phrases]; + for (unsigned int i = 0; i < halPhraseEvent->num_phrases; i++) { + convertPhraseRecognitionExtraFromHal(&phraseExtras[i], + &halPhraseEvent->phrase_extras[i]); + } + phraseEvent->phraseExtras.setToExternal(phraseExtras, halPhraseEvent->num_phrases); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + phraseEvent->phraseExtras.resize(halPhraseEvent->num_phrases); + delete[] phraseExtras; + event = reinterpret_cast<ISoundTriggerHwCallback::RecognitionEvent *>(phraseEvent); + } else { + event = new ISoundTriggerHwCallback::RecognitionEvent(); + } + + event->status = static_cast<ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status); + event->type = static_cast<SoundModelType>(halEvent->type); + // event->model to be remapped by called + event->captureAvailable = halEvent->capture_available; + event->captureSession = halEvent->capture_session; + event->captureDelayMs = halEvent->capture_delay_ms; + event->capturePreambleMs = halEvent->capture_preamble_ms; + event->triggerInData = halEvent->trigger_in_data; + event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate; + event->audioConfig.channelMask = + (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask; + event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format; + event->data.setToExternal( + const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset, + halEvent->data_size); + + return event; +} + +// static +void SoundTriggerHalImpl::convertPhraseRecognitionExtraFromHal( + PhraseRecognitionExtra *extra, + const struct sound_trigger_phrase_recognition_extra *halExtra) +{ + extra->id = halExtra->id; + extra->recognitionModes = halExtra->recognition_modes; + extra->confidenceLevel = halExtra->confidence_level; + + ConfidenceLevel *levels = + new ConfidenceLevel[halExtra->num_levels]; + for (unsigned int i = 0; i < halExtra->num_levels; i++) { + levels[i].userId = halExtra->levels[i].user_id; + levels[i].levelPercent = halExtra->levels[i].level; + } + extra->levels.setToExternal(levels, halExtra->num_levels); + // FIXME: transfer buffer ownership. should have a method for that in hidl_vec + extra->levels.resize(halExtra->num_levels); + delete[] levels; +} + +ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char *name) +{ + if (name != NULL) { + if (strncmp(SOUND_TRIGGER_HARDWARE_MODULE_ID, name, + strlen(SOUND_TRIGGER_HARDWARE_MODULE_ID)) != 0) { + return NULL; + } + name = strchr(name, '.'); + if (name == NULL) { + return NULL; + } + name++; + } + return new SoundTriggerHalImpl(name); +} +} // namespace implementation +} // namespace V2_0 +} // namespace soundtrigger +} // namespace hardware +} // namespace android + + +
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.h b/soundtrigger/2.0/default/SoundTriggerHalImpl.h new file mode 100644 index 0000000..8aa9285 --- /dev/null +++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
@@ -0,0 +1,135 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_V2_0_IMPLEMENTATION_H +#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_0_IMPLEMENTATION_H + +#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h> +#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h> +#include <hidl/Status.h> +#include <stdatomic.h> +#include <utils/threads.h> +#include <utils/KeyedVector.h> +#include <system/sound_trigger.h> +#include <hardware/sound_trigger.h> + +namespace android { +namespace hardware { +namespace soundtrigger { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::Uuid; +using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback; + + +class SoundTriggerHalImpl : public ISoundTriggerHw { +public: + explicit SoundTriggerHalImpl(const char *moduleName = NULL); + + // Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow. + Return<void> getProperties(getProperties_cb _hidl_cb) override; + Return<void> loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel, + const sp<ISoundTriggerHwCallback>& callback, + ISoundTriggerHwCallback::CallbackCookie cookie, + loadSoundModel_cb _hidl_cb) override; + Return<void> loadPhraseSoundModel(const ISoundTriggerHw::PhraseSoundModel& soundModel, + const sp<ISoundTriggerHwCallback>& callback, + ISoundTriggerHwCallback::CallbackCookie cookie, + loadPhraseSoundModel_cb _hidl_cb) override; + + Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle) override; + Return<int32_t> startRecognition(SoundModelHandle modelHandle, + const ISoundTriggerHw::RecognitionConfig& config, + const sp<ISoundTriggerHwCallback>& callback, + ISoundTriggerHwCallback::CallbackCookie cookie) override; + Return<int32_t> stopRecognition(SoundModelHandle modelHandle) override; + Return<int32_t> stopAllRecognitions() override; + + // RefBase + virtual void onFirstRef(); + + static void soundModelCallback(struct sound_trigger_model_event *halEvent, + void *cookie); + static void recognitionCallback(struct sound_trigger_recognition_event *halEvent, + void *cookie); + +private: + + class SoundModelClient : public RefBase { + public: + SoundModelClient(uint32_t id, sp<ISoundTriggerHwCallback> callback, + ISoundTriggerHwCallback::CallbackCookie cookie) + : mId(id), mCallback(callback), mCookie(cookie) {} + virtual ~SoundModelClient() {} + + uint32_t mId; + sound_model_handle_t mHalHandle; + sp<ISoundTriggerHwCallback> mCallback; + ISoundTriggerHwCallback::CallbackCookie mCookie; + }; + + uint32_t nextUniqueId(); + void convertUuidFromHal(Uuid *uuid, + const sound_trigger_uuid_t *halUuid); + void convertUuidToHal(sound_trigger_uuid_t *halUuid, + const Uuid *uuid); + void convertPropertiesFromHal(ISoundTriggerHw::Properties *properties, + const struct sound_trigger_properties *halProperties); + void convertTriggerPhraseToHal(struct sound_trigger_phrase *halTriggerPhrase, + const ISoundTriggerHw::Phrase *triggerPhrase); + // returned HAL sound model must be freed by caller + struct sound_trigger_sound_model *convertSoundModelToHal( + const ISoundTriggerHw::SoundModel *soundModel); + void convertPhraseRecognitionExtraToHal( + struct sound_trigger_phrase_recognition_extra *halExtra, + const PhraseRecognitionExtra *extra); + // returned recognition config must be freed by caller + struct sound_trigger_recognition_config *convertRecognitionConfigToHal( + const ISoundTriggerHw::RecognitionConfig *config); + + + static void convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event, + const struct sound_trigger_model_event *halEvent); + static ISoundTriggerHwCallback::RecognitionEvent *convertRecognitionEventFromHal( + const struct sound_trigger_recognition_event *halEvent); + static void convertPhraseRecognitionExtraFromHal(PhraseRecognitionExtra *extra, + const struct sound_trigger_phrase_recognition_extra *halExtra); + + int doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel, + const sp<ISoundTriggerHwCallback>& callback, + ISoundTriggerHwCallback::CallbackCookie cookie, + uint32_t *modelId); + + virtual ~SoundTriggerHalImpl(); + + const char * mModuleName; + struct sound_trigger_hw_device* mHwDevice; + volatile atomic_uint_fast32_t mNextModelId; + DefaultKeyedVector<int32_t, sp<SoundModelClient> > mClients; + Mutex mLock; +}; + +extern "C" ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char *name); + +} // namespace implementation +} // namespace V2_0 +} // namespace soundtrigger +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_SOUNDTRIGGER_V2_0_IMPLEMENTATION_H +
diff --git a/soundtrigger/2.0/types.hal b/soundtrigger/2.0/types.hal new file mode 100644 index 0000000..26928ba --- /dev/null +++ b/soundtrigger/2.0/types.hal
@@ -0,0 +1,81 @@ +/* + * Copyright 2016 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.soundtrigger@2.0; + +/* + * Sound model types modes used in ISoundTriggerHw.SoundModel + */ +enum SoundModelType : int32_t { + /* use for unspecified sound model type */ + UNKNOWN = -1, + /* use for key phrase sound models */ + KEYPHRASE = 0, + /* use for all models other than keyphrase */ + GENERIC = 1, +}; + +typedef int32_t SoundModelHandle; + + +/* + * Recognition modes used in ISoundTriggerHw.RecognitionConfig, + * ISoundTriggerHw.Properties or PhraseRecognitionExtra + */ +enum RecognitionMode : uint32_t { + /* simple voice trigger */ + VOICE_TRIGGER = (1 << 0), + /* trigger only if one user in model identified */ + USER_IDENTIFICATION = (1 << 1), + /* trigger only if one user in mode authenticated */ + USER_AUTHENTICATION = (1 << 2), + /* generic sound trigger */ + GENERIC_TRIGGER = (1 << 3), +}; + +/* + * Confidence level for each user in structure PhraseRecognitionExtra + */ +struct ConfidenceLevel { + /* user ID */ + uint32_t userId; + /* confidence level in percent (0 - 100): */ + /* - min level for recognition configuration */ + /* - detected level for recognition event */ + uint32_t levelPercent; +}; + +/* + * Specialized recognition event for key phrase detection + */ +struct PhraseRecognitionExtra { + /* keyphrase ID */ + uint32_t id; + /* recognition modes used for this keyphrase */ + uint32_t recognitionModes; + /* confidence level for mode RecognitionMode.VOICE_TRIGGER */ + uint32_t confidenceLevel; + /* list of confidence levels per user for + * RecognitionMode.USER_IDENTIFICATION and + * RecognitionMode.USER_AUTHENTICATION */ + vec<ConfidenceLevel> levels; +}; + +/* TODO(elaurent) remove when Java build problem is fixed */ +union Dummy { + uint32_t dummy1; + int32_t dummy2; +}; \ No newline at end of file
diff --git a/soundtrigger/2.0/vts/Android.mk b/soundtrigger/2.0/vts/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/soundtrigger/2.0/vts/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/soundtrigger/2.0/vts/functional/Android.bp b/soundtrigger/2.0/vts/functional/Android.bp new file mode 100644 index 0000000..8f0cc4e --- /dev/null +++ b/soundtrigger/2.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalSoundtriggerV2_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalSoundtriggerV2_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.soundtrigger@2.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +}
diff --git a/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp new file mode 100644 index 0000000..0ef4063 --- /dev/null +++ b/soundtrigger/2.0/vts/functional/VtsHalSoundtriggerV2_0TargetTest.cpp
@@ -0,0 +1,327 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "SoundTriggerHidlHalTest" +#include <stdlib.h> +#include <time.h> + +#include <condition_variable> +#include <mutex> + +#include <android/log.h> +#include <cutils/native_handle.h> + +#include <android/hardware/audio/common/2.0/types.h> +#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h> +#include <android/hardware/soundtrigger/2.0/types.h> + +#include <VtsHalHidlTargetTestBase.h> + +#define SHORT_TIMEOUT_PERIOD (1) + +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::soundtrigger::V2_0::SoundModelHandle; +using ::android::hardware::soundtrigger::V2_0::SoundModelType; +using ::android::hardware::soundtrigger::V2_0::RecognitionMode; +using ::android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra; +using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw; +using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback; +using ::android::hardware::Return; +using ::android::hardware::Status; +using ::android::hardware::Void; +using ::android::sp; + +/** + * Test code uses this class to wait for notification from callback. + */ +class Monitor { + public: + Monitor() : mCount(0) {} + + /** + * Adds 1 to the internal counter and unblocks one of the waiting threads. + */ + void notify() { + std::unique_lock<std::mutex> lock(mMtx); + mCount++; + mCv.notify_one(); + } + + /** + * Blocks until the internal counter becomes greater than 0. + * + * If notified, this method decreases the counter by 1 and returns true. + * If timeout, returns false. + */ + bool wait(int timeoutSeconds) { + std::unique_lock<std::mutex> lock(mMtx); + auto deadline = std::chrono::system_clock::now() + + std::chrono::seconds(timeoutSeconds); + while (mCount == 0) { + if (mCv.wait_until(lock, deadline) == std::cv_status::timeout) { + return false; + } + } + mCount--; + return true; + } + + private: + std::mutex mMtx; + std::condition_variable mCv; + int mCount; +}; + +// The main test class for Sound Trigger HIDL HAL. +class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>("sound_trigger.primary"); + ASSERT_NE(nullptr, mSoundTriggerHal.get()); + mCallback = new SoundTriggerHwCallback(*this); + ASSERT_NE(nullptr, mCallback.get()); + } + + static void SetUpTestCase() { + srand(time(nullptr)); + } + + class SoundTriggerHwCallback : public ISoundTriggerHwCallback { + private: + SoundTriggerHidlTest& mParent; + + public: + SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {} + + virtual Return<void> recognitionCallback( + const ISoundTriggerHwCallback::RecognitionEvent& event __unused, + int32_t cookie __unused) { + ALOGI("%s", __FUNCTION__); + return Void(); + } + + virtual Return<void> phraseRecognitionCallback( + const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused, + int32_t cookie __unused) { + ALOGI("%s", __FUNCTION__); + return Void(); + } + + virtual Return<void> soundModelCallback( + const ISoundTriggerHwCallback::ModelEvent& event, + int32_t cookie __unused) { + ALOGI("%s", __FUNCTION__); + mParent.lastModelEvent = event; + mParent.monitor.notify(); + return Void(); + } + }; + + virtual void TearDown() override {} + + Monitor monitor; + // updated by soundModelCallback() + ISoundTriggerHwCallback::ModelEvent lastModelEvent; + + protected: + sp<ISoundTriggerHw> mSoundTriggerHal; + sp<SoundTriggerHwCallback> mCallback; +}; + +// A class for test environment setup (kept since this file is a template). +class SoundTriggerHidlEnvironment : public ::testing::Environment { + public: + virtual void SetUp() {} + virtual void TearDown() {} + + private: +}; + +/** + * Test ISoundTriggerHw::getProperties() method + * + * Verifies that: + * - the implementation implements the method + * - the method returns 0 (no error) + * - the implementation supports at least one sound model and one key phrase + * - the implementation supports at least VOICE_TRIGGER recognition mode + */ +TEST_F(SoundTriggerHidlTest, GetProperties) { + ISoundTriggerHw::Properties halProperties; + Return<void> hidlReturn; + int ret = -ENODEV; + + hidlReturn = mSoundTriggerHal->getProperties([&](int rc, auto res) { + ret = rc; + halProperties = res; + }); + + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_EQ(0, ret); + EXPECT_GT(halProperties.maxSoundModels, 0u); + EXPECT_GT(halProperties.maxKeyPhrases, 0u); + EXPECT_NE(0u, (halProperties.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER)); +} + +/** + * Test ISoundTriggerHw::loadPhraseSoundModel() method + * + * Verifies that: + * - the implementation implements the method + * - the implementation returns an error when passed a malformed sound model + * + * There is no way to verify that implementation actually can load a sound model because each + * sound model is vendor specific. + */ +TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) { + Return<void> hidlReturn; + int ret = -ENODEV; + ISoundTriggerHw::PhraseSoundModel model; + SoundModelHandle handle; + + model.common.type = SoundModelType::UNKNOWN; + + hidlReturn = mSoundTriggerHal->loadPhraseSoundModel( + model, + mCallback, 0, [&](int32_t retval, auto res) { + ret = retval; + handle = res; + }); + + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_NE(0, ret); + EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD)); +} + +/** + * Test ISoundTriggerHw::loadSoundModel() method + * + * Verifies that: + * - the implementation returns error when passed a sound model with random data. + */ +TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) { + int ret = -ENODEV; + ISoundTriggerHw::SoundModel model; + SoundModelHandle handle = 0; + + model.type = SoundModelType::GENERIC; + model.data.resize(100); + for (auto& d : model.data) { + d = rand(); + } + + Return<void> loadReturn = mSoundTriggerHal->loadSoundModel( + model, + mCallback, 0, [&](int32_t retval, auto res) { + ret = retval; + handle = res; + }); + + EXPECT_TRUE(loadReturn.isOk()); + EXPECT_NE(0, ret); + EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD)); +} + +/** + * Test ISoundTriggerHw::unloadSoundModel() method + * + * Verifies that: + * - the implementation implements the method + * - the implementation returns an error when called without a valid loaded sound model + * + */ +TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) { + Return<int32_t> hidlReturn(0); + SoundModelHandle halHandle = 0; + + hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle); + + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_NE(0, hidlReturn); +} + +/** + * Test ISoundTriggerHw::startRecognition() method + * + * Verifies that: + * - the implementation implements the method + * - the implementation returns an error when called without a valid loaded sound model + * + * There is no way to verify that implementation actually starts recognition because no model can + * be loaded. + */ +TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) { + Return<int32_t> hidlReturn(0); + SoundModelHandle handle = 0; + PhraseRecognitionExtra phrase; + ISoundTriggerHw::RecognitionConfig config; + + config.captureHandle = 0; + config.captureDevice = AudioDevice::IN_BUILTIN_MIC; + phrase.id = 0; + phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER; + phrase.confidenceLevel = 0; + + config.phrases.setToExternal(&phrase, 1); + + hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0); + + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_NE(0, hidlReturn); +} + +/** + * Test ISoundTriggerHw::stopRecognition() method + * + * Verifies that: + * - the implementation implements the method + * - the implementation returns an error when called without an active recognition running + * + */ +TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) { + Return<int32_t> hidlReturn(0); + SoundModelHandle handle = 0; + + hidlReturn = mSoundTriggerHal->stopRecognition(handle); + + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_NE(0, hidlReturn); +} + +/** + * Test ISoundTriggerHw::stopAllRecognitions() method + * + * Verifies that: + * - the implementation implements this optional method or indicates it is not support by + * returning -ENOSYS + */ +TEST_F(SoundTriggerHidlTest, stopAllRecognitions) { + Return<int32_t> hidlReturn(0); + + hidlReturn = mSoundTriggerHal->stopAllRecognitions(); + + EXPECT_TRUE(hidlReturn.isOk()); + EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS); +} + + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(new SoundTriggerHidlEnvironment); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +}
diff --git a/soundtrigger/Android.bp b/soundtrigger/Android.bp new file mode 100644 index 0000000..8d2c986 --- /dev/null +++ b/soundtrigger/Android.bp
@@ -0,0 +1,5 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "2.0", + "2.0/vts/functional", +]
diff --git a/tests/Android.bp b/tests/Android.bp index 9bb4bf5..6606d94 100644 --- a/tests/Android.bp +++ b/tests/Android.bp
@@ -5,6 +5,7 @@ "baz/1.0", "baz/1.0/default", "expression/1.0", + "extension/light/2.0", "foo/1.0", "foo/1.0/default", "foo/1.0/default/lib",
diff --git a/tests/bar/Android.mk b/tests/bar/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tests/bar/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/tests/baz/Android.mk b/tests/baz/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tests/baz/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/tests/expression/Android.mk b/tests/expression/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tests/expression/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/tests/extension/light/2.0/Android.bp b/tests/extension/light/2.0/Android.bp new file mode 100644 index 0000000..5203da6 --- /dev/null +++ b/tests/extension/light/2.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.tests.extension.light@2.0_hal", + srcs: [ + "types.hal", + "IExtLight.hal", + ], +} + +genrule { + name: "android.hardware.tests.extension.light@2.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.extension.light@2.0", + srcs: [ + ":android.hardware.tests.extension.light@2.0_hal", + ], + out: [ + "android/hardware/tests/extension/light/2.0/types.cpp", + "android/hardware/tests/extension/light/2.0/ExtLightAll.cpp", + ], +} + +genrule { + name: "android.hardware.tests.extension.light@2.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tests.extension.light@2.0", + srcs: [ + ":android.hardware.tests.extension.light@2.0_hal", + ], + out: [ + "android/hardware/tests/extension/light/2.0/types.h", + "android/hardware/tests/extension/light/2.0/IExtLight.h", + "android/hardware/tests/extension/light/2.0/IHwExtLight.h", + "android/hardware/tests/extension/light/2.0/BnHwExtLight.h", + "android/hardware/tests/extension/light/2.0/BpHwExtLight.h", + "android/hardware/tests/extension/light/2.0/BsExtLight.h", + ], +} + +cc_library_shared { + name: "android.hardware.tests.extension.light@2.0", + generated_sources: ["android.hardware.tests.extension.light@2.0_genc++"], + generated_headers: ["android.hardware.tests.extension.light@2.0_genc++_headers"], + export_generated_headers: ["android.hardware.tests.extension.light@2.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.light@2.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.light@2.0", + ], +}
diff --git a/tests/extension/light/2.0/Android.mk b/tests/extension/light/2.0/Android.mk new file mode 100644 index 0000000..16424a3 --- /dev/null +++ b/tests/extension/light/2.0/Android.mk
@@ -0,0 +1,196 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.tests.extension.light@2.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hardware.light@2.0-java \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (Default) +# +GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/Default.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tests.extension.light@2.0::types.Default + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ExtBrightness) +# +GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/ExtBrightness.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tests.extension.light@2.0::types.ExtBrightness + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ExtLightState) +# +GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/ExtLightState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tests.extension.light@2.0::types.ExtLightState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IExtLight.hal +# +GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/IExtLight.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IExtLight.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tests.extension.light@2.0::IExtLight + +$(GEN): $(LOCAL_PATH)/IExtLight.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.tests.extension.light@2.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hardware.light@2.0-java-static \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (Default) +# +GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/Default.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tests.extension.light@2.0::types.Default + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ExtBrightness) +# +GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/ExtBrightness.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tests.extension.light@2.0::types.ExtBrightness + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ExtLightState) +# +GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/ExtLightState.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tests.extension.light@2.0::types.ExtLightState + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IExtLight.hal +# +GEN := $(intermediates)/android/hardware/tests/extension/light/V2_0/IExtLight.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IExtLight.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tests.extension.light@2.0::IExtLight + +$(GEN): $(LOCAL_PATH)/IExtLight.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/extension/light/2.0/IExtLight.hal b/tests/extension/light/2.0/IExtLight.hal new file mode 100644 index 0000000..1515b86 --- /dev/null +++ b/tests/extension/light/2.0/IExtLight.hal
@@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 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. + */ + +// Would normally be 'vendor.example.extension.light@2.0' however, this is +// a google extension example. A vendor extension should also live in the +// vendor partition. +package android.hardware.tests.extension.light@2.0; + +import android.hardware.light@2.0; + +interface IExtLight extends android.hardware.light@2.0::ILight { + + /** + * Set the provided lights to the provided values. + * + * @param type logical light to set + * @param state describes what the light should look like. + * @return status result of applying state transformation. + */ + setExtLight(Type type, ExtLightState state) generates (Status status); + +};
diff --git a/tests/extension/light/2.0/default/Android.mk b/tests/extension/light/2.0/default/Android.mk new file mode 100644 index 0000000..b30d11c --- /dev/null +++ b/tests/extension/light/2.0/default/Android.mk
@@ -0,0 +1,19 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.tests.extension.light@2.0-service +LOCAL_INIT_RC := android.hardware.tests.extension.light@2.0-service.rc +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + Light.cpp \ + service.cpp + +LOCAL_SHARED_LIBRARIES := \ + libhidlbase \ + libhidltransport \ + libutils \ + android.hardware.light@2.0 \ + android.hardware.tests.extension.light@2.0 \ + +include $(BUILD_EXECUTABLE)
diff --git a/tests/extension/light/2.0/default/Light.cpp b/tests/extension/light/2.0/default/Light.cpp new file mode 100644 index 0000000..d941e73 --- /dev/null +++ b/tests/extension/light/2.0/default/Light.cpp
@@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 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. + */ +#include "Light.h" + +namespace android { +namespace hardware { +namespace tests { +namespace extension { +namespace light { +namespace V2_0 { +namespace implementation { + +// Methods from ::android::hardware::light::V2_0::ILight follow. +Return<Status> Light::setLight(Type type, const LightState& state) { + // Forward types for new methods. + + ExtLightState extState { + .state = state, + .interpolationOmega = + static_cast<int32_t>(Default::INTERPOLATION_OMEGA), + .brightness = // ExtBrightness inherits from Brightness + static_cast<ExtBrightness>(state.brightnessMode) + }; + + return setExtLight(type, extState); +} + +Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb) { + // implement unchanged method as you would always + hidl_vec<Type> vec{}; + + // ****************************************************** + // Note: awesome proprietary hardware implementation here + // ****************************************************** + + _hidl_cb(vec); + + return Void(); +} + +// Methods from ::android::hardware::example::extension::light::V2_0::ILight follow. +Return<Status> Light::setExtLight(Type /* type */, + const ExtLightState& /* state */) { + + // ****************************************************** + // Note: awesome proprietary hardware implementation here + // ****************************************************** + + return Status::SUCCESS; +} + +} // namespace implementation +} // namespace V2_0 +} // namespace light +} // namespace extension +} // namespace tests +} // namespace hardware +} // namespace android
diff --git a/tests/extension/light/2.0/default/Light.h b/tests/extension/light/2.0/default/Light.h new file mode 100644 index 0000000..dc2c5dd --- /dev/null +++ b/tests/extension/light/2.0/default/Light.h
@@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_TESTS_EXTENSION_LIGHT_V2_0_LIGHT_H +#define ANDROID_HARDWARE_TESTS_EXTENSION_LIGHT_V2_0_LIGHT_H + +#include <android/hardware/tests/extension/light/2.0/IExtLight.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace tests { +namespace extension { +namespace light { +namespace V2_0 { +namespace implementation { + +using ::android::hardware::tests::extension::light::V2_0::ExtLightState; +using ::android::hardware::tests::extension::light::V2_0::IExtLight; +using ::android::hardware::light::V2_0::ILight; +using ::android::hardware::light::V2_0::LightState; +using ::android::hardware::light::V2_0::Status; +using ::android::hardware::light::V2_0::Type; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Light : public IExtLight { + // Methods from ::android::hardware::light::V2_0::ILight follow. + Return<Status> setLight(Type type, const LightState& state) override; + Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb) override; + + // Methods from ::android::hardware::example::extension::light::V2_0::ILight follow. + Return<Status> setExtLight(Type type, const ExtLightState& state) override; + +}; + +} // namespace implementation +} // namespace V2_0 +} // namespace light +} // namespace extension +} // namespace tests +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TESTS_EXTENSION_LIGHT_V2_0_LIGHT_H
diff --git a/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc b/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc new file mode 100644 index 0000000..8f379ee --- /dev/null +++ b/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc
@@ -0,0 +1,4 @@ +service light-ext-2-0 /vendor/bin/hw/android.hardware.tests.extension.light@2.0-service + class hal + user system + group system \ No newline at end of file
diff --git a/tests/extension/light/2.0/default/service.cpp b/tests/extension/light/2.0/default/service.cpp new file mode 100644 index 0000000..4d839b2 --- /dev/null +++ b/tests/extension/light/2.0/default/service.cpp
@@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.tests.extension.light@2.0-service" + +#include <android/log.h> +#include <hidl/HidlTransportSupport.h> + +#include "Light.h" + +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::sp; + +using android::hardware::light::V2_0::ILight; +using android::hardware::tests::extension::light::V2_0::implementation::Light; + +int main() { + android::sp<ILight> service = new Light(); + configureRpcThreadpool(1, true /*callerWillJoin*/); + service->registerAsService(); + joinRpcThreadpool(); +}
diff --git a/tests/extension/light/2.0/types.hal b/tests/extension/light/2.0/types.hal new file mode 100644 index 0000000..1b09479 --- /dev/null +++ b/tests/extension/light/2.0/types.hal
@@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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.tests.extension.light@2.0; + +import android.hardware.light@2.0; + +enum Default : int32_t { + // for calls to setLight from the framework that don't know about this + // extension or its requirements + INTERPOLATION_OMEGA = 2 +}; + +/** + * One possibility is renaming an old type. Another possibility is taking + * advantages of the different namespaces. + */ +enum ExtBrightness : Brightness { + /** + * Say we're really going to use the phone as a heater. + */ + EXTREME, + + /** + * Sometimes at night, we need it to be day. + */ + THE_SUN, +}; + +/** + * Structs can't inherit eachother in hidl. Use composition instead. In this + * case, I won't use inheritence because I want to replace Brightness with + * ExtBrightness. + */ +struct ExtLightState { + LightState state; + + /** + * This is the secret sauce that will really make this extension shine. + * No other person has such a cool feature in their hals. Don't forget + * to describe all details of parameters. An interface is a contract, and + * specifying this contract to the letter is what allows that contracted + * to be maintained. :) + * + * So, this parameter represents the speed at which brightness is changed + * to the new value in the three dimensional space with coordinates RGB + * from the red, blue, and green. + */ + int32_t interpolationOmega; + + /** + * Include new values. + */ + ExtBrightness brightness; +};
diff --git a/tests/foo/Android.mk b/tests/foo/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tests/foo/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/tests/inheritance/Android.mk b/tests/inheritance/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tests/inheritance/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/tests/libhwbinder/Android.mk b/tests/libhwbinder/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tests/libhwbinder/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/tests/msgq/Android.mk b/tests/msgq/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tests/msgq/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/tests/pointer/Android.mk b/tests/pointer/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tests/pointer/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/thermal/1.0/Android.bp b/thermal/1.0/Android.bp new file mode 100644 index 0000000..fab5533 --- /dev/null +++ b/thermal/1.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.thermal@1.0_hal", + srcs: [ + "types.hal", + "IThermal.hal", + ], +} + +genrule { + name: "android.hardware.thermal@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.thermal@1.0", + srcs: [ + ":android.hardware.thermal@1.0_hal", + ], + out: [ + "android/hardware/thermal/1.0/types.cpp", + "android/hardware/thermal/1.0/ThermalAll.cpp", + ], +} + +genrule { + name: "android.hardware.thermal@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.thermal@1.0", + srcs: [ + ":android.hardware.thermal@1.0_hal", + ], + out: [ + "android/hardware/thermal/1.0/types.h", + "android/hardware/thermal/1.0/IThermal.h", + "android/hardware/thermal/1.0/IHwThermal.h", + "android/hardware/thermal/1.0/BnHwThermal.h", + "android/hardware/thermal/1.0/BpHwThermal.h", + "android/hardware/thermal/1.0/BsThermal.h", + ], +} + +cc_library_shared { + name: "android.hardware.thermal@1.0", + generated_sources: ["android.hardware.thermal@1.0_genc++"], + generated_headers: ["android.hardware.thermal@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.thermal@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/thermal/1.0/Android.mk b/thermal/1.0/Android.mk new file mode 100644 index 0000000..7748b9e --- /dev/null +++ b/thermal/1.0/Android.mk
@@ -0,0 +1,380 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.thermal@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (CoolingDevice) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/CoolingDevice.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.CoolingDevice + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CoolingType) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/CoolingType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.CoolingType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CpuUsage) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/CpuUsage.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.CpuUsage + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Temperature) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/Temperature.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.Temperature + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TemperatureType) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/TemperatureType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.TemperatureType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ThermalStatus) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/ThermalStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.ThermalStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ThermalStatusCode) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/ThermalStatusCode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.ThermalStatusCode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IThermal.hal +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/IThermal.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IThermal.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::IThermal + +$(GEN): $(LOCAL_PATH)/IThermal.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.thermal@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (CoolingDevice) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/CoolingDevice.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.CoolingDevice + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CoolingType) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/CoolingType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.CoolingType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CpuUsage) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/CpuUsage.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.CpuUsage + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Temperature) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/Temperature.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.Temperature + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (TemperatureType) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/TemperatureType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.TemperatureType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ThermalStatus) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/ThermalStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.ThermalStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (ThermalStatusCode) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/ThermalStatusCode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::types.ThermalStatusCode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IThermal.hal +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/IThermal.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IThermal.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0::IThermal + +$(GEN): $(LOCAL_PATH)/IThermal.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.thermal@1.0-java-constants +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +# +GEN := $(intermediates)/android/hardware/thermal/V1_0/Constants.java +$(GEN): $(HIDL) +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/IThermal.hal + +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava-constants \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.thermal@1.0 + +$(GEN): + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +# Avoid dependency cycle of framework.jar -> this-library -> framework.jar +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj + +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/thermal/1.0/IThermal.hal b/thermal/1.0/IThermal.hal new file mode 100644 index 0000000..e5f70cb --- /dev/null +++ b/thermal/1.0/IThermal.hal
@@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 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.thermal@1.0; + +interface IThermal { + + /* + * Retrieves temperatures in Celsius. + * + * @return status Status of the operation. If status code is FAILURE, + * the status.debugMessage must be populated with the human-readable + * error message. + * @return temperatures If status code is SUCCESS, it's filled with the + * current temperatures. The order of temperatures of built-in + * devices (such as CPUs, GPUs and etc.) in the list must be kept + * the same regardless the number of calls to this method even if + * they go offline, if these devices exist on boot. The method + * always returns and never removes such temperatures. + * + */ + @callflow(next={"*"}) + @entry + @exit + getTemperatures() + generates (ThermalStatus status, vec<Temperature> temperatures); + + /* + * Retrieves CPU usage information of each core: active and total times + * in ms since first boot. + * + * @return status Status of the operation. If status code is FAILURE, + * the status.debugMessage must be populated with the human-readable + * error message. + * @return cpuUsages If status code is SUCCESS, it's filled with the current + * CPU usages. The order and number of CPUs in the list must be kept + * the same regardless the number of calls to this method. + * + */ + @callflow(next={"*"}) + @entry + @exit + getCpuUsages() generates (ThermalStatus status, vec<CpuUsage> cpuUsages); + + /* + * Retrieves the cooling devices information. + * + * @return status Status of the operation. If status code is FAILURE, + * the status.debugMessage must be populated with the human-readable + * error message. + * @return devices If status code is SUCCESS, it's filled with the current + * cooling device information. The order of built-in cooling + * devices in the list must be kept the same regardless the number + * of calls to this method even if they go offline, if these devices + * exist on boot. The method always returns and never removes from + * the list such cooling devices. + * + */ + @callflow(next={"*"}) + @entry + @exit + getCoolingDevices() + generates (ThermalStatus status, vec<CoolingDevice> devices); + +};
diff --git a/thermal/1.0/default/Android.bp b/thermal/1.0/default/Android.bp new file mode 100644 index 0000000..1510509 --- /dev/null +++ b/thermal/1.0/default/Android.bp
@@ -0,0 +1,18 @@ +cc_library_shared { + name: "android.hardware.thermal@1.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["Thermal.cpp"], + shared_libs: [ + "liblog", + "libcutils", + "libhardware", + "libbase", + "libcutils", + "libutils", + "libhidlbase", + "libhidltransport", + "android.hardware.thermal@1.0", + ], +}
diff --git a/thermal/1.0/default/Android.mk b/thermal/1.0/default/Android.mk new file mode 100644 index 0000000..2d25dc3 --- /dev/null +++ b/thermal/1.0/default/Android.mk
@@ -0,0 +1,40 @@ +# +# Copyright (C) 2016 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.thermal@1.0-service +LOCAL_INIT_RC := android.hardware.thermal@1.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + +LOCAL_SHARED_LIBRARIES += \ + libhidlbase \ + libhidltransport \ + android.hardware.thermal@1.0 \ + +include $(BUILD_EXECUTABLE)
diff --git a/thermal/1.0/default/Thermal.cpp b/thermal/1.0/default/Thermal.cpp new file mode 100644 index 0000000..2dd0090 --- /dev/null +++ b/thermal/1.0/default/Thermal.cpp
@@ -0,0 +1,210 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.thermal@1.0-impl" + +#include <errno.h> +#include <math.h> + +#include <vector> + +#include <log/log.h> + +#include <hardware/hardware.h> +#include <hardware/thermal.h> + +#include "Thermal.h" + +namespace android { +namespace hardware { +namespace thermal { +namespace V1_0 { +namespace implementation { + +namespace { + +float finalizeTemperature(float temperature) { + return temperature == UNKNOWN_TEMPERATURE ? NAN : temperature; +} + +} + +Thermal::Thermal(thermal_module_t* module) : mModule(module) {} + +// Methods from ::android::hardware::thermal::V1_0::IThermal follow. +Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + hidl_vec<Temperature> temperatures; + + if (!mModule || !mModule->getTemperatures) { + ALOGI("getTemperatures is not implemented in Thermal HAL."); + _hidl_cb(status, temperatures); + return Void(); + } + + ssize_t size = mModule->getTemperatures(mModule, nullptr, 0); + if (size >= 0) { + std::vector<temperature_t> list; + list.resize(size); + size = mModule->getTemperatures(mModule, list.data(), list.size()); + if (size >= 0) { + temperatures.resize(list.size()); + for (size_t i = 0; i < list.size(); ++i) { + switch (list[i].type) { + case DEVICE_TEMPERATURE_UNKNOWN: + temperatures[i].type = TemperatureType::UNKNOWN; + break; + case DEVICE_TEMPERATURE_CPU: + temperatures[i].type = TemperatureType::CPU; + break; + case DEVICE_TEMPERATURE_GPU: + temperatures[i].type = TemperatureType::GPU; + break; + case DEVICE_TEMPERATURE_BATTERY: + temperatures[i].type = TemperatureType::BATTERY; + break; + case DEVICE_TEMPERATURE_SKIN: + temperatures[i].type = TemperatureType::SKIN; + break; + default: + ALOGE("Unknown temperature %s type", list[i].name); + ; + } + temperatures[i].name = list[i].name; + temperatures[i].currentValue = finalizeTemperature(list[i].current_value); + temperatures[i].throttlingThreshold = finalizeTemperature(list[i].throttling_threshold); + temperatures[i].shutdownThreshold = finalizeTemperature(list[i].shutdown_threshold); + temperatures[i].vrThrottlingThreshold = + finalizeTemperature(list[i].vr_throttling_threshold); + } + } + } + if (size < 0) { + status.code = ThermalStatusCode::FAILURE; + status.debugMessage = strerror(-size); + } + _hidl_cb(status, temperatures); + return Void(); +} + +Return<void> Thermal::getCpuUsages(getCpuUsages_cb _hidl_cb) { + ThermalStatus status; + hidl_vec<CpuUsage> cpuUsages; + status.code = ThermalStatusCode::SUCCESS; + + if (!mModule || !mModule->getCpuUsages) { + ALOGI("getCpuUsages is not implemented in Thermal HAL"); + _hidl_cb(status, cpuUsages); + return Void(); + } + + ssize_t size = mModule->getCpuUsages(mModule, nullptr); + if (size >= 0) { + std::vector<cpu_usage_t> list; + list.resize(size); + size = mModule->getCpuUsages(mModule, list.data()); + if (size >= 0) { + list.resize(size); + cpuUsages.resize(size); + for (size_t i = 0; i < list.size(); ++i) { + cpuUsages[i].name = list[i].name; + cpuUsages[i].active = list[i].active; + cpuUsages[i].total = list[i].total; + cpuUsages[i].isOnline = list[i].is_online; + } + } else { + status.code = ThermalStatusCode::FAILURE; + status.debugMessage = strerror(-size); + } + } + if (size < 0) { + status.code = ThermalStatusCode::FAILURE; + status.debugMessage = strerror(-size); + } + _hidl_cb(status, cpuUsages); + return Void(); +} + +Return<void> Thermal::getCoolingDevices(getCoolingDevices_cb _hidl_cb) { + ThermalStatus status; + status.code = ThermalStatusCode::SUCCESS; + hidl_vec<CoolingDevice> coolingDevices; + + if (!mModule || !mModule->getCoolingDevices) { + ALOGI("getCoolingDevices is not implemented in Thermal HAL."); + _hidl_cb(status, coolingDevices); + return Void(); + } + + ssize_t size = mModule->getCoolingDevices(mModule, nullptr, 0); + if (size >= 0) { + std::vector<cooling_device_t> list; + list.resize(size); + size = mModule->getCoolingDevices(mModule, list.data(), list.size()); + if (size >= 0) { + list.resize(size); + coolingDevices.resize(list.size()); + for (size_t i = 0; i < list.size(); ++i) { + switch (list[i].type) { + case FAN_RPM: + coolingDevices[i].type = CoolingType::FAN_RPM; + break; + default: + ALOGE("Unknown cooling device %s type", list[i].name); + } + coolingDevices[i].name = list[i].name; + coolingDevices[i].currentValue = list[i].current_value; + } + } + } + if (size < 0) { + status.code = ThermalStatusCode::FAILURE; + status.debugMessage = strerror(-size); + } + _hidl_cb(status, coolingDevices); + return Void(); +} + +IThermal* HIDL_FETCH_IThermal(const char* /* name */) { + thermal_module_t* module; + status_t err = hw_get_module(THERMAL_HARDWARE_MODULE_ID, + const_cast<hw_module_t const**>( + reinterpret_cast<hw_module_t**>(&module))); + if (err || !module) { + ALOGE("Couldn't load %s module (%s)", THERMAL_HARDWARE_MODULE_ID, + strerror(-err)); + } + + if (err == 0 && module->common.methods->open) { + struct hw_device_t* device; + err = module->common.methods->open(&module->common, + THERMAL_HARDWARE_MODULE_ID, &device); + if (err) { + ALOGE("Couldn't open %s module (%s)", THERMAL_HARDWARE_MODULE_ID, + strerror(-err)); + } else { + return new Thermal(reinterpret_cast<thermal_module_t*>(device)); + } + } + return new Thermal(module); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace thermal +} // namespace hardware +} // namespace android
diff --git a/thermal/1.0/default/Thermal.h b/thermal/1.0/default/Thermal.h new file mode 100644 index 0000000..2e06289 --- /dev/null +++ b/thermal/1.0/default/Thermal.h
@@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_THERMAL_V1_0_THERMAL_H +#define ANDROID_HARDWARE_THERMAL_V1_0_THERMAL_H + +#include <android/hardware/thermal/1.0/IThermal.h> +#include <hidl/Status.h> +#include <hardware/thermal.h> + +#include <hidl/MQDescriptor.h> + +namespace android { +namespace hardware { +namespace thermal { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::thermal::V1_0::CoolingDevice; +using ::android::hardware::thermal::V1_0::CpuUsage; +using ::android::hardware::thermal::V1_0::IThermal; +using ::android::hardware::thermal::V1_0::Temperature; +using ::android::hardware::thermal::V1_0::ThermalStatus; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Thermal : public IThermal { + Thermal(thermal_module_t* module); + // Methods from ::android::hardware::thermal::V1_0::IThermal follow. + Return<void> getTemperatures(getTemperatures_cb _hidl_cb) override; + Return<void> getCpuUsages(getCpuUsages_cb _hidl_cb) override; + Return<void> getCoolingDevices(getCoolingDevices_cb _hidl_cb) override; + private: + thermal_module_t* mModule; +}; + +extern "C" IThermal* HIDL_FETCH_IThermal(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace thermal +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_THERMAL_V1_0_THERMAL_H
diff --git a/thermal/1.0/default/android.hardware.thermal@1.0-service.rc b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc new file mode 100644 index 0000000..f8da101 --- /dev/null +++ b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
@@ -0,0 +1,4 @@ +service thermal-hal-1-0 /vendor/bin/hw/android.hardware.thermal@1.0-service + class hal + user system + group system readproc
diff --git a/thermal/1.0/default/service.cpp b/thermal/1.0/default/service.cpp new file mode 100644 index 0000000..b83cbf8 --- /dev/null +++ b/thermal/1.0/default/service.cpp
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.thermal@1.0-service" + +#include <android/hardware/thermal/1.0/IThermal.h> +#include <hidl/LegacySupport.h> + +using android::hardware::thermal::V1_0::IThermal; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IThermal>(); +}
diff --git a/thermal/1.0/types.hal b/thermal/1.0/types.hal new file mode 100644 index 0000000..eb5d7c7 --- /dev/null +++ b/thermal/1.0/types.hal
@@ -0,0 +1,136 @@ +/* + * Copyright (C) 2016 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.thermal@1.0; + +/** Device temperature types */ +@export +enum TemperatureType : int32_t { + UNKNOWN = -1, + CPU = 0, + GPU = 1, + BATTERY = 2, + SKIN = 3, +}; + +enum CoolingType : uint32_t { + /** Fan cooling device speed in RPM. */ + FAN_RPM = 0, +}; + +struct Temperature { + /** + * This temperature's type. + */ + TemperatureType type; + + /** + * Name of this temperature. + * All temperatures of the same "type" must have a different "name", + * e.g., cpu0, battery. + */ + string name; + + /** + * Current temperature in Celsius. If not available set by HAL to NAN. + * Current temperature can be in any units if type=UNKNOWN. + */ + float currentValue; + + /** + * Throttling temperature constant for this temperature. + * If not available, set by HAL to NAN. + */ + float throttlingThreshold; + + /** + * Shutdown temperature constant for this temperature. + * If not available, set by HAL to NAN. + */ + float shutdownThreshold; + + /** + * Threshold temperature above which the VR mode clockrate minimums cannot + * be maintained for this device. + * If not available, set by HAL to NAN. + */ + float vrThrottlingThreshold; + +}; + +struct CoolingDevice { + /** + * This cooling device type. + */ + CoolingType type; + + /** + * Name of this cooling device. + * All cooling devices of the same "type" must have a different "name". + */ + string name; + + /** + * Current cooling device value. Units depend on cooling device "type". + */ + float currentValue; + +}; + +struct CpuUsage { + /** + * Name of this CPU. + * All CPUs must have a different "name". + */ + string name; + + /** + * Active time since the last boot in ms. + */ + uint64_t active; + + /** + * Total time since the last boot in ms. + */ + uint64_t total; + + /** + * Is set to true when a core is online. + * If the core is offline, all other members except |name| should be ignored. + */ + bool isOnline; + +}; + +enum ThermalStatusCode : uint32_t { + /** No errors. */ + SUCCESS = 0, + /** Unknown failure occured. */ + FAILURE = 1 +}; + +/** + * Generic structure to return the status of any thermal operation. + */ +struct ThermalStatus { + ThermalStatusCode code; + + /** + * A specific error message to provide more information. + * This can be used for debugging purposes only. + */ + string debugMessage; +};
diff --git a/thermal/1.0/vts/Android.mk b/thermal/1.0/vts/Android.mk new file mode 100644 index 0000000..60cc723 --- /dev/null +++ b/thermal/1.0/vts/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/thermal/1.0/vts/functional/Android.bp b/thermal/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..9046882 --- /dev/null +++ b/thermal/1.0/vts/functional/Android.bp
@@ -0,0 +1,37 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalThermalV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalThermalV1_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.thermal@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +} +
diff --git a/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp new file mode 100644 index 0000000..3989c94 --- /dev/null +++ b/thermal/1.0/vts/functional/VtsHalThermalV1_0TargetTest.cpp
@@ -0,0 +1,213 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <algorithm> +#include <cmath> +#include <string> +#include <vector> + +#define LOG_TAG "thermal_hidl_hal_test" + +#include <android-base/logging.h> +#include <android/hardware/thermal/1.0/IThermal.h> +#include <android/hardware/thermal/1.0/types.h> +#include <VtsHalHidlTargetTestBase.h> +#include <unistd.h> + +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::thermal::V1_0::CoolingDevice; +using ::android::hardware::thermal::V1_0::CpuUsage; +using ::android::hardware::thermal::V1_0::IThermal; +using ::android::hardware::thermal::V1_0::Temperature; +using ::android::hardware::thermal::V1_0::TemperatureType; +using ::android::hardware::thermal::V1_0::ThermalStatus; +using ::android::hardware::thermal::V1_0::ThermalStatusCode; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +#define MONITORING_OPERATION_NUMBER 10 + +#define MAX_DEVICE_TEMPERATURE 200 +#define MAX_FAN_SPEED 20000 + +// The main test class for THERMAL HIDL HAL. +class ThermalHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + thermal_ = ::testing::VtsHalHidlTargetTestBase::getService<IThermal>(); + ASSERT_NE(thermal_, nullptr); + baseSize_ = 0; + names_.clear(); + } + + virtual void TearDown() override {} + + protected: + // Check validity of temperatures returned by Thremal HAL. + void checkTemperatures(const hidl_vec<Temperature> temperatures) { + size_t size = temperatures.size(); + EXPECT_LE(baseSize_, size); + + for (size_t i = 0; i < size; ++i) { + checkDeviceTemperature(temperatures[i]); + if (i < baseSize_) { + EXPECT_EQ(names_[i], temperatures[i].name.c_str()); + } else { + // Names must be unique. + EXPECT_EQ(names_.end(), std::find(names_.begin(), names_.end(), + temperatures[i].name.c_str())); + names_.push_back(temperatures[i].name); + } + } + baseSize_ = size; + } + + // Check validity of CPU usages returned by Thermal HAL. + void checkCpuUsages(const hidl_vec<CpuUsage>& cpuUsages) { + size_t size = cpuUsages.size(); + // A number of CPU's does not change. + if (baseSize_ != 0) EXPECT_EQ(baseSize_, size); + + for (size_t i = 0; i < size; ++i) { + checkCpuUsage(cpuUsages[i]); + if (i < baseSize_) { + EXPECT_EQ(names_[i], cpuUsages[i].name.c_str()); + } else { + // Names must be unique. + EXPECT_EQ(names_.end(), std::find(names_.begin(), names_.end(), + cpuUsages[i].name.c_str())); + names_.push_back(cpuUsages[i].name); + } + } + baseSize_ = size; + } + + // Check validity of cooling devices information returned by Thermal HAL. + void checkCoolingDevices(const hidl_vec<CoolingDevice> coolingDevices) { + size_t size = coolingDevices.size(); + EXPECT_LE(baseSize_, size); + + for (size_t i = 0; i < size; ++i) { + checkCoolingDevice(coolingDevices[i]); + if (i < baseSize_) { + EXPECT_EQ(names_[i], coolingDevices[i].name.c_str()); + } else { + // Names must be unique. + EXPECT_EQ(names_.end(), std::find(names_.begin(), names_.end(), + coolingDevices[i].name.c_str())); + names_.push_back(coolingDevices[i].name); + } + } + baseSize_ = size; + } + + sp<IThermal> thermal_; + + private: + // Check validity of temperature returned by Thermal HAL. + void checkDeviceTemperature(const Temperature& temperature) { + // .currentValue of known type is in Celsius and must be reasonable. + EXPECT_TRUE(temperature.type == TemperatureType::UNKNOWN || + std::abs(temperature.currentValue) < MAX_DEVICE_TEMPERATURE || + isnan(temperature.currentValue)); + + // .name must not be empty. + EXPECT_LT(0u, temperature.name.size()); + + // .currentValue must not exceed .shutdwonThreshold if defined. + EXPECT_TRUE(temperature.currentValue < temperature.shutdownThreshold || + isnan(temperature.currentValue) || isnan(temperature.shutdownThreshold)); + + // .throttlingThreshold must not exceed .shutdownThreshold if defined. + EXPECT_TRUE(temperature.throttlingThreshold < temperature.shutdownThreshold || + isnan(temperature.throttlingThreshold) || isnan(temperature.shutdownThreshold)); + } + + // Check validity of CPU usage returned by Thermal HAL. + void checkCpuUsage(const CpuUsage& cpuUsage) { + // .active must be less than .total if CPU is online. + EXPECT_TRUE(!cpuUsage.isOnline || + (cpuUsage.active >= 0 && cpuUsage.total >= 0 && + cpuUsage.total >= cpuUsage.active)); + + // .name must be not empty. + EXPECT_LT(0u, cpuUsage.name.size()); + } + + // Check validity of a cooling device information returned by Thermal HAL. + void checkCoolingDevice(const CoolingDevice& coolingDevice) { + EXPECT_LE(0, coolingDevice.currentValue); + EXPECT_GT(MAX_FAN_SPEED, coolingDevice.currentValue); + EXPECT_LT(0u, coolingDevice.name.size()); + } + + size_t baseSize_; + std::vector<hidl_string> names_; +}; + +// Sanity test for Thermal::getTemperatures(). +TEST_F(ThermalHidlTest, TemperatureTest) { + hidl_vec<Temperature> passed; + for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) { + thermal_->getTemperatures( + [&passed](ThermalStatus status, hidl_vec<Temperature> temperatures) { + EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); + passed = temperatures; + }); + + checkTemperatures(passed); + sleep(1); + } +} + +// Sanity test for Thermal::getCpuUsages(). +TEST_F(ThermalHidlTest, CpuUsageTest) { + hidl_vec<CpuUsage> passed; + for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) { + thermal_->getCpuUsages( + [&passed](ThermalStatus status, hidl_vec<CpuUsage> cpuUsages) { + EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); + passed = cpuUsages; + }); + + checkCpuUsages(passed); + sleep(1); + } +} + +// Sanity test for Thermal::getCoolingDevices(). +TEST_F(ThermalHidlTest, CoolingDeviceTest) { + hidl_vec<CoolingDevice> passed; + for (size_t i = 0; i < MONITORING_OPERATION_NUMBER; ++i) { + thermal_->getCoolingDevices([&passed]( + ThermalStatus status, hidl_vec<CoolingDevice> coolingDevices) { + EXPECT_EQ(ThermalStatusCode::SUCCESS, status.code); + passed = coolingDevices; + }); + + checkCoolingDevices(passed); + sleep(1); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +}
diff --git a/thermal/Android.bp b/thermal/Android.bp new file mode 100644 index 0000000..ed19a37 --- /dev/null +++ b/thermal/Android.bp
@@ -0,0 +1,6 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/default", + "1.0/vts/functional", +]
diff --git a/tv/Android.bp b/tv/Android.bp new file mode 100644 index 0000000..ac54910 --- /dev/null +++ b/tv/Android.bp
@@ -0,0 +1,6 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "cec/1.0", + "input/1.0", + "input/1.0/vts/functional", +]
diff --git a/tv/cec/1.0/Android.bp b/tv/cec/1.0/Android.bp new file mode 100644 index 0000000..5c6919d --- /dev/null +++ b/tv/cec/1.0/Android.bp
@@ -0,0 +1,69 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.tv.cec@1.0_hal", + srcs: [ + "types.hal", + "IHdmiCec.hal", + "IHdmiCecCallback.hal", + ], +} + +genrule { + name: "android.hardware.tv.cec@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.cec@1.0", + srcs: [ + ":android.hardware.tv.cec@1.0_hal", + ], + out: [ + "android/hardware/tv/cec/1.0/types.cpp", + "android/hardware/tv/cec/1.0/HdmiCecAll.cpp", + "android/hardware/tv/cec/1.0/HdmiCecCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.tv.cec@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.cec@1.0", + srcs: [ + ":android.hardware.tv.cec@1.0_hal", + ], + out: [ + "android/hardware/tv/cec/1.0/types.h", + "android/hardware/tv/cec/1.0/IHdmiCec.h", + "android/hardware/tv/cec/1.0/IHwHdmiCec.h", + "android/hardware/tv/cec/1.0/BnHwHdmiCec.h", + "android/hardware/tv/cec/1.0/BpHwHdmiCec.h", + "android/hardware/tv/cec/1.0/BsHdmiCec.h", + "android/hardware/tv/cec/1.0/IHdmiCecCallback.h", + "android/hardware/tv/cec/1.0/IHwHdmiCecCallback.h", + "android/hardware/tv/cec/1.0/BnHwHdmiCecCallback.h", + "android/hardware/tv/cec/1.0/BpHwHdmiCecCallback.h", + "android/hardware/tv/cec/1.0/BsHdmiCecCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.tv.cec@1.0", + generated_sources: ["android.hardware.tv.cec@1.0_genc++"], + generated_headers: ["android.hardware.tv.cec@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.tv.cec@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/tv/cec/1.0/Android.mk b/tv/cec/1.0/Android.mk new file mode 100644 index 0000000..b08099e --- /dev/null +++ b/tv/cec/1.0/Android.mk
@@ -0,0 +1,582 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.tv.cec@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (AbortReason) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/AbortReason.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.AbortReason + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CecDeviceType) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecDeviceType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.CecDeviceType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CecLogicalAddress) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecLogicalAddress.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.CecLogicalAddress + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CecMessage) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecMessage.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.CecMessage + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CecMessageType) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecMessageType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.CecMessageType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HdmiPortInfo) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HdmiPortInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.HdmiPortInfo + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HdmiPortType) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HdmiPortType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.HdmiPortType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HotplugEvent) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HotplugEvent.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.HotplugEvent + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MaxLength) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/MaxLength.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.MaxLength + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (OptionKey) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/OptionKey.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.OptionKey + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Result) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/Result.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.Result + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SendMessageResult) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/SendMessageResult.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.SendMessageResult + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IHdmiCec.hal +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/IHdmiCec.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHdmiCec.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IHdmiCecCallback.hal +$(GEN): $(LOCAL_PATH)/IHdmiCecCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::IHdmiCec + +$(GEN): $(LOCAL_PATH)/IHdmiCec.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IHdmiCecCallback.hal +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/IHdmiCecCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHdmiCecCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::IHdmiCecCallback + +$(GEN): $(LOCAL_PATH)/IHdmiCecCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.tv.cec@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (AbortReason) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/AbortReason.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.AbortReason + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CecDeviceType) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecDeviceType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.CecDeviceType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CecLogicalAddress) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecLogicalAddress.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.CecLogicalAddress + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CecMessage) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecMessage.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.CecMessage + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (CecMessageType) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/CecMessageType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.CecMessageType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HdmiPortInfo) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HdmiPortInfo.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.HdmiPortInfo + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HdmiPortType) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HdmiPortType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.HdmiPortType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (HotplugEvent) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/HotplugEvent.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.HotplugEvent + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (MaxLength) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/MaxLength.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.MaxLength + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (OptionKey) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/OptionKey.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.OptionKey + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Result) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/Result.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.Result + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (SendMessageResult) +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/SendMessageResult.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::types.SendMessageResult + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IHdmiCec.hal +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/IHdmiCec.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHdmiCec.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IHdmiCecCallback.hal +$(GEN): $(LOCAL_PATH)/IHdmiCecCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::IHdmiCec + +$(GEN): $(LOCAL_PATH)/IHdmiCec.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IHdmiCecCallback.hal +# +GEN := $(intermediates)/android/hardware/tv/cec/V1_0/IHdmiCecCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IHdmiCecCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.tv.cec@1.0::IHdmiCecCallback + +$(GEN): $(LOCAL_PATH)/IHdmiCecCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tv/cec/1.0/IHdmiCec.hal b/tv/cec/1.0/IHdmiCec.hal new file mode 100644 index 0000000..e8db265 --- /dev/null +++ b/tv/cec/1.0/IHdmiCec.hal
@@ -0,0 +1,166 @@ +/* + * Copyright (C) 2016 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.tv.cec@1.0; + +import IHdmiCecCallback; + +/* + * HDMI-CEC HAL interface definition. + */ +interface IHdmiCec { + /* + * Passes the logical address that must be used in this system. + * + * HAL must use it to configure the hardware so that the CEC commands + * addressed the given logical address can be filtered in. This method must + * be able to be called as many times as necessary in order to support + * multiple logical devices. + * + * @param addr Logical address that must be used in this system. It must be + * in the range of valid logical addresses for the call to succeed. + * @return result Result status of the operation. SUCCESS if successful, + * FAILURE_INVALID_ARGS if the given logical address is invalid, + * FAILURE_BUSY if device or resource is busy + */ + @callflow(next={"*"}) + addLogicalAddress(CecLogicalAddress addr) generates (Result result); + + /* + * Clears all the logical addresses. + * + * It is used when the system doesn't need to process CEC command any more, + * hence to tell HAL to stop receiving commands from the CEC bus, and change + * the state back to the beginning. + */ + @callflow(next="addLogicalAddress") + @exit + clearLogicalAddress(); + + /* + * Gets the CEC physical address. + * + * The physical address depends on the topology of the network formed by + * connected HDMI devices. It is therefore likely to change if the cable is + * plugged off and on again. It is advised to call getPhysicalAddress to get + * the updated address when hot plug event takes place. + * + * @return result Result status of the operation. SUCCESS if successful, + * FAILURE_INVALID_STATE if HAL cannot retrieve the physical + * address. + * @return addr Physical address of this device. + */ + @callflow(next="*") + getPhysicalAddress() generates (Result result, uint16_t addr); + + /* + * Transmits HDMI-CEC message to other HDMI device. + * + * The method must be designed to return in a certain amount of time and not + * hanging forever which may happen if CEC signal line is pulled low for + * some reason. + * + * It must try retransmission at least once as specified in the section '7.1 + * Frame Re-transmissions' of the CEC Spec 1.4b. + * + * @param message CEC message to be sent to other HDMI device. + * @return result Result status of the operation. SUCCESS if successful, + * NACK if the sent message is not acknowledged, + * BUSY if the CEC bus is busy. + */ + @callflow(next="*") + sendMessage(CecMessage message) generates (SendMessageResult result); + + /* + * Sets a callback that HDMI-CEC HAL must later use for incoming CEC + * messages or internal HDMI events. + * + * @param callback Callback object to pass hdmi events to the system. The + * previously registered callback must be replaced with this one. + */ + @callflow(next={"addLogicalAddress"}) + @entry + setCallback(IHdmiCecCallback callback); + + /* + * Returns the CEC version supported by underlying hardware. + * + * @return version the CEC version supported by underlying hardware. + */ + @callflow(next={"*"}) + getCecVersion() generates (int32_t version); + + /* + * Gets the identifier of the vendor. + * + * @return vendorId Identifier of the vendor that is the 24-bit unique + * company ID obtained from the IEEE Registration Authority + * Committee (RAC). The upper 8 bits must be 0. + */ + @callflow(next={"*"}) + getVendorId() generates (uint32_t vendorId); + + /* + * Gets the hdmi port information of underlying hardware. + * + * @return infos The list of HDMI port information + */ + @callflow(next={"*"}) + getPortInfo() generates (vec<HdmiPortInfo> infos); + + /* + * Sets flags controlling the way HDMI-CEC service works down to HAL + * implementation. Those flags must be used in case the feature needs update + * in HAL itself, firmware or microcontroller. + * + * @param key The key of the option to be updated with a new value. + * @param value Value to be set. + */ + @callflow(next="*") + setOption(OptionKey key, bool value); + + /* + * Passes the updated language information of Android system. Contains + * three-letter code as defined in ISO/FDIS 639-2. Must be used for HAL to + * respond to <Get Menu Language> while in standby mode. + * + * @param language Three-letter code defined in ISO/FDIS 639-2. Must be + * lowercase letters. (e.g., eng for English) + */ + @callflow(next="*") + setLanguage(string language); + + /* + * Configures ARC circuit in the hardware logic to start or stop the + * feature. + * + * @param portId Port id to be configured. + * @param enable Flag must be either true to start the feature or false to + * stop it. + */ + @callflow(next="*") + enableAudioReturnChannel(int32_t portId, bool enable); + + /* + * Gets the connection status of the specified port. + * + * @param portId Port id to be inspected for the connection status. + * @return status True if a device is connected, otherwise false. The HAL + * must watch for +5V power signal to determine the status. + */ + @callflow(next="*") + isConnected(int32_t portId) generates (bool status); +};
diff --git a/tv/cec/1.0/IHdmiCecCallback.hal b/tv/cec/1.0/IHdmiCecCallback.hal new file mode 100644 index 0000000..4a9d28f --- /dev/null +++ b/tv/cec/1.0/IHdmiCecCallback.hal
@@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 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.tv.cec@1.0; + +interface IHdmiCecCallback { + /* + * The callback function that must be called by HAL implementation to notify + * the system of new CEC message arrival. + */ + oneway onCecMessage(CecMessage message); + + /* + * The callback function that must be called by HAL implementation to notify + * the system of new hotplug event. + */ + oneway onHotplugEvent(HotplugEvent event); +};
diff --git a/tv/cec/1.0/default/Android.mk b/tv/cec/1.0/default/Android.mk new file mode 100644 index 0000000..9d37344 --- /dev/null +++ b/tv/cec/1.0/default/Android.mk
@@ -0,0 +1,44 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.tv.cec@1.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + HdmiCec.cpp + +LOCAL_SHARED_LIBRARIES := \ + libhidlbase \ + libhidltransport \ + liblog \ + libbase \ + libutils \ + libhardware \ + android.hardware.tv.cec@1.0 \ + +include $(BUILD_SHARED_LIBRARY) + + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.tv.cec@1.0-service +LOCAL_INIT_RC := android.hardware.tv.cec@1.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + +LOCAL_SHARED_LIBRARIES += \ + libhidlbase \ + libhidltransport \ + android.hardware.tv.cec@1.0 \ + +include $(BUILD_EXECUTABLE)
diff --git a/tv/cec/1.0/default/HdmiCec.cpp b/tv/cec/1.0/default/HdmiCec.cpp new file mode 100644 index 0000000..ebe2681 --- /dev/null +++ b/tv/cec/1.0/default/HdmiCec.cpp
@@ -0,0 +1,415 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.tv.cec@1.0-impl" +#include <android-base/logging.h> + +#include <hardware/hardware.h> +#include <hardware/hdmi_cec.h> +#include "HdmiCec.h" + +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V1_0 { +namespace implementation { + +static_assert(CEC_DEVICE_INACTIVE == static_cast<int>(CecDeviceType::INACTIVE), + "CecDeviceType::INACTIVE must match legacy value."); +static_assert(CEC_DEVICE_TV == static_cast<int>(CecDeviceType::TV), + "CecDeviceType::TV must match legacy value."); +static_assert(CEC_DEVICE_RECORDER == static_cast<int>(CecDeviceType::RECORDER), + "CecDeviceType::RECORDER must match legacy value."); +static_assert(CEC_DEVICE_TUNER == static_cast<int>(CecDeviceType::TUNER), + "CecDeviceType::TUNER must match legacy value."); +static_assert(CEC_DEVICE_PLAYBACK == static_cast<int>(CecDeviceType::PLAYBACK), + "CecDeviceType::PLAYBACK must match legacy value."); +static_assert(CEC_DEVICE_AUDIO_SYSTEM == static_cast<int>(CecDeviceType::AUDIO_SYSTEM), + "CecDeviceType::AUDIO_SYSTEM must match legacy value."); +static_assert(CEC_DEVICE_MAX == static_cast<int>(CecDeviceType::MAX), + "CecDeviceType::MAX must match legacy value."); + +static_assert(CEC_ADDR_TV == static_cast<int>(CecLogicalAddress::TV), + "CecLogicalAddress::TV must match legacy value."); +static_assert(CEC_ADDR_RECORDER_1 == static_cast<int>(CecLogicalAddress::RECORDER_1), + "CecLogicalAddress::RECORDER_1 must match legacy value."); +static_assert(CEC_ADDR_RECORDER_2 == static_cast<int>(CecLogicalAddress::RECORDER_2), + "CecLogicalAddress::RECORDER_2 must match legacy value."); +static_assert(CEC_ADDR_TUNER_1 == static_cast<int>(CecLogicalAddress::TUNER_1), + "CecLogicalAddress::TUNER_1 must match legacy value."); +static_assert(CEC_ADDR_PLAYBACK_1 == static_cast<int>(CecLogicalAddress::PLAYBACK_1), + "CecLogicalAddress::PLAYBACK_1 must match legacy value."); +static_assert(CEC_ADDR_AUDIO_SYSTEM == static_cast<int>(CecLogicalAddress::AUDIO_SYSTEM), + "CecLogicalAddress::AUDIO_SYSTEM must match legacy value."); +static_assert(CEC_ADDR_TUNER_2 == static_cast<int>(CecLogicalAddress::TUNER_2), + "CecLogicalAddress::TUNER_2 must match legacy value."); +static_assert(CEC_ADDR_TUNER_3 == static_cast<int>(CecLogicalAddress::TUNER_3), + "CecLogicalAddress::TUNER_3 must match legacy value."); +static_assert(CEC_ADDR_PLAYBACK_2 == static_cast<int>(CecLogicalAddress::PLAYBACK_2), + "CecLogicalAddress::PLAYBACK_2 must match legacy value."); +static_assert(CEC_ADDR_RECORDER_3 == static_cast<int>(CecLogicalAddress::RECORDER_3), + "CecLogicalAddress::RECORDER_3 must match legacy value."); +static_assert(CEC_ADDR_TUNER_4 == static_cast<int>(CecLogicalAddress::TUNER_4), + "CecLogicalAddress::TUNER_4 must match legacy value."); +static_assert(CEC_ADDR_PLAYBACK_3 == static_cast<int>(CecLogicalAddress::PLAYBACK_3), + "CecLogicalAddress::PLAYBACK_3 must match legacy value."); +static_assert(CEC_ADDR_FREE_USE == static_cast<int>(CecLogicalAddress::FREE_USE), + "CecLogicalAddress::FREE_USE must match legacy value."); +static_assert(CEC_ADDR_UNREGISTERED == static_cast<int>(CecLogicalAddress::UNREGISTERED), + "CecLogicalAddress::UNREGISTERED must match legacy value."); +static_assert(CEC_ADDR_BROADCAST == static_cast<int>(CecLogicalAddress::BROADCAST), + "CecLogicalAddress::BROADCAST must match legacy value."); + +static_assert(CEC_MESSAGE_FEATURE_ABORT == static_cast<int>(CecMessageType::FEATURE_ABORT), + "CecMessageType::FEATURE_ABORT must match legacy value."); +static_assert(CEC_MESSAGE_IMAGE_VIEW_ON == static_cast<int>(CecMessageType::IMAGE_VIEW_ON), + "CecMessageType::IMAGE_VIEW_ON must match legacy value."); +static_assert(CEC_MESSAGE_TUNER_STEP_INCREMENT == static_cast<int>( + CecMessageType::TUNER_STEP_INCREMENT), + "CecMessageType::TUNER_STEP_INCREMENT must match legacy value."); +static_assert(CEC_MESSAGE_TUNER_STEP_DECREMENT == static_cast<int>( + CecMessageType::TUNER_STEP_DECREMENT), + "CecMessageType::TUNER_STEP_DECREMENT must match legacy value."); +static_assert(CEC_MESSAGE_TUNER_DEVICE_STATUS == static_cast<int>( + CecMessageType::TUNER_DEVICE_STATUS), + "CecMessageType::TUNER_DEVICE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_TUNER_DEVICE_STATUS == static_cast<int>( + CecMessageType::GIVE_TUNER_DEVICE_STATUS), + "CecMessageType::GIVE_TUNER_DEVICE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_ON == static_cast<int>(CecMessageType::RECORD_ON), + "CecMessageType::RECORD_ON must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_STATUS == static_cast<int>(CecMessageType::RECORD_STATUS), + "CecMessageType::RECORD_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_OFF == static_cast<int>(CecMessageType::RECORD_OFF), + "CecMessageType::RECORD_OFF must match legacy value."); +static_assert(CEC_MESSAGE_TEXT_VIEW_ON == static_cast<int>(CecMessageType::TEXT_VIEW_ON), + "CecMessageType::TEXT_VIEW_ON must match legacy value."); +static_assert(CEC_MESSAGE_RECORD_TV_SCREEN == static_cast<int>(CecMessageType::RECORD_TV_SCREEN), + "CecMessageType::RECORD_TV_SCREEN must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_DECK_STATUS == static_cast<int>(CecMessageType::GIVE_DECK_STATUS), + "CecMessageType::GIVE_DECK_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_STANDBY == static_cast<int>(CecMessageType::STANDBY), + "CecMessageType::STANDBY must match legacy value."); +static_assert(CEC_MESSAGE_PLAY == static_cast<int>(CecMessageType::PLAY), + "CecMessageType::PLAY must match legacy value."); +static_assert(CEC_MESSAGE_DECK_CONTROL == static_cast<int>(CecMessageType::DECK_CONTROL), + "CecMessageType::DECK_CONTROL must match legacy value."); +static_assert(CEC_MESSAGE_TIMER_CLEARED_STATUS == static_cast<int>( + CecMessageType::TIMER_CLEARED_STATUS), + "CecMessageType::TIMER_CLEARED_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_USER_CONTROL_PRESSED == static_cast<int>( + CecMessageType::USER_CONTROL_PRESSED), + "CecMessageType::USER_CONTROL_PRESSED must match legacy value."); +static_assert(CEC_MESSAGE_USER_CONTROL_RELEASED == static_cast<int>( + CecMessageType::USER_CONTROL_RELEASED), + "CecMessageType::USER_CONTROL_RELEASED must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_OSD_NAME == static_cast<int>(CecMessageType::GIVE_OSD_NAME), + "CecMessageType::GIVE_OSD_NAME must match legacy value."); +static_assert(CEC_MESSAGE_SET_OSD_NAME == static_cast<int>(CecMessageType::SET_OSD_NAME), + "CecMessageType::SET_OSD_NAME must match legacy value."); +static_assert(CEC_MESSAGE_SYSTEM_AUDIO_MODE_REQUEST == static_cast<int>( + CecMessageType::SYSTEM_AUDIO_MODE_REQUEST), + "CecMessageType::SYSTEM_AUDIO_MODE_REQUEST must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_AUDIO_STATUS == static_cast<int>(CecMessageType::GIVE_AUDIO_STATUS), + "CecMessageType::GIVE_AUDIO_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_SET_SYSTEM_AUDIO_MODE == static_cast<int>( + CecMessageType::SET_SYSTEM_AUDIO_MODE), + "CecMessageType::SET_SYSTEM_AUDIO_MODE must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_AUDIO_STATUS == static_cast<int>( + CecMessageType::REPORT_AUDIO_STATUS), + "CecMessageType::REPORT_AUDIO_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS == static_cast<int>( + CecMessageType::GIVE_SYSTEM_AUDIO_MODE_STATUS), + "CecMessageType::GIVE_SYSTEM_AUDIO_MODE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_SYSTEM_AUDIO_MODE_STATUS == static_cast<int>( + CecMessageType::SYSTEM_AUDIO_MODE_STATUS), + "CecMessageType::SYSTEM_AUDIO_MODE_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_ROUTING_CHANGE == static_cast<int>(CecMessageType::ROUTING_CHANGE), + "CecMessageType::ROUTING_CHANGE must match legacy value."); +static_assert(CEC_MESSAGE_ROUTING_INFORMATION == static_cast<int>( + CecMessageType::ROUTING_INFORMATION), + "CecMessageType::ROUTING_INFORMATION must match legacy value."); +static_assert(CEC_MESSAGE_ACTIVE_SOURCE == static_cast<int>(CecMessageType::ACTIVE_SOURCE), + "CecMessageType::ACTIVE_SOURCE must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS == static_cast<int>( + CecMessageType::GIVE_PHYSICAL_ADDRESS), + "CecMessageType::GIVE_PHYSICAL_ADDRESS must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS == static_cast<int>( + CecMessageType::REPORT_PHYSICAL_ADDRESS), + "CecMessageType::REPORT_PHYSICAL_ADDRESS must match legacy value."); +static_assert(CEC_MESSAGE_REQUEST_ACTIVE_SOURCE == static_cast<int>( + CecMessageType::REQUEST_ACTIVE_SOURCE), + "CecMessageType::REQUEST_ACTIVE_SOURCE must match legacy value."); +static_assert(CEC_MESSAGE_SET_STREAM_PATH == static_cast<int>(CecMessageType::SET_STREAM_PATH), + "CecMessageType::SET_STREAM_PATH must match legacy value."); +static_assert(CEC_MESSAGE_DEVICE_VENDOR_ID == static_cast<int>(CecMessageType::DEVICE_VENDOR_ID), + "CecMessageType::DEVICE_VENDOR_ID must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_COMMAND == static_cast<int>(CecMessageType::VENDOR_COMMAND), + "CecMessageType::VENDOR_COMMAND must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_REMOTE_BUTTON_DOWN == static_cast<int>( + CecMessageType::VENDOR_REMOTE_BUTTON_DOWN), + "CecMessageType::VENDOR_REMOTE_BUTTON_DOWN must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_REMOTE_BUTTON_UP == static_cast<int>( + CecMessageType::VENDOR_REMOTE_BUTTON_UP), + "CecMessageType::VENDOR_REMOTE_BUTTON_UP must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID == static_cast<int>( + CecMessageType::GIVE_DEVICE_VENDOR_ID), + "CecMessageType::GIVE_DEVICE_VENDOR_ID must match legacy value."); +static_assert(CEC_MESSAGE_MENU_REQUEST == static_cast<int>(CecMessageType::MENU_REQUEST), + "CecMessageType::MENU_REQUEST must match legacy value."); +static_assert(CEC_MESSAGE_MENU_STATUS == static_cast<int>(CecMessageType::MENU_STATUS), + "CecMessageType::MENU_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GIVE_DEVICE_POWER_STATUS == static_cast<int>( + CecMessageType::GIVE_DEVICE_POWER_STATUS), + "CecMessageType::GIVE_DEVICE_POWER_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_POWER_STATUS == static_cast<int>( + CecMessageType::REPORT_POWER_STATUS), + "CecMessageType::REPORT_POWER_STATUS must match legacy value."); +static_assert(CEC_MESSAGE_GET_MENU_LANGUAGE == static_cast<int>(CecMessageType::GET_MENU_LANGUAGE), + "CecMessageType::GET_MENU_LANGUAGE must match legacy value."); +static_assert(CEC_MESSAGE_SELECT_ANALOG_SERVICE == static_cast<int>( + CecMessageType::SELECT_ANALOG_SERVICE), + "CecMessageType::SELECT_ANALOG_SERVICE must match legacy value."); +static_assert(CEC_MESSAGE_SELECT_DIGITAL_SERVICE == static_cast<int>( + CecMessageType::SELECT_DIGITAL_SERVICE), + "CecMessageType::SELECT_DIGITAL_SERVICE must match legacy value."); +static_assert(CEC_MESSAGE_SET_DIGITAL_TIMER == static_cast<int>(CecMessageType::SET_DIGITAL_TIMER), + "CecMessageType::SET_DIGITAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_CLEAR_DIGITAL_TIMER == static_cast<int>( + CecMessageType::CLEAR_DIGITAL_TIMER), + "CecMessageType::CLEAR_DIGITAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_SET_AUDIO_RATE == static_cast<int>(CecMessageType::SET_AUDIO_RATE), + "CecMessageType::SET_AUDIO_RATE must match legacy value."); +static_assert(CEC_MESSAGE_INACTIVE_SOURCE == static_cast<int>(CecMessageType::INACTIVE_SOURCE), + "CecMessageType::INACTIVE_SOURCE must match legacy value."); +static_assert(CEC_MESSAGE_CEC_VERSION == static_cast<int>(CecMessageType::CEC_VERSION), + "CecMessageType::CEC_VERSION must match legacy value."); +static_assert(CEC_MESSAGE_GET_CEC_VERSION == static_cast<int>(CecMessageType::GET_CEC_VERSION), + "CecMessageType::GET_CEC_VERSION must match legacy value."); +static_assert(CEC_MESSAGE_VENDOR_COMMAND_WITH_ID == static_cast<int>( + CecMessageType::VENDOR_COMMAND_WITH_ID), + "CecMessageType::VENDOR_COMMAND_WITH_ID must match legacy value."); +static_assert(CEC_MESSAGE_CLEAR_EXTERNAL_TIMER == static_cast<int>( + CecMessageType::CLEAR_EXTERNAL_TIMER), + "CecMessageType::CLEAR_EXTERNAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_SET_EXTERNAL_TIMER == static_cast<int>( + CecMessageType::SET_EXTERNAL_TIMER), + "CecMessageType::SET_EXTERNAL_TIMER must match legacy value."); +static_assert(CEC_MESSAGE_INITIATE_ARC == static_cast<int>(CecMessageType::INITIATE_ARC), + "CecMessageType::INITIATE_ARC must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_ARC_INITIATED == static_cast<int>( + CecMessageType::REPORT_ARC_INITIATED), + "CecMessageType::REPORT_ARC_INITIATED must match legacy value."); +static_assert(CEC_MESSAGE_REPORT_ARC_TERMINATED == static_cast<int>( + CecMessageType::REPORT_ARC_TERMINATED), + "CecMessageType::REPORT_ARC_TERMINATED must match legacy value."); +static_assert(CEC_MESSAGE_REQUEST_ARC_INITIATION == static_cast<int>( + CecMessageType::REQUEST_ARC_INITIATION), + "CecMessageType::REQUEST_ARC_INITIATION must match legacy value."); +static_assert(CEC_MESSAGE_REQUEST_ARC_TERMINATION == static_cast<int>( + CecMessageType::REQUEST_ARC_TERMINATION), + "CecMessageType::REQUEST_ARC_TERMINATION must match legacy value."); +static_assert(CEC_MESSAGE_TERMINATE_ARC == static_cast<int>(CecMessageType::TERMINATE_ARC), + "CecMessageType::TERMINATE_ARC must match legacy value."); +static_assert(CEC_MESSAGE_ABORT == static_cast<int>(CecMessageType::ABORT), + "CecMessageType::ABORT must match legacy value."); + +static_assert(ABORT_UNRECOGNIZED_MODE == static_cast<int>(AbortReason::UNRECOGNIZED_MODE), + "AbortReason::UNRECOGNIZED_MODE must match legacy value."); +static_assert(ABORT_NOT_IN_CORRECT_MODE == static_cast<int>(AbortReason::NOT_IN_CORRECT_MODE), + "AbortReason::NOT_IN_CORRECT_MODE must match legacy value."); +static_assert(ABORT_CANNOT_PROVIDE_SOURCE == static_cast<int>(AbortReason::CANNOT_PROVIDE_SOURCE), + "AbortReason::CANNOT_PROVIDE_SOURCE must match legacy value."); +static_assert(ABORT_INVALID_OPERAND == static_cast<int>(AbortReason::INVALID_OPERAND), + "AbortReason::INVALID_OPERAND must match legacy value."); +static_assert(ABORT_REFUSED == static_cast<int>(AbortReason::REFUSED), + "AbortReason::REFUSED must match legacy value."); +static_assert(ABORT_UNABLE_TO_DETERMINE == static_cast<int>(AbortReason::UNABLE_TO_DETERMINE), + "AbortReason::UNABLE_TO_DETERMINE must match legacy value."); + +static_assert(HDMI_RESULT_SUCCESS == static_cast<int>(SendMessageResult::SUCCESS), + "SendMessageResult::SUCCESS must match legacy value."); +static_assert(HDMI_RESULT_NACK == static_cast<int>(SendMessageResult::NACK), + "SendMessageResult::NACK must match legacy value."); +static_assert(HDMI_RESULT_BUSY == static_cast<int>(SendMessageResult::BUSY), + "SendMessageResult::BUSY must match legacy value."); +static_assert(HDMI_RESULT_FAIL == static_cast<int>(SendMessageResult::FAIL), + "SendMessageResult::FAIL must match legacy value."); + +static_assert(HDMI_INPUT == static_cast<int>(HdmiPortType::INPUT), + "HdmiPortType::INPUT must match legacy value."); +static_assert(HDMI_OUTPUT == static_cast<int>(HdmiPortType::OUTPUT), + "HdmiPortType::OUTPUT must match legacy value."); + +static_assert(HDMI_OPTION_WAKEUP == static_cast<int>(OptionKey::WAKEUP), + "OptionKey::WAKEUP must match legacy value."); +static_assert(HDMI_OPTION_ENABLE_CEC == static_cast<int>(OptionKey::ENABLE_CEC), + "OptionKey::ENABLE_CEC must match legacy value."); +static_assert(HDMI_OPTION_SYSTEM_CEC_CONTROL == static_cast<int>(OptionKey::SYSTEM_CEC_CONTROL), + "OptionKey::SYSTEM_CEC_CONTROL must match legacy value."); + +sp<IHdmiCecCallback> HdmiCec::mCallback = nullptr; + +HdmiCec::HdmiCec(hdmi_cec_device_t* device) : mDevice(device) { +} + +// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow. +Return<Result> HdmiCec::addLogicalAddress(CecLogicalAddress addr) { + int ret = mDevice->add_logical_address(mDevice, static_cast<cec_logical_address_t>(addr)); + switch (ret) { + case 0: + return Result::SUCCESS; + case -EINVAL: + return Result::FAILURE_INVALID_ARGS; + case -ENOTSUP: + return Result::FAILURE_NOT_SUPPORTED; + case -EBUSY: + return Result::FAILURE_BUSY; + default: + return Result::FAILURE_UNKNOWN; + } +} + +Return<void> HdmiCec::clearLogicalAddress() { + mDevice->clear_logical_address(mDevice); + return Void(); +} + +Return<void> HdmiCec::getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) { + uint16_t addr; + int ret = mDevice->get_physical_address(mDevice, &addr); + switch (ret) { + case 0: + _hidl_cb(Result::SUCCESS, addr); + break; + case -EBADF: + _hidl_cb(Result::FAILURE_INVALID_STATE, addr); + break; + default: + _hidl_cb(Result::FAILURE_UNKNOWN, addr); + break; + } + return Void(); +} + +Return<SendMessageResult> HdmiCec::sendMessage(const CecMessage& message) { + cec_message_t legacyMessage { + .initiator = static_cast<cec_logical_address_t>(message.initiator), + .destination = static_cast<cec_logical_address_t>(message.destination), + .length = message.body.size(), + }; + for (size_t i = 0; i < message.body.size(); ++i) { + legacyMessage.body[i] = static_cast<unsigned char>(message.body[i]); + } + return static_cast<SendMessageResult>(mDevice->send_message(mDevice, &legacyMessage)); +} + +Return<void> HdmiCec::setCallback(const sp<IHdmiCecCallback>& callback) { + mCallback = callback; + mDevice->register_event_callback(mDevice, eventCallback, nullptr); + return Void(); +} + +Return<int32_t> HdmiCec::getCecVersion() { + int version; + mDevice->get_version(mDevice, &version); + return static_cast<int32_t>(version); +} + +Return<uint32_t> HdmiCec::getVendorId() { + uint32_t vendor_id; + mDevice->get_vendor_id(mDevice, &vendor_id); + return vendor_id; +} + +Return<void> HdmiCec::getPortInfo(getPortInfo_cb _hidl_cb) { + struct hdmi_port_info* legacyPorts; + int numPorts; + hidl_vec<HdmiPortInfo> portInfos; + mDevice->get_port_info(mDevice, &legacyPorts, &numPorts); + portInfos.resize(numPorts); + for (int i = 0; i < numPorts; ++i) { + portInfos[i] = { + .type = static_cast<HdmiPortType>(legacyPorts[i].type), + .portId = static_cast<uint32_t>(legacyPorts[i].port_id), + .cecSupported = legacyPorts[i].cec_supported != 0, + .arcSupported = legacyPorts[i].arc_supported != 0, + .physicalAddress = legacyPorts[i].physical_address + }; + } + _hidl_cb(portInfos); + return Void(); +} + +Return<void> HdmiCec::setOption(OptionKey key, bool value) { + mDevice->set_option(mDevice, static_cast<int>(key), value ? 1 : 0); + return Void(); +} + +Return<void> HdmiCec::setLanguage(const hidl_string& language) { + if (language.size() != 3) { + LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size() + << "."; + return Void(); + } + const char *languageStr = language.c_str(); + int convertedLanguage = ((languageStr[0] & 0xFF) << 16) + | ((languageStr[1] & 0xFF) << 8) + | (languageStr[2] & 0xFF); + mDevice->set_option(mDevice, HDMI_OPTION_SET_LANG, convertedLanguage); + return Void(); +} + +Return<void> HdmiCec::enableAudioReturnChannel(int32_t portId, bool enable) { + mDevice->set_audio_return_channel(mDevice, portId, enable ? 1 : 0); + return Void(); +} + +Return<bool> HdmiCec::isConnected(int32_t portId) { + return mDevice->is_connected(mDevice, portId) > 0; +} + + +IHdmiCec* HIDL_FETCH_IHdmiCec(const char* hal) { + hdmi_cec_device_t* hdmi_cec_device; + int ret = 0; + const hw_module_t* hw_module = nullptr; + + ret = hw_get_module (HDMI_CEC_HARDWARE_MODULE_ID, &hw_module); + if (ret == 0) { + ret = hdmi_cec_open (hw_module, &hdmi_cec_device); + if (ret != 0) { + LOG(ERROR) << "hdmi_cec_open " << hal << " failed: " << ret; + } + } else { + LOG(ERROR) << "hw_get_module " << hal << " failed: " << ret; + } + + if (ret == 0) { + return new HdmiCec(hdmi_cec_device); + } else { + LOG(ERROR) << "Passthrough failed to load legacy HAL."; + return nullptr; + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android
diff --git a/tv/cec/1.0/default/HdmiCec.h b/tv/cec/1.0/default/HdmiCec.h new file mode 100644 index 0000000..34a3bb0 --- /dev/null +++ b/tv/cec/1.0/default/HdmiCec.h
@@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 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. + */ + +#ifndef ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H +#define ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H + +#include <algorithm> + +#include <android/hardware/tv/cec/1.0/IHdmiCec.h> +#include <hidl/Status.h> +#include <hardware/hardware.h> +#include <hardware/hdmi_cec.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace tv { +namespace cec { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::tv::cec::V1_0::CecLogicalAddress; +using ::android::hardware::tv::cec::V1_0::CecMessage; +using ::android::hardware::tv::cec::V1_0::MaxLength; +using ::android::hardware::tv::cec::V1_0::HdmiPortInfo; +using ::android::hardware::tv::cec::V1_0::IHdmiCec; +using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback; +using ::android::hardware::tv::cec::V1_0::OptionKey; +using ::android::hardware::tv::cec::V1_0::Result; +using ::android::hardware::tv::cec::V1_0::SendMessageResult; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct HdmiCec : public IHdmiCec { + HdmiCec(hdmi_cec_device_t* device); + // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow. + Return<Result> addLogicalAddress(CecLogicalAddress addr) override; + Return<void> clearLogicalAddress() override; + Return<void> getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) override; + Return<SendMessageResult> sendMessage(const CecMessage& message) override; + Return<void> setCallback(const sp<IHdmiCecCallback>& callback) override; + Return<int32_t> getCecVersion() override; + Return<uint32_t> getVendorId() override; + Return<void> getPortInfo(getPortInfo_cb _hidl_cb) override; + Return<void> setOption(OptionKey key, bool value) override; + Return<void> setLanguage(const hidl_string& language) override; + Return<void> enableAudioReturnChannel(int32_t portId, bool enable) override; + Return<bool> isConnected(int32_t portId) override; + + static void eventCallback(const hdmi_event_t* event, void* /* arg */) { + if (mCallback != nullptr && event != nullptr) { + if (event->type == HDMI_EVENT_CEC_MESSAGE) { + size_t length = std::min(event->cec.length, + static_cast<size_t>(MaxLength::MESSAGE_BODY)); + CecMessage cecMessage { + .initiator = static_cast<CecLogicalAddress>(event->cec.initiator), + .destination = static_cast<CecLogicalAddress>(event->cec.destination), + }; + cecMessage.body.resize(length); + for (size_t i = 0; i < length; ++i) { + cecMessage.body[i] = static_cast<uint8_t>(event->cec.body[i]); + } + mCallback->onCecMessage(cecMessage); + } else if (event->type == HDMI_EVENT_HOT_PLUG) { + HotplugEvent hotplugEvent { + .connected = event->hotplug.connected > 0, + .portId = static_cast<uint32_t>(event->hotplug.port_id) + }; + mCallback->onHotplugEvent(hotplugEvent); + } + } + } + +private: + static sp<IHdmiCecCallback> mCallback; + const hdmi_cec_device_t* mDevice; +}; + +extern "C" IHdmiCec* HIDL_FETCH_IHdmiCec(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace cec +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_CEC_V1_0_HDMICEC_H
diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc new file mode 100644 index 0000000..9c80094 --- /dev/null +++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
@@ -0,0 +1,4 @@ +service cec-hal-1-0 /vendor/bin/hw/android.hardware.tv.cec@1.0-service + class hal + user system + group system
diff --git a/tv/cec/1.0/default/service.cpp b/tv/cec/1.0/default/service.cpp new file mode 100644 index 0000000..74b1f62 --- /dev/null +++ b/tv/cec/1.0/default/service.cpp
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.tv.cec@1.0-service" + +#include <android/hardware/tv/cec/1.0/IHdmiCec.h> +#include <hidl/LegacySupport.h> + +using android::hardware::tv::cec::V1_0::IHdmiCec; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IHdmiCec>(); +}
diff --git a/tv/cec/1.0/types.hal b/tv/cec/1.0/types.hal new file mode 100644 index 0000000..ec2e373 --- /dev/null +++ b/tv/cec/1.0/types.hal
@@ -0,0 +1,222 @@ +/* + * Copyright (C) 2016 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.tv.cec@1.0; + +enum MaxLength : int32_t { + MESSAGE_BODY = 15, +}; + +enum CecDeviceType : int32_t { + INACTIVE = -1, + TV = 0, + RECORDER = 1, + TUNER = 3, + PLAYBACK = 4, + AUDIO_SYSTEM = 5, + MAX = AUDIO_SYSTEM, +}; + +enum CecLogicalAddress : int32_t { + TV = 0, + RECORDER_1 = 1, + RECORDER_2 = 2, + TUNER_1 = 3, + PLAYBACK_1 = 4, + AUDIO_SYSTEM = 5, + TUNER_2 = 6, + TUNER_3 = 7, + PLAYBACK_2 = 8, + RECORDER_3 = 9, + TUNER_4 = 10, + PLAYBACK_3 = 11, + FREE_USE = 14, + UNREGISTERED = 15, // as Initiator address + BROADCAST = 15, // as Destination address +}; + +/* + * HDMI CEC message types. The assigned values represent opcode used in CEC + * frame as specified in CEC Table 8-26 of the CEC Spec 1.4b. + */ +enum CecMessageType : int32_t { + FEATURE_ABORT = 0x00, + IMAGE_VIEW_ON = 0x04, + TUNER_STEP_INCREMENT = 0x05, + TUNER_STEP_DECREMENT = 0x06, + TUNER_DEVICE_STATUS = 0x07, + GIVE_TUNER_DEVICE_STATUS = 0x08, + RECORD_ON = 0x09, + RECORD_STATUS = 0x0A, + RECORD_OFF = 0x0B, + TEXT_VIEW_ON = 0x0D, + RECORD_TV_SCREEN = 0x0F, + GIVE_DECK_STATUS = 0x1A, + DECK_STATUS = 0x1B, + SET_MENU_LANGUAGE = 0x32, + CLEAR_ANALOG_TIMER = 0x33, + SET_ANALOG_TIMER = 0x34, + TIMER_STATUS = 0x35, + STANDBY = 0x36, + PLAY = 0x41, + DECK_CONTROL = 0x42, + TIMER_CLEARED_STATUS = 0x43, + USER_CONTROL_PRESSED = 0x44, + USER_CONTROL_RELEASED = 0x45, + GIVE_OSD_NAME = 0x46, + SET_OSD_NAME = 0x47, + SET_OSD_STRING = 0x64, + SET_TIMER_PROGRAM_TITLE = 0x67, + SYSTEM_AUDIO_MODE_REQUEST = 0x70, + GIVE_AUDIO_STATUS = 0x71, + SET_SYSTEM_AUDIO_MODE = 0x72, + REPORT_AUDIO_STATUS = 0x7A, + GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D, + SYSTEM_AUDIO_MODE_STATUS = 0x7E, + ROUTING_CHANGE = 0x80, + ROUTING_INFORMATION = 0x81, + ACTIVE_SOURCE = 0x82, + GIVE_PHYSICAL_ADDRESS = 0x83, + REPORT_PHYSICAL_ADDRESS = 0x84, + REQUEST_ACTIVE_SOURCE = 0x85, + SET_STREAM_PATH = 0x86, + DEVICE_VENDOR_ID = 0x87, + VENDOR_COMMAND = 0x89, + VENDOR_REMOTE_BUTTON_DOWN = 0x8A, + VENDOR_REMOTE_BUTTON_UP = 0x8B, + GIVE_DEVICE_VENDOR_ID = 0x8C, + MENU_REQUEST = 0x8D, + MENU_STATUS = 0x8E, + GIVE_DEVICE_POWER_STATUS = 0x8F, + REPORT_POWER_STATUS = 0x90, + GET_MENU_LANGUAGE = 0x91, + SELECT_ANALOG_SERVICE = 0x92, + SELECT_DIGITAL_SERVICE = 0x93, + SET_DIGITAL_TIMER = 0x97, + CLEAR_DIGITAL_TIMER = 0x99, + SET_AUDIO_RATE = 0x9A, + INACTIVE_SOURCE = 0x9D, + CEC_VERSION = 0x9E, + GET_CEC_VERSION = 0x9F, + VENDOR_COMMAND_WITH_ID = 0xA0, + CLEAR_EXTERNAL_TIMER = 0xA1, + SET_EXTERNAL_TIMER = 0xA2, + INITIATE_ARC = 0xC0, + REPORT_ARC_INITIATED = 0xC1, + REPORT_ARC_TERMINATED = 0xC2, + REQUEST_ARC_INITIATION = 0xC3, + REQUEST_ARC_TERMINATION = 0xC4, + TERMINATE_ARC = 0xC5, + ABORT = 0xFF, +}; + +/* + * Operand description [Abort Reason] + */ +enum AbortReason : int32_t { + UNRECOGNIZED_MODE = 0, + NOT_IN_CORRECT_MODE = 1, + CANNOT_PROVIDE_SOURCE = 2, + INVALID_OPERAND = 3, + REFUSED = 4, + UNABLE_TO_DETERMINE = 5, +}; + +enum Result : int32_t { + SUCCESS = 0, + FAILURE_UNKNOWN = 1, + FAILURE_INVALID_ARGS = 2, + FAILURE_INVALID_STATE = 3, + FAILURE_NOT_SUPPORTED = 4, + FAILURE_BUSY = 5, +}; + +/* + * error code used for send_message. + */ +enum SendMessageResult : int32_t { + SUCCESS = 0, + NACK = 1, // not acknowledged + BUSY = 2, // bus is busy + FAIL = 3, +}; + +/* + * HDMI port type. + */ +enum HdmiPortType : int32_t { + INPUT = 0, + OUTPUT = 1, +}; + +/* + * Options used for IHdmiCec.setOption() + */ +enum OptionKey : int32_t { + /* When set to false, HAL does not wake up the system upon receiving <Image + * View On> or <Text View On>. Used when user changes the TV settings to + * disable the auto TV on functionality. + * True by default. + */ + WAKEUP = 1, + + /* When set to false, all the CEC commands are discarded. Used when user + * changes the TV settings to disable CEC functionality. + * True by default. + */ + ENABLE_CEC = 2, + + /* Setting this flag to false means Android system must stop handling CEC + * service and yield the control over to the microprocessor that is powered + * on through the standby mode. When set to true, the system must gain the + * control over, hence telling the microprocessor to stop handling the CEC + * commands. For example, this may be called when system goes in and out of + * standby mode to notify the microprocessor that it should start/stop + * handling CEC commands on behalf of the system. + * False by default. + */ + SYSTEM_CEC_CONTROL = 3, + + /* Option 4 not used */ +}; + +struct CecMessage { + /* logical address of sender */ + CecLogicalAddress initiator; + + /* logical address of receiver */ + CecLogicalAddress destination; + + /* The maximum size of body is 15 (MaxLength::MESSAGE_BODY) as specified in + * the section 6 of the CEC Spec 1.4b. Overflowed data must be ignored. */ + vec<uint8_t> body; +}; + +struct HotplugEvent { + bool connected; + uint32_t portId; +}; + +/* + * HDMI port descriptor + */ +struct HdmiPortInfo { + HdmiPortType type; + uint32_t portId; // Should start from 1 which corresponds to HDMI "port 1". + bool cecSupported; + bool arcSupported; + uint16_t physicalAddress; +};
diff --git a/tv/cec/Android.mk b/tv/cec/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tv/cec/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/tv/input/1.0/Android.bp b/tv/input/1.0/Android.bp new file mode 100644 index 0000000..ae5e3de --- /dev/null +++ b/tv/input/1.0/Android.bp
@@ -0,0 +1,71 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.tv.input@1.0_hal", + srcs: [ + "types.hal", + "ITvInput.hal", + "ITvInputCallback.hal", + ], +} + +genrule { + name: "android.hardware.tv.input@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.input@1.0", + srcs: [ + ":android.hardware.tv.input@1.0_hal", + ], + out: [ + "android/hardware/tv/input/1.0/types.cpp", + "android/hardware/tv/input/1.0/TvInputAll.cpp", + "android/hardware/tv/input/1.0/TvInputCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.tv.input@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.input@1.0", + srcs: [ + ":android.hardware.tv.input@1.0_hal", + ], + out: [ + "android/hardware/tv/input/1.0/types.h", + "android/hardware/tv/input/1.0/ITvInput.h", + "android/hardware/tv/input/1.0/IHwTvInput.h", + "android/hardware/tv/input/1.0/BnHwTvInput.h", + "android/hardware/tv/input/1.0/BpHwTvInput.h", + "android/hardware/tv/input/1.0/BsTvInput.h", + "android/hardware/tv/input/1.0/ITvInputCallback.h", + "android/hardware/tv/input/1.0/IHwTvInputCallback.h", + "android/hardware/tv/input/1.0/BnHwTvInputCallback.h", + "android/hardware/tv/input/1.0/BpHwTvInputCallback.h", + "android/hardware/tv/input/1.0/BsTvInputCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.tv.input@1.0", + generated_sources: ["android.hardware.tv.input@1.0_genc++"], + generated_headers: ["android.hardware.tv.input@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.tv.input@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hardware.audio.common@2.0", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hardware.audio.common@2.0", + "android.hidl.base@1.0", + ], +}
diff --git a/tv/input/1.0/Android.mk b/tv/input/1.0/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tv/input/1.0/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/tv/input/1.0/ITvInput.hal b/tv/input/1.0/ITvInput.hal new file mode 100644 index 0000000..43de276 --- /dev/null +++ b/tv/input/1.0/ITvInput.hal
@@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 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.tv.input@1.0; + +import ITvInputCallback; + +interface ITvInput { + /* + * Sets a callback for events. + * + * Note that initially no device is available in the client side, so the + * implementation must notify all the currently available devices including + * static devices via callback once callback is set. + * + * @param callback Callback object to pass events. + */ + @entry + @exit + @callflow(next={"getStreamConfigurations"}) + setCallback(ITvInputCallback callback); + + /* + * Gets stream configurations for a specific device. + * + * The configs object is valid only until the next + * STREAM_CONFIGURATIONS_CHANGED event. + * + * @param deviceId Device ID for the configurations. + * @return result OK upon success. Otherwise, + * INVALID_ARGUMENTS if the given device ID is not valid. + * @return configurations An array of available configurations. + */ + @callflow(next={"openStream", "getStreamConfigurations", "closeStream"}) + getStreamConfigurations(int32_t deviceId) + generates (Result result, vec<TvStreamConfig> configurations); + + /* + * Opens a specific stream in a device. + * + * @param deviceId Device ID for the steam to open. + * @param streamId Steam ID for the steam to open. Must be one of the + * stream IDs returned from getStreamConfigurations(). + * @return result OK upon success. Otherwise, + * INVALID_ARGUMENTS if any of given IDs are not valid; + * INVALID_STATE if the stream with the given ID is already open; + * NO_RESOURCE if the client must close other streams to open the + * stream. + * @return sidebandStream handle for sideband stream. + */ + @callflow(next={"closeStream", "getStreamConfigurations", "openStream"}) + openStream(int32_t deviceId, int32_t streamId) + generates (Result result, handle sidebandStream); + + /* + * Closes a specific stream in a device. + * + * @param deviceId Device ID for the steam to open. + * @param streamId Steam ID for the steam to open. + * @return result OK upon success. Otherwise, + * INVALID_ARGUMENTS if any of given IDs are not valid; + * INVALID_STATE if the stream with the given ID is not open. + */ + @callflow(next={"getStreamConfigurations", "openStream", "closeStream"}) + closeStream(int32_t deviceId, int32_t streamId) generates (Result result); +};
diff --git a/tv/input/1.0/ITvInputCallback.hal b/tv/input/1.0/ITvInputCallback.hal new file mode 100644 index 0000000..f2f07a0 --- /dev/null +++ b/tv/input/1.0/ITvInputCallback.hal
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 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.tv.input@1.0; + +interface ITvInputCallback { + /* + * Notifies the client that an event has occured. For possible event types, + * check TvInputEventType. + * + * @param event Event passed to the client. + */ + notify(TvInputEvent event); +};
diff --git a/tv/input/1.0/default/Android.mk b/tv/input/1.0/default/Android.mk new file mode 100644 index 0000000..210da86 --- /dev/null +++ b/tv/input/1.0/default/Android.mk
@@ -0,0 +1,46 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.tv.input@1.0-impl +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + TvInput.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + liblog \ + libhardware \ + libhidlbase \ + libhidltransport \ + libutils \ + android.hardware.audio.common@2.0 \ + android.hardware.tv.input@1.0 \ + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.tv.input@1.0-service +LOCAL_INIT_RC := android.hardware.tv.input@1.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libbase \ + libutils \ + libhardware_legacy \ + libhardware \ + +LOCAL_SHARED_LIBRARIES += \ + libhidlbase \ + libhidltransport \ + android.hardware.audio.common@2.0 \ + android.hardware.tv.input@1.0 \ + +include $(BUILD_EXECUTABLE) +
diff --git a/tv/input/1.0/default/TvInput.cpp b/tv/input/1.0/default/TvInput.cpp new file mode 100644 index 0000000..0bc6401 --- /dev/null +++ b/tv/input/1.0/default/TvInput.cpp
@@ -0,0 +1,230 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.tv.input@1.0-service" +#include <android-base/logging.h> + +#include "TvInput.h" + +const native_handle_t kNullNativeHandle{sizeof(native_handle_t), 0, 0, {}}; + +namespace android { +namespace hardware { +namespace tv { +namespace input { +namespace V1_0 { +namespace implementation { + +static_assert(TV_INPUT_TYPE_OTHER_HARDWARE == static_cast<int>(TvInputType::OTHER), + "TvInputType::OTHER must match legacy value."); +static_assert(TV_INPUT_TYPE_TUNER == static_cast<int>(TvInputType::TUNER), + "TvInputType::TUNER must match legacy value."); +static_assert(TV_INPUT_TYPE_COMPOSITE == static_cast<int>(TvInputType::COMPOSITE), + "TvInputType::COMPOSITE must match legacy value."); +static_assert(TV_INPUT_TYPE_SVIDEO == static_cast<int>(TvInputType::SVIDEO), + "TvInputType::SVIDEO must match legacy value."); +static_assert(TV_INPUT_TYPE_SCART == static_cast<int>(TvInputType::SCART), + "TvInputType::SCART must match legacy value."); +static_assert(TV_INPUT_TYPE_COMPONENT == static_cast<int>(TvInputType::COMPONENT), + "TvInputType::COMPONENT must match legacy value."); +static_assert(TV_INPUT_TYPE_VGA == static_cast<int>(TvInputType::VGA), + "TvInputType::VGA must match legacy value."); +static_assert(TV_INPUT_TYPE_DVI == static_cast<int>(TvInputType::DVI), + "TvInputType::DVI must match legacy value."); +static_assert(TV_INPUT_TYPE_HDMI == static_cast<int>(TvInputType::HDMI), + "TvInputType::HDMI must match legacy value."); +static_assert(TV_INPUT_TYPE_DISPLAY_PORT == static_cast<int>(TvInputType::DISPLAY_PORT), + "TvInputType::DISPLAY_PORT must match legacy value."); + +static_assert(TV_INPUT_EVENT_DEVICE_AVAILABLE == static_cast<int>( + TvInputEventType::DEVICE_AVAILABLE), + "TvInputEventType::DEVICE_AVAILABLE must match legacy value."); +static_assert(TV_INPUT_EVENT_DEVICE_UNAVAILABLE == static_cast<int>( + TvInputEventType::DEVICE_UNAVAILABLE), + "TvInputEventType::DEVICE_UNAVAILABLE must match legacy value."); +static_assert(TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED == static_cast<int>( + TvInputEventType::STREAM_CONFIGURATIONS_CHANGED), + "TvInputEventType::STREAM_CONFIGURATIONS_CHANGED must match legacy value."); + +sp<ITvInputCallback> TvInput::mCallback = nullptr; + +TvInput::TvInput(tv_input_device_t* device) : mDevice(device) { + mCallbackOps.notify = &TvInput::notify; +} + +TvInput::~TvInput() { + if (mDevice != nullptr) { + free(mDevice); + } +} + +// Methods from ::android::hardware::tv_input::V1_0::ITvInput follow. +Return<void> TvInput::setCallback(const sp<ITvInputCallback>& callback) { + mCallback = callback; + if (mCallback != nullptr) { + mDevice->initialize(mDevice, &mCallbackOps, nullptr); + } + return Void(); +} + +Return<void> TvInput::getStreamConfigurations(int32_t deviceId, getStreamConfigurations_cb cb) { + int32_t configCount = 0; + const tv_stream_config_t* configs = nullptr; + int ret = mDevice->get_stream_configurations(mDevice, deviceId, &configCount, &configs); + Result res = Result::UNKNOWN; + hidl_vec<TvStreamConfig> tvStreamConfigs; + if (ret == 0) { + res = Result::OK; + tvStreamConfigs.resize(getSupportedConfigCount(configCount, configs)); + int32_t pos = 0; + for (int32_t i = 0; i < configCount; ++i) { + if (isSupportedStreamType(configs[i].type)) { + tvStreamConfigs[pos].streamId = configs[i].stream_id; + tvStreamConfigs[pos].maxVideoWidth = configs[i].max_video_width; + tvStreamConfigs[pos].maxVideoHeight = configs[i].max_video_height; + ++pos; + } + } + } else if (ret == -EINVAL) { + res = Result::INVALID_ARGUMENTS; + } + cb(res, tvStreamConfigs); + return Void(); +} + +Return<void> TvInput::openStream(int32_t deviceId, int32_t streamId, openStream_cb cb) { + tv_stream_t stream; + stream.stream_id = streamId; + int ret = mDevice->open_stream(mDevice, deviceId, &stream); + Result res = Result::UNKNOWN; + native_handle_t* sidebandStream = nullptr; + if (ret == 0) { + if (isSupportedStreamType(stream.type)) { + res = Result::OK; + sidebandStream = stream.sideband_stream_source_handle; + } + } else { + // TODO(b/30814137) + sidebandStream = const_cast<native_handle_t*>(&kNullNativeHandle); + if (ret == -EBUSY) { + res = Result::NO_RESOURCE; + } else if (ret == -EEXIST) { + res = Result::INVALID_STATE; + } else if (ret == -EINVAL) { + res = Result::INVALID_ARGUMENTS; + } + } + cb(res, sidebandStream); + return Void(); +} + +Return<Result> TvInput::closeStream(int32_t deviceId, int32_t streamId) { + int ret = mDevice->close_stream(mDevice, deviceId, streamId); + Result res = Result::UNKNOWN; + if (ret == 0) { + res = Result::OK; + } else if (ret == -ENOENT) { + res = Result::INVALID_STATE; + } else if (ret == -EINVAL) { + res = Result::INVALID_ARGUMENTS; + } + return res; +} + +// static +void TvInput::notify(struct tv_input_device* __unused, tv_input_event_t* event, + void* __unused) { + if (mCallback != nullptr && event != nullptr) { + // Capturing is no longer supported. + if (event->type >= TV_INPUT_EVENT_CAPTURE_SUCCEEDED) { + return; + } + TvInputEvent tvInputEvent; + tvInputEvent.type = static_cast<TvInputEventType>(event->type); + tvInputEvent.deviceInfo.deviceId = event->device_info.device_id; + tvInputEvent.deviceInfo.type = static_cast<TvInputType>( + event->device_info.type); + tvInputEvent.deviceInfo.portId = event->device_info.hdmi.port_id; + tvInputEvent.deviceInfo.cableConnectionStatus = CableConnectionStatus::UNKNOWN; + // TODO: Ensure the legacy audio type code is the same once audio HAL default + // implementation is ready. + tvInputEvent.deviceInfo.audioType = static_cast<AudioDevice>( + event->device_info.audio_type); + memset(tvInputEvent.deviceInfo.audioAddress.data(), 0, + tvInputEvent.deviceInfo.audioAddress.size()); + const char* address = event->device_info.audio_address; + if (address != nullptr) { + size_t size = strlen(address); + if (size > tvInputEvent.deviceInfo.audioAddress.size()) { + LOG(ERROR) << "Audio address is too long. Address:" << address << ""; + return; + } + for (size_t i = 0; i < size; ++i) { + tvInputEvent.deviceInfo.audioAddress[i] = + static_cast<uint8_t>(event->device_info.audio_address[i]); + } + } + mCallback->notify(tvInputEvent); + } +} + +// static +uint32_t TvInput::getSupportedConfigCount(uint32_t configCount, + const tv_stream_config_t* configs) { + uint32_t supportedConfigCount = 0; + for (uint32_t i = 0; i < configCount; ++i) { + if (isSupportedStreamType(configs[i].type)) { + supportedConfigCount++; + } + } + return supportedConfigCount; +} + +// static +bool TvInput::isSupportedStreamType(int type) { + // Buffer producer type is no longer supported. + return type != TV_STREAM_TYPE_BUFFER_PRODUCER; +} + +ITvInput* HIDL_FETCH_ITvInput(const char* /* name */) { + int ret = 0; + const hw_module_t* hw_module = nullptr; + tv_input_device_t* input_device; + ret = hw_get_module(TV_INPUT_HARDWARE_MODULE_ID, &hw_module); + if (ret == 0 && hw_module->methods->open != nullptr) { + ret = hw_module->methods->open(hw_module, TV_INPUT_DEFAULT_DEVICE, + reinterpret_cast<hw_device_t**>(&input_device)); + if (ret == 0) { + return new TvInput(input_device); + } + else { + LOG(ERROR) << "Passthrough failed to load legacy HAL."; + return nullptr; + } + } + else { + LOG(ERROR) << "hw_get_module " << TV_INPUT_HARDWARE_MODULE_ID + << " failed: " << ret; + return nullptr; + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace input +} // namespace tv +} // namespace hardware +} // namespace android
diff --git a/tv/input/1.0/default/TvInput.h b/tv/input/1.0/default/TvInput.h new file mode 100644 index 0000000..beb69f5 --- /dev/null +++ b/tv/input/1.0/default/TvInput.h
@@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_TV_INPUT_V1_0_TVINPUT_H +#define ANDROID_HARDWARE_TV_INPUT_V1_0_TVINPUT_H + +#include <android/hardware/tv/input/1.0/ITvInput.h> +#include <hidl/Status.h> +#include <hardware/tv_input.h> + +#include <hidl/MQDescriptor.h> + +namespace android { +namespace hardware { +namespace tv { +namespace input { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::audio::common::V2_0::AudioDevice; +using ::android::hardware::tv::input::V1_0::ITvInput; +using ::android::hardware::tv::input::V1_0::ITvInputCallback; +using ::android::hardware::tv::input::V1_0::Result; +using ::android::hardware::tv::input::V1_0::TvInputEvent; +using ::android::hardware::tv::input::V1_0::TvStreamConfig; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct TvInput : public ITvInput { + TvInput(tv_input_device_t* device); + ~TvInput(); + Return<void> setCallback(const sp<ITvInputCallback>& callback) override; + Return<void> getStreamConfigurations(int32_t deviceId, + getStreamConfigurations_cb _hidl_cb) override; + Return<void> openStream(int32_t deviceId, int32_t streamId, + openStream_cb _hidl_cb) override; + Return<Result> closeStream(int32_t deviceId, int32_t streamId) override; + + static void notify(struct tv_input_device* __unused, tv_input_event_t* event, + void* __unused); + static uint32_t getSupportedConfigCount(uint32_t configCount, + const tv_stream_config_t* configs); + static bool isSupportedStreamType(int type); + + private: + static sp<ITvInputCallback> mCallback; + tv_input_callback_ops_t mCallbackOps; + tv_input_device_t* mDevice; +}; + +extern "C" ITvInput* HIDL_FETCH_ITvInput(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace input +} // namespace tv +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_TV_INPUT_V1_0_TVINPUT_H
diff --git a/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc new file mode 100644 index 0000000..9edeba6 --- /dev/null +++ b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
@@ -0,0 +1,4 @@ +service tv-input-1-0 /vendor/bin/hw/android.hardware.tv.input@1.0-service + class hal + user system + group system readproc
diff --git a/tv/input/1.0/default/service.cpp b/tv/input/1.0/default/service.cpp new file mode 100644 index 0000000..d904d0b --- /dev/null +++ b/tv/input/1.0/default/service.cpp
@@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "android.hardware.tv_input@1.0-service" + +#include <android/hardware/tv/input/1.0/ITvInput.h> + +#include <hidl/LegacySupport.h> + +using android::sp; + +// Generated HIDL files +using android::hardware::tv::input::V1_0::ITvInput; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<ITvInput>(); +}
diff --git a/tv/input/1.0/types.hal b/tv/input/1.0/types.hal new file mode 100644 index 0000000..55eb6ad --- /dev/null +++ b/tv/input/1.0/types.hal
@@ -0,0 +1,138 @@ +/* + * Copyright (C) 2016 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.tv.input@1.0; + +import android.hardware.audio.common@2.0; + +enum Result : int32_t { + OK, + UNKNOWN, + NO_RESOURCE, + INVALID_ARGUMENTS, + INVALID_STATE, +}; + +/* Type of physical TV input. */ +enum TvInputType : int32_t { + OTHER = 1, // Generic hardware. + TUNER = 2, // Tuner. e.g. built-in terrestrial tuner + COMPOSITE = 3, + SVIDEO = 4, + SCART = 5, + COMPONENT = 6, + VGA = 7, + DVI = 8, + HDMI = 9, // Physical HDMI port. e.g. HDMI 1 + DISPLAY_PORT = 10, +}; + +/* + * Status of cable connection. + * This status is for devices having availability to detect the cable in a mechanical way, + * regardless of whether the connected external device is electrically on or not. + * If the device does not have such capability, you must use UNKNOWN. + */ +enum CableConnectionStatus : int32_t { + UNKNOWN = 0, + CONNECTED = 1, + DISCONNECTED = 2, +}; + +struct TvInputDeviceInfo { + int32_t deviceId; + TvInputType type; + uint32_t portId; // HDMI port ID number. e.g. 2 for HDMI 2 + CableConnectionStatus cableConnectionStatus; // Cable connection status. + AudioDevice audioType; // Audio device type. e.g AudioDevice::IN_HDMI + uint8_t[32] audioAddress; // Audio device address. "" if N/A. If the text + // length is less than 32, the remaining part + // must be filled with 0s. +}; + +enum TvInputEventType : int32_t { + /* + * Hardware notifies the framework that a device is available. + * + * Note that DEVICE_AVAILABLE and DEVICE_UNAVAILABLE events do not represent + * hotplug events (i.e. plugging cable into or out of the physical port). + * These events notify the framework whether the port is available or not. + * For a concrete example, when a user plugs in or pulls out the HDMI cable + * from a HDMI port, it does not generate DEVICE_AVAILABLE and/or + * DEVICE_UNAVAILABLE events. However, if a user inserts a pluggable USB + * tuner into the Android device, it must generate a DEVICE_AVAILABLE event + * and when the port is removed, it must generate a DEVICE_UNAVAILABLE + * event. + * + * For hotplug events, please see STREAM_CONFIGURATION_CHANGED for more + * details. + * + * HAL implementation must register devices by using this event when the + * device boots up. The framework must recognize device reported via this + * event only. + */ + DEVICE_AVAILABLE = 1, + + /* + * Hardware notifies the framework that a device is unavailable. + * + * HAL implementation must generate this event when a device registered + * by DEVICE_AVAILABLE is no longer available. For example, + * the event can indicate that a USB tuner is plugged out from the Android + * device. + * + * Note that this event is not for indicating cable plugged out of the port; + * for that purpose, the implementation must use + * STREAM_CONFIGURATION_CHANGED event. This event represents the port itself + * being no longer available. + */ + DEVICE_UNAVAILABLE = 2, + + /* + * Stream configurations are changed. Client must regard all open streams + * at the specific device are closed, and must call + * getStreamConfigurations() again, opening some of them if necessary. + * + * HAL implementation must generate this event when the available stream + * configurations change for any reason. A typical use case of this event + * is to notify the framework that the input signal has changed resolution, + * or that the cable is plugged out so that the number of available streams + * is 0. + * + * The implementation must use this event to indicate hotplug status of the + * port. the framework regards input devices with no available streams as + * disconnected, so the implementation can generate this event with no + * available streams to indicate that this device is disconnected, and vice + * versa. + */ + STREAM_CONFIGURATIONS_CHANGED = 3, +}; + +struct TvInputEvent { + TvInputEventType type; + /* + * DEVICE_AVAILABLE: all fields are relevant. + * DEVICE_UNAVAILABLE: only deviceId is relevant. + * STREAM_CONFIGURATIONS_CHANGED: only deviceId is relevant. + */ + TvInputDeviceInfo deviceInfo; +}; + +struct TvStreamConfig { + int32_t streamId; + uint32_t maxVideoWidth; // Max width of the stream. + uint32_t maxVideoHeight; // Max height of the stream. +};
diff --git a/tv/input/1.0/vts/functional/Android.bp b/tv/input/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..c862429 --- /dev/null +++ b/tv/input/1.0/vts/functional/Android.bp
@@ -0,0 +1,37 @@ +// +// Copyright (C) 2017 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. +// + +cc_test { + name: "VtsHalTvInputV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalTvInputV1_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.tv.input@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ] +} +
diff --git a/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp new file mode 100644 index 0000000..0d5110e --- /dev/null +++ b/tv/input/1.0/vts/functional/VtsHalTvInputV1_0TargetTest.cpp
@@ -0,0 +1,363 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "tv_input_hidl_hal_test" +#include <android-base/logging.h> + +#include <android/hardware/tv/input/1.0/types.h> +#include <android/hardware/tv/input/1.0/ITvInput.h> +#include <android/hardware/tv/input/1.0/ITvInputCallback.h> + +#include <VtsHalHidlTargetTestBase.h> +#include <utils/KeyedVector.h> +#include <mutex> +#include <vector> + +using ::android::hardware::tv::input::V1_0::ITvInput; +using ::android::hardware::tv::input::V1_0::ITvInputCallback; +using ::android::hardware::tv::input::V1_0::Result; +using ::android::hardware::tv::input::V1_0::TvInputType; +using ::android::hardware::tv::input::V1_0::TvInputDeviceInfo; +using ::android::hardware::tv::input::V1_0::TvInputEventType; +using ::android::hardware::tv::input::V1_0::TvInputEvent; +using ::android::hardware::tv::input::V1_0::TvStreamConfig; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::sp; + +#define WAIT_FOR_EVENT_TIMEOUT 5 +#define DEFAULT_ID INT32_MIN + +/* The main test class for TV Input HIDL HAL. */ +class TvInputHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + tv_input_ = ::testing::VtsHalHidlTargetTestBase::getService<ITvInput>(); + ASSERT_NE(tv_input_, nullptr); + tv_input_callback_ = new TvInputCallback(*this); + ASSERT_NE(tv_input_callback_, nullptr); + tv_input_->setCallback(tv_input_callback_); + // All events received within the timeout should be handled. + sleep(WAIT_FOR_EVENT_TIMEOUT); + } + + virtual void TearDown() override {} + + /* Called when a DEVICE_AVAILABLE event is received. */ + void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) { + device_info_.add(deviceInfo.deviceId, deviceInfo); + } + + /* Called when a DEVICE_UNAVAILABLE event is received. */ + void onDeviceUnavailable(int32_t deviceId) { + device_info_.removeItem(deviceId); + } + + /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */ + Result onStreamConfigurationsChanged(int32_t deviceId) { + return updateStreamConfigurations(deviceId); + } + + /* Gets and updates the stream configurations for a device. */ + Result updateStreamConfigurations(int32_t deviceId) { + stream_config_.removeItem(deviceId); + Result result = Result::UNKNOWN; + hidl_vec<TvStreamConfig> list; + tv_input_->getStreamConfigurations(deviceId, + [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) { + result = res; + if (res == Result::OK) { + list = configs; + } + }); + if (result == Result::OK) { + stream_config_.add(deviceId, list); + } + return result; + } + + /* Gets and updates the stream configurations for all existing devices. */ + void updateAllStreamConfigurations() { + for (size_t i = 0; i < device_info_.size(); i++) { + int32_t device_id = device_info_.keyAt(i); + updateStreamConfigurations(device_id); + } + } + + /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */ + std::vector<size_t> getConfigIndices() { + std::vector<size_t> indices; + for (size_t i = 0; i < stream_config_.size(); i++) { + if (stream_config_.valueAt(i).size() != 0) { + indices.push_back(i); + } + } + return indices; + } + + /* + * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums). + * Otherwise, returns the smallest missing non-negative integer. + */ + int32_t getNumNotIn(std::vector<int32_t>& nums) { + int32_t result = DEFAULT_ID; + int32_t size = static_cast<int32_t>(nums.size()); + for (int32_t i = 0; i < size; i++) { + // Put every element to its target position, if possible. + int32_t target_pos = nums[i]; + while (target_pos >= 0 && target_pos < size && i != target_pos && nums[i] != nums[target_pos]) { + std::swap(nums[i], nums[target_pos]); + target_pos = nums[i]; + } + } + + for (int32_t i = 0; i < size; i++) { + if (nums[i] != i) { + return i; + } + } + return result; + } + + /* A simple test implementation of TvInputCallback for TV Input Events. */ + class TvInputCallback : public ITvInputCallback { + public: + TvInputCallback(TvInputHidlTest& parent) : parent_(parent){}; + + virtual ~TvInputCallback() = default; + + /* + * Notifies the client that an event has occured. For possible event types, + * check TvInputEventType. + */ + Return<void> notify(const TvInputEvent& event) override { + std::unique_lock<std::mutex> lock(parent_.mutex_); + switch(event.type) { + case TvInputEventType::DEVICE_AVAILABLE: + parent_.onDeviceAvailable(event.deviceInfo); + break; + case TvInputEventType::DEVICE_UNAVAILABLE: + parent_.onDeviceUnavailable(event.deviceInfo.deviceId); + break; + case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: + parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId); + break; + } + return Void(); + }; + private: + /* The test contains this callback instance. */ + TvInputHidlTest& parent_; + }; + + /* The TvInput used for the test. */ + sp<ITvInput> tv_input_; + + /* The TvInputCallback used for the test. */ + sp<ITvInputCallback> tv_input_callback_; + + /* + * A KeyedVector stores device information of every available device. + * A key is a device ID and the corresponding value is the TvInputDeviceInfo. + */ + android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_; + + /* + * A KeyedVector stores a list of stream configurations of every available device. + * A key is a device ID and the corresponding value is the stream configuration list. + */ + android::KeyedVector<int32_t, hidl_vec<TvStreamConfig>> stream_config_; + + /* The mutex controls the access of shared data. */ + std::mutex mutex_; +}; + + +/* A class for test environment setup. */ +class TvInputHidlEnvironment : public ::testing::Environment { + public: + virtual void SetUp() {} + virtual void TearDown() {} + + private: +}; + +/* + * GetStreamConfigTest: + * Calls updateStreamConfigurations() for each existing device + * Checks returned results + */ +TEST_F(TvInputHidlTest, GetStreamConfigTest) { + std::unique_lock<std::mutex> lock(mutex_); + for (size_t i = 0; i < device_info_.size(); i++) { + int32_t device_id = device_info_.keyAt(i); + Result result = updateStreamConfigurations(device_id); + EXPECT_EQ(Result::OK, result); + } +} + +/* + * OpenAndCloseStreamTest: + * Calls openStream() and then closeStream() for each existing stream + * Checks returned results + */ +TEST_F(TvInputHidlTest, OpenAndCloseStreamTest) { + std::unique_lock<std::mutex> lock(mutex_); + updateAllStreamConfigurations(); + for (size_t j = 0; j < stream_config_.size(); j++) { + int32_t device_id = stream_config_.keyAt(j); + hidl_vec<TvStreamConfig> config = stream_config_.valueAt(j); + for (size_t i = 0; i < config.size(); i++) { + Result result = Result::UNKNOWN; + int32_t stream_id = config[i].streamId; + tv_input_->openStream(device_id, stream_id, + [&result](Result res, const native_handle_t*) { + result = res; + }); + EXPECT_EQ(Result::OK, result); + + result = Result::UNKNOWN; + result = tv_input_->closeStream(device_id, stream_id); + EXPECT_EQ(Result::OK, result); + } + } +} + +/* + * InvalidDeviceIdTest: + * Calls updateStreamConfigurations(), openStream(), and closeStream() + * for a non-existing device + * Checks returned results + * The results should be Result::INVALID_ARGUMENTS + */ +TEST_F(TvInputHidlTest, InvalidDeviceIdTest) { + std::unique_lock<std::mutex> lock(mutex_); + + std::vector<int32_t> device_ids; + for (size_t i = 0; i < device_info_.size(); i++) { + device_ids.push_back(device_info_.keyAt(i)); + } + // Get a non-existing device ID. + int32_t id = getNumNotIn(device_ids); + EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id)); + + Result result = Result::UNKNOWN; + int32_t stream_id = 0; + tv_input_->openStream(id, stream_id, + [&result](Result res, const native_handle_t*) { + result = res; + }); + EXPECT_EQ(Result::INVALID_ARGUMENTS, result); + + result = Result::UNKNOWN; + result = tv_input_->closeStream(id, stream_id); + EXPECT_EQ(Result::INVALID_ARGUMENTS, result); +} + +/* + * InvalidStreamIdTest: + * Calls openStream(), and closeStream() for a non-existing stream + * Checks returned results + * The results should be Result::INVALID_ARGUMENTS + */ +TEST_F(TvInputHidlTest, InvalidStreamIdTest) { + std::unique_lock<std::mutex> lock(mutex_); + if (device_info_.isEmpty()) { + return; + } + updateAllStreamConfigurations(); + + int32_t device_id = device_info_.keyAt(0); + // Get a non-existing stream ID. + int32_t id = DEFAULT_ID; + if (stream_config_.indexOfKey(device_id) >= 0) { + std::vector<int32_t> stream_ids; + hidl_vec<TvStreamConfig> config = stream_config_.valueFor(device_id); + for (size_t i = 0; i < config.size(); i++) { + stream_ids.push_back(config[i].streamId); + } + id = getNumNotIn(stream_ids); + } + + Result result = Result::UNKNOWN; + tv_input_->openStream(device_id, id, + [&result](Result res, const native_handle_t*) { + result = res; + }); + EXPECT_EQ(Result::INVALID_ARGUMENTS, result); + + result = Result::UNKNOWN; + result = tv_input_->closeStream(device_id, id); + EXPECT_EQ(Result::INVALID_ARGUMENTS, result); +} + +/* + * OpenAnOpenedStreamsTest: + * Calls openStream() twice for a stream (if any) + * Checks returned results + * The result of the second call should be Result::INVALID_STATE + */ +TEST_F(TvInputHidlTest, OpenAnOpenedStreamsTest) { + std::unique_lock<std::mutex> lock(mutex_); + updateAllStreamConfigurations(); + std::vector<size_t> indices = getConfigIndices(); + if (indices.empty()) { + return; + } + int32_t device_id = stream_config_.keyAt(indices[0]); + int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId; + + Result result = Result::UNKNOWN; + tv_input_->openStream(device_id, stream_id, + [&result](Result res, const native_handle_t*) { + result = res; + }); + EXPECT_EQ(Result::OK, result); + + tv_input_->openStream(device_id, stream_id, + [&result](Result res, const native_handle_t*) { + result = res; + }); + EXPECT_EQ(Result::INVALID_STATE, result); +} + +/* + * CloseStreamBeforeOpenTest: + * Calls closeStream() without calling openStream() for a stream (if any) + * Checks the returned result + * The result should be Result::INVALID_STATE + */ +TEST_F(TvInputHidlTest, CloseStreamBeforeOpenTest) { + std::unique_lock<std::mutex> lock(mutex_); + updateAllStreamConfigurations(); + std::vector<size_t> indices = getConfigIndices(); + if (indices.empty()) { + return; + } + int32_t device_id = stream_config_.keyAt(indices[0]); + int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId; + EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id)); +} + +int main(int argc, char **argv) { + ::testing::AddGlobalTestEnvironment(new TvInputHidlEnvironment); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} +
diff --git a/tv/input/Android.mk b/tv/input/Android.mk new file mode 100644 index 0000000..f9e3276 --- /dev/null +++ b/tv/input/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2016 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-subdir-makefiles)
diff --git a/update-base-files.sh b/update-base-files.sh new file mode 100755 index 0000000..1eb6b51 --- /dev/null +++ b/update-base-files.sh
@@ -0,0 +1,43 @@ +#!/bin/bash + +if [ ! -d hardware/interfaces ] ; then + echo "Where is hardware/interfaces?"; + exit 1; +fi + +if [ ! -d system/libhidl/transport ] ; then + echo "Where is system/libhidl/transport?"; + exit 1; +fi + +echo "WARNING: This script changes files in many places." + +# These files only exist to facilitate the easy transition to hidl. + +options="-Lexport-header \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport" + +# hardware/libhardware +hidl-gen $options \ + -o hardware/libhardware/include/hardware/sensors-base.h \ + android.hardware.sensors@1.0 +hidl-gen $options \ + -o hardware/libhardware/include/hardware/nfc-base.h \ + android.hardware.nfc@1.0 +hidl-gen $options \ + -o hardware/libhardware/include/hardware/gnss-base.h \ + android.hardware.gnss@1.0 + +# system/core +hidl-gen $options \ + -o system/core/include/system/graphics-base.h \ + android.hardware.graphics.common@1.0 + +# system/media +hidl-gen $options \ + -o system/media/audio/include/system/audio-base.h \ + android.hardware.audio.common@2.0 +hidl-gen $options \ + -o system/media/audio/include/system/audio_effect-base.h \ + android.hardware.audio.effect@2.0
diff --git a/usb/1.0/Android.bp b/usb/1.0/Android.bp new file mode 100644 index 0000000..0b641f1 --- /dev/null +++ b/usb/1.0/Android.bp
@@ -0,0 +1,69 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.usb@1.0_hal", + srcs: [ + "types.hal", + "IUsb.hal", + "IUsbCallback.hal", + ], +} + +genrule { + name: "android.hardware.usb@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.usb@1.0", + srcs: [ + ":android.hardware.usb@1.0_hal", + ], + out: [ + "android/hardware/usb/1.0/types.cpp", + "android/hardware/usb/1.0/UsbAll.cpp", + "android/hardware/usb/1.0/UsbCallbackAll.cpp", + ], +} + +genrule { + name: "android.hardware.usb@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.usb@1.0", + srcs: [ + ":android.hardware.usb@1.0_hal", + ], + out: [ + "android/hardware/usb/1.0/types.h", + "android/hardware/usb/1.0/IUsb.h", + "android/hardware/usb/1.0/IHwUsb.h", + "android/hardware/usb/1.0/BnHwUsb.h", + "android/hardware/usb/1.0/BpHwUsb.h", + "android/hardware/usb/1.0/BsUsb.h", + "android/hardware/usb/1.0/IUsbCallback.h", + "android/hardware/usb/1.0/IHwUsbCallback.h", + "android/hardware/usb/1.0/BnHwUsbCallback.h", + "android/hardware/usb/1.0/BpHwUsbCallback.h", + "android/hardware/usb/1.0/BsUsbCallback.h", + ], +} + +cc_library_shared { + name: "android.hardware.usb@1.0", + generated_sources: ["android.hardware.usb@1.0_genc++"], + generated_headers: ["android.hardware.usb@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.usb@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/usb/1.0/Android.mk b/usb/1.0/Android.mk new file mode 100644 index 0000000..7be7147 --- /dev/null +++ b/usb/1.0/Android.mk
@@ -0,0 +1,427 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.usb@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (PortDataRole) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortDataRole.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortDataRole + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortMode) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortPowerRole) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortPowerRole.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortPowerRole + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortRole) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortRole.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortRole + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortRoleType) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortRoleType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortRoleType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortStatus) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IUsb.hal +# +GEN := $(intermediates)/android/hardware/usb/V1_0/IUsb.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IUsb.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IUsbCallback.hal +$(GEN): $(LOCAL_PATH)/IUsbCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::IUsb + +$(GEN): $(LOCAL_PATH)/IUsb.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IUsbCallback.hal +# +GEN := $(intermediates)/android/hardware/usb/V1_0/IUsbCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IUsbCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::IUsbCallback + +$(GEN): $(LOCAL_PATH)/IUsbCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.usb@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (PortDataRole) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortDataRole.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortDataRole + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortMode) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortMode.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortMode + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortPowerRole) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortPowerRole.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortPowerRole + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortRole) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortRole.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortRole + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortRoleType) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortRoleType.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortRoleType + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (PortStatus) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/PortStatus.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.PortStatus + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IUsb.hal +# +GEN := $(intermediates)/android/hardware/usb/V1_0/IUsb.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IUsb.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IUsbCallback.hal +$(GEN): $(LOCAL_PATH)/IUsbCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::IUsb + +$(GEN): $(LOCAL_PATH)/IUsb.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IUsbCallback.hal +# +GEN := $(intermediates)/android/hardware/usb/V1_0/IUsbCallback.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IUsbCallback.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0::IUsbCallback + +$(GEN): $(LOCAL_PATH)/IUsbCallback.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.usb@1.0-java-constants +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) +# +GEN := $(intermediates)/android/hardware/usb/V1_0/Constants.java +$(GEN): $(HIDL) +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/IUsb.hal +$(GEN): $(LOCAL_PATH)/IUsbCallback.hal + +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava-constants \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.usb@1.0 + +$(GEN): + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +# Avoid dependency cycle of framework.jar -> this-library -> framework.jar +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj + +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/usb/1.0/IUsb.hal b/usb/1.0/IUsb.hal new file mode 100644 index 0000000..965326a --- /dev/null +++ b/usb/1.0/IUsb.hal
@@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 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.usb@1.0; + +import IUsbCallback; + +interface IUsb { + /* + * This function is used to change the port role of a specific port. + * For example, when PD_SWAP or PR_SWAP is supported. + * This is function is asynchronous. The status of the role switch + * will be informed through IUsbCallback object's notifyPortStatusChange + * method. + * + * @param portName name of the port for which the role has to be changed + * @param role the new port role. + */ + oneway switchRole(string portName, PortRole role); + + /* + * This function is used to register a callback function which is + * called by the HAL whenever there is a change in the port state. + * i.e. DATA_ROLE, POWER_ROLE or MODE. + * + * Also the same callback object would be called to inform the caller + * of the roleSwitch status. + * + * @param callback IUsbCallback object used to convey status to the + * userspace. + */ + oneway setCallback(IUsbCallback callback); + + /* + * This functions is used to request the hal for the current status + * status of the Type-C ports. This method is async/oneway. The result of the + * query would be sent through the IUsbCallback object's notifyRoleSwitchStatus + * to the caller. This api would would let the caller know of the number + * of type-c ports that are present and their connection status through the + * PortStatus type. + */ + oneway queryPortStatus(); +}; +
diff --git a/usb/1.0/IUsbCallback.hal b/usb/1.0/IUsbCallback.hal new file mode 100644 index 0000000..b665ba3 --- /dev/null +++ b/usb/1.0/IUsbCallback.hal
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 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.usb@1.0; + +/* + * Callback object used for all the IUsb async methods which expects a result. + * Caller is expected to register the callback object using setCallback method + * to receive updates on the PortStatus. + */ +interface IUsbCallback { + /* + * Used to convey the current port status to the caller. + * Called either when PortState changes due to the port partner (or) + * when caller requested for the PortStatus update through queryPortStatus. + * + * @param currentPortStatus vector object of current status of all the + * typeC ports in the device. + * @param retval SUCCESS when query was done successfully. + * ERROR otherwise. + */ + oneway notifyPortStatusChange(vec<PortStatus> currentPortStatus, Status retval); + + /* + * Used to notify the result of the switchRole call to the caller. + * + * @param portName name of the port for which the roleswap is requested. + * @param newRole the new role requested by the caller. + * @param retval SUCCESS if the role switch succeeded. FAILURE otherwise. + */ + oneway notifyRoleSwitchStatus(string portName, PortRole newRole, Status retval); +};
diff --git a/usb/1.0/default/Android.mk b/usb/1.0/default/Android.mk new file mode 100644 index 0000000..afd53cf --- /dev/null +++ b/usb/1.0/default/Android.mk
@@ -0,0 +1,21 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE := android.hardware.usb@1.0-service +LOCAL_INIT_RC := android.hardware.usb@1.0-service.rc +LOCAL_SRC_FILES := \ + service.cpp \ + Usb.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libhidlbase \ + libhidltransport \ + liblog \ + libutils \ + libhardware \ + android.hardware.usb@1.0 \ + +include $(BUILD_EXECUTABLE)
diff --git a/usb/1.0/default/Usb.cpp b/usb/1.0/default/Usb.cpp new file mode 100644 index 0000000..6eb8842 --- /dev/null +++ b/usb/1.0/default/Usb.cpp
@@ -0,0 +1,473 @@ +/* + * Copyright (C) 2016 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. + */ +#include <assert.h> +#include <dirent.h> +#include <iostream> +#include <fstream> +#include <pthread.h> +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> + +#include <cutils/uevent.h> +#include <sys/epoll.h> +#include <utils/Errors.h> +#include <utils/StrongPointer.h> + +#include "Usb.h" + +namespace android { +namespace hardware { +namespace usb { +namespace V1_0 { +namespace implementation { + +// Set by the signal handler to destroy the thread +volatile bool destroyThread; + +int32_t readFile(std::string filename, std::string& contents) { + std::ifstream file(filename); + + if (file.is_open()) { + getline(file, contents); + file.close(); + return 0; + } + return -1; +} + +std::string appendRoleNodeHelper(const std::string portName, PortRoleType type) { + std::string node("/sys/class/dual_role_usb/" + portName); + + switch(type) { + case PortRoleType::DATA_ROLE: + return node + "/data_role"; + case PortRoleType::POWER_ROLE: + return node + "/power_role"; + default: + return node + "/mode"; + } +} + +std::string convertRoletoString(PortRole role) { + if (role.type == PortRoleType::POWER_ROLE) { + if (role.role == static_cast<uint32_t> (PortPowerRole::SOURCE)) + return "source"; + else if (role.role == static_cast<uint32_t> (PortPowerRole::SINK)) + return "sink"; + } else if (role.type == PortRoleType::DATA_ROLE) { + if (role.role == static_cast<uint32_t> (PortDataRole::HOST)) + return "host"; + if (role.role == static_cast<uint32_t> (PortDataRole::DEVICE)) + return "device"; + } else if (role.type == PortRoleType::MODE) { + if (role.role == static_cast<uint32_t> (PortMode::UFP)) + return "ufp"; + if (role.role == static_cast<uint32_t> (PortMode::DFP)) + return "dfp"; + } + return "none"; +} + +Return<void> Usb::switchRole(const hidl_string& portName, + const PortRole& newRole) { + std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), + newRole.type); + std::ofstream file(filename); + std::string written; + + ALOGI("filename write: %s role:%d", filename.c_str(), newRole.role); + + if (file.is_open()) { + file << convertRoletoString(newRole).c_str(); + file.close(); + if (!readFile(filename, written)) { + ALOGI("written: %s", written.c_str()); + if (written == convertRoletoString(newRole)) { + ALOGI("Role switch successfull"); + Return<void> ret = + mCallback->notifyRoleSwitchStatus(portName, newRole, + Status::SUCCESS); + if (!ret.isOk()) + ALOGE("RoleSwitchStatus error %s", + ret.description().c_str()); + } + } + } + + Return<void> ret = mCallback->notifyRoleSwitchStatus(portName, newRole, Status::ERROR); + if (!ret.isOk()) + ALOGE("RoleSwitchStatus error %s", ret.description().c_str()); + + return Void(); +} + +Status getCurrentRoleHelper(std::string portName, + PortRoleType type, uint32_t ¤tRole) { + std::string filename; + std::string roleName; + + if (type == PortRoleType::POWER_ROLE) { + filename = "/sys/class/dual_role_usb/" + + portName + "/power_role"; + currentRole = static_cast<uint32_t>(PortPowerRole::NONE); + } else if (type == PortRoleType::DATA_ROLE) { + filename = "/sys/class/dual_role_usb/" + + portName + "/data_role"; + currentRole = static_cast<uint32_t> (PortDataRole::NONE); + } else if (type == PortRoleType::MODE) { + filename = "/sys/class/dual_role_usb/" + + portName + "/mode"; + currentRole = static_cast<uint32_t> (PortMode::NONE); + } + + if (readFile(filename, roleName)) { + ALOGE("getCurrentRole: Failed to open filesystem node"); + return Status::ERROR; + } + + if (roleName == "dfp") + currentRole = static_cast<uint32_t> (PortMode::DFP); + else if (roleName == "ufp") + currentRole = static_cast<uint32_t> (PortMode::UFP); + else if (roleName == "source") + currentRole = static_cast<uint32_t> (PortPowerRole::SOURCE); + else if (roleName == "sink") + currentRole = static_cast<uint32_t> (PortPowerRole::SINK); + else if (roleName == "host") + currentRole = static_cast<uint32_t> (PortDataRole::HOST); + else if (roleName == "device") + currentRole = static_cast<uint32_t> (PortDataRole::DEVICE); + else if (roleName != "none") { + /* case for none has already been addressed. + * so we check if the role isnt none. + */ + return Status::UNRECOGNIZED_ROLE; + } + return Status::SUCCESS; +} + +Status getTypeCPortNamesHelper(std::vector<std::string>& names) { + DIR *dp; + + dp = opendir("/sys/class/dual_role_usb"); + if (dp != NULL) + { +rescan: + int32_t ports = 0; + int32_t current = 0; + struct dirent *ep; + + while ((ep = readdir (dp))) { + if (ep->d_type == DT_LNK) { + ports++; + } + } + + if (ports == 0) { + closedir(dp); + return Status::SUCCESS; + } + + names.resize(ports); + rewinddir(dp); + + while ((ep = readdir (dp))) { + if (ep->d_type == DT_LNK) { + /* Check to see if new ports were added since the first pass. */ + if (current >= ports) { + rewinddir(dp); + goto rescan; + } + names[current++] = ep->d_name; + } + } + + closedir (dp); + return Status::SUCCESS; + } + + ALOGE("Failed to open /sys/class/dual_role_usb"); + return Status::ERROR; +} + +bool canSwitchRoleHelper(const std::string portName, PortRoleType type) { + std::string filename = appendRoleNodeHelper(portName, type); + std::ofstream file(filename); + + if (file.is_open()) { + file.close(); + return true; + } + return false; +} + +Status getPortModeHelper(const std::string portName, PortMode& portMode) { + std::string filename = "/sys/class/dual_role_usb/" + + std::string(portName.c_str()) + "/supported_modes"; + std::string modes; + + if (readFile(filename, modes)) { + ALOGE("getSupportedRoles: Failed to open filesystem node"); + return Status::ERROR; + } + + if (modes == "ufp dfp") + portMode = PortMode::DRP; + else if (modes == "ufp") + portMode = PortMode::UFP; + else if (modes == "dfp") + portMode = PortMode::DFP; + else + return Status::UNRECOGNIZED_ROLE; + + return Status::SUCCESS; +} + +Status getPortStatusHelper (hidl_vec<PortStatus>& currentPortStatus) { + std::vector<std::string> names; + Status result = getTypeCPortNamesHelper(names); + + if (result == Status::SUCCESS) { + currentPortStatus.resize(names.size()); + for(std::vector<std::string>::size_type i = 0; i < names.size(); i++) { + ALOGI("%s", names[i].c_str()); + currentPortStatus[i].portName = names[i]; + + uint32_t currentRole; + if (getCurrentRoleHelper(names[i], PortRoleType::POWER_ROLE, + currentRole) == Status::SUCCESS) { + currentPortStatus[i].currentPowerRole = + static_cast<PortPowerRole> (currentRole); + } else { + ALOGE("Error while retreiving portNames"); + goto done; + } + + if (getCurrentRoleHelper(names[i], + PortRoleType::DATA_ROLE, currentRole) == Status::SUCCESS) { + currentPortStatus[i].currentDataRole = + static_cast<PortDataRole> (currentRole); + } else { + ALOGE("Error while retreiving current port role"); + goto done; + } + + if (getCurrentRoleHelper(names[i], PortRoleType::MODE, + currentRole) == Status::SUCCESS) { + currentPortStatus[i].currentMode = + static_cast<PortMode> (currentRole); + } else { + ALOGE("Error while retreiving current data role"); + goto done; + } + + currentPortStatus[i].canChangeMode = + canSwitchRoleHelper(names[i], PortRoleType::MODE); + currentPortStatus[i].canChangeDataRole = + canSwitchRoleHelper(names[i], PortRoleType::DATA_ROLE); + currentPortStatus[i].canChangePowerRole = + canSwitchRoleHelper(names[i], PortRoleType::POWER_ROLE); + + ALOGI("canChangeMode: %d canChagedata: %d canChangePower:%d", + currentPortStatus[i].canChangeMode, + currentPortStatus[i].canChangeDataRole, + currentPortStatus[i].canChangePowerRole); + + if (getPortModeHelper(names[i], currentPortStatus[i].supportedModes) + != Status::SUCCESS) { + ALOGE("Error while retrieving port modes"); + goto done; + } + } + return Status::SUCCESS; + } +done: + return Status::ERROR; +} + +Return<void> Usb::queryPortStatus() { + hidl_vec<PortStatus> currentPortStatus; + Status status; + + status = getPortStatusHelper(currentPortStatus); + Return<void> ret = mCallback->notifyPortStatusChange(currentPortStatus, + status); + if (!ret.isOk()) + ALOGE("queryPortStatus error %s", ret.description().c_str()); + + return Void(); +} +struct data { + int uevent_fd; + android::hardware::usb::V1_0::implementation::Usb *usb; +}; + +static void uevent_event(uint32_t /*epevents*/, struct data *payload) { + char msg[UEVENT_MSG_LEN + 2]; + char *cp; + int n; + + n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN); + if (n <= 0) + return; + if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ + return; + + msg[n] = '\0'; + msg[n + 1] = '\0'; + cp = msg; + + while (*cp) { + if (!strcmp(cp, "SUBSYSTEM=dual_role_usb")) { + ALOGE("uevent received %s", cp); + if (payload->usb->mCallback != NULL) { + hidl_vec<PortStatus> currentPortStatus; + Status status = getPortStatusHelper(currentPortStatus); + Return<void> ret = + payload->usb->mCallback->notifyPortStatusChange(currentPortStatus, status); + if (!ret.isOk()) + ALOGE("error %s", ret.description().c_str()); + } + break; + } + /* advance to after the next \0 */ + while (*cp++); + } +} + +void* work(void* param) { + int epoll_fd, uevent_fd; + struct epoll_event ev; + int nevents = 0; + struct data payload; + + ALOGE("creating thread"); + + uevent_fd = uevent_open_socket(64*1024, true); + + if (uevent_fd < 0) { + ALOGE("uevent_init: uevent_open_socket failed\n"); + return NULL; + } + + payload.uevent_fd = uevent_fd; + payload.usb = (android::hardware::usb::V1_0::implementation::Usb *)param; + + fcntl(uevent_fd, F_SETFL, O_NONBLOCK); + + ev.events = EPOLLIN; + ev.data.ptr = (void *)uevent_event; + + epoll_fd = epoll_create(64); + if (epoll_fd == -1) { + ALOGE("epoll_create failed; errno=%d", errno); + goto error; + } + + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) { + ALOGE("epoll_ctl failed; errno=%d", errno); + goto error; + } + + while (!destroyThread) { + struct epoll_event events[64]; + + nevents = epoll_wait(epoll_fd, events, 64, -1); + if (nevents == -1) { + if (errno == EINTR) + continue; + ALOGE("usb epoll_wait failed; errno=%d", errno); + break; + } + + for (int n = 0; n < nevents; ++n) { + if (events[n].data.ptr) + (*(void (*)(int, struct data *payload))events[n].data.ptr) + (events[n].events, &payload); + } + } + + ALOGI("exiting worker thread"); +error: + close(uevent_fd); + + if (epoll_fd >= 0) + close(epoll_fd); + + return NULL; +} + +void sighandler(int sig) +{ + if (sig == SIGUSR1) { + destroyThread = true; + ALOGI("destroy set"); + return; + } + signal(SIGUSR1, sighandler); +} + +Return<void> Usb::setCallback(const sp<IUsbCallback>& callback) { + + pthread_mutex_lock(&mLock); + if ((mCallback == NULL && callback == NULL) || + (mCallback != NULL && callback != NULL)) { + mCallback = callback; + pthread_mutex_unlock(&mLock); + return Void(); + } + + mCallback = callback; + ALOGI("registering callback"); + + if (mCallback == NULL) { + if (!pthread_kill(mPoll, SIGUSR1)) { + pthread_join(mPoll, NULL); + ALOGI("pthread destroyed"); + } + pthread_mutex_unlock(&mLock); + return Void(); + } + + destroyThread = false; + signal(SIGUSR1, sighandler); + + if (pthread_create(&mPoll, NULL, work, this)) { + ALOGE("pthread creation failed %d", errno); + mCallback = NULL; + } + pthread_mutex_unlock(&mLock); + return Void(); +} + +// Protects *usb assignment +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +Usb *usb; + +Usb::Usb() { + pthread_mutex_lock(&lock); + // Make this a singleton class + assert(usb == NULL); + usb = this; + pthread_mutex_unlock(&lock); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace usb +} // namespace hardware +} // namespace android
diff --git a/usb/1.0/default/Usb.h b/usb/1.0/default/Usb.h new file mode 100644 index 0000000..c34d080 --- /dev/null +++ b/usb/1.0/default/Usb.h
@@ -0,0 +1,52 @@ +#ifndef ANDROID_HARDWARE_USB_V1_0_USB_H +#define ANDROID_HARDWARE_USB_V1_0_USB_H + +#include <android/hardware/usb/1.0/IUsb.h> +#include <hidl/MQDescriptor.h> +#include <hidl/Status.h> +#include <utils/Log.h> + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "android.hardware.usb@1.0-service" +#define UEVENT_MSG_LEN 2048 + +namespace android { +namespace hardware { +namespace usb { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::usb::V1_0::IUsb; +using ::android::hardware::usb::V1_0::IUsbCallback; +using ::android::hardware::usb::V1_0::PortRole; +using ::android::hidl::base::V1_0::IBase; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +struct Usb : public IUsb { + Usb(); + Return<void> switchRole(const hidl_string& portName, const PortRole& role) override; + Return<void> setCallback(const sp<IUsbCallback>& callback) override; + Return<void> queryPortStatus() override; + + sp<IUsbCallback> mCallback; + private: + pthread_t mPoll; + pthread_mutex_t mLock = PTHREAD_MUTEX_INITIALIZER; +}; + +} // namespace implementation +} // namespace V1_0 +} // namespace usb +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_USB_V1_0_USB_H
diff --git a/usb/1.0/default/android.hardware.usb@1.0-service.rc b/usb/1.0/default/android.hardware.usb@1.0-service.rc new file mode 100644 index 0000000..6ea0720 --- /dev/null +++ b/usb/1.0/default/android.hardware.usb@1.0-service.rc
@@ -0,0 +1,4 @@ +service usb-hal-1-0 /vendor/bin/hw/android.hardware.usb@1.0-service + class hal + user system + group system
diff --git a/usb/1.0/default/service.cpp b/usb/1.0/default/service.cpp new file mode 100644 index 0000000..b4db241 --- /dev/null +++ b/usb/1.0/default/service.cpp
@@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 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. + */ + +#include <hidl/HidlTransportSupport.h> +#include "Usb.h" + +using android::sp; + +// libhwbinder: +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; + +// Generated HIDL files +using android::hardware::usb::V1_0::IUsb; +using android::hardware::usb::V1_0::implementation::Usb; + +int main() { + const char instance[] = "usb_hal"; + + android::sp<IUsb> service = new Usb(); + + configureRpcThreadpool(1, true /*callerWillJoin*/); + service->registerAsService(instance); + + ALOGI("USB HAL Ready."); + joinRpcThreadpool(); +}
diff --git a/usb/1.0/types.hal b/usb/1.0/types.hal new file mode 100644 index 0000000..17cd8c7 --- /dev/null +++ b/usb/1.0/types.hal
@@ -0,0 +1,214 @@ +/* + * Copyright (C) 2016 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.usb@1.0; + + +enum Status : uint32_t { + SUCCESS = 0, + + /* + * error value when the HAL operation fails for reasons not listed here. + */ + ERROR = 1, + + /* + * error value returned when input argument is invalid. + */ + INVALID_ARGUMENT = 2, + + /* + * error value returned when role string is unrecognized. + */ + UNRECOGNIZED_ROLE = 3, +}; + +/* + * Denotes the Port role type. + * Passed as an argument for functions used to query or change port roles. + */ +enum PortRoleType : uint32_t { + /* + * Denotes the data role of the port. + * The port can either be a "host" or a "device" for data. + * This maps to the PortDataRole enum. + */ + DATA_ROLE = 0, + + /* + * Denotes the power role of the port. + * The port can either be a "source" or "sink" for power. + * This maps to PortPowerRole enum. + */ + POWER_ROLE = 1, + + /* + * USB ports can be a pure DFP port which can only act + * as a host. A UFP port which can only act as a device. + * Or a dual role ports which can either can as a host or + * a device. This property is used to mention them. + */ + MODE = 2, +}; + +@export +enum PortDataRole : uint32_t { + /* + * Indicates that the port does not have a data role. + * In case of DRP, the current data role of the port is only resolved + * when the type-c handshake happens. + */ + NONE = 0, + + /* + * Indicates that the port is acting as a host for data. + */ + HOST = 1, + + /* + * Indicated that the port is acting as a device for data. + */ + DEVICE = 2, + + NUM_DATA_ROLES = 3, +}; + +@export +enum PortPowerRole : uint32_t { + /* + * Indicates that the port does not have a power role. + * In case of DRP, the current power role of the port is only resolved + * when the type-c handshake happens. + */ + NONE = 0, + + /* + * Indicates that the port is supplying power to the other port. + */ + SOURCE = 1, + + /* + * Indicates that the port is sinking power from the other port. + */ + SINK = 2, + + NUM_POWER_ROLES = 3, +}; + +@export +enum PortMode : uint32_t { + /* + * Indicates that the port does not have a mode. + * In case of DRP, the current mode of the port is only resolved + * when the type-c handshake happens. + */ + NONE = 0, + /* + * Indicates that port can only act as device for data and sink for power. + */ + UFP = 1, + + /* + * Indicates the port can only act as host for data and source for power. + */ + DFP = 2, + + /* + * Indicates can either act as UFP or DFP at a given point of time. + */ + DRP = 3, + + NUM_MODES = 4, +}; + +/* + * Used as a container to send port role information. + */ +struct PortRole { + /* + * Indicates the type of Port Role. + * Maps to the PortRoleType enum. + */ + PortRoleType type; + + /* + * when type is HAL_USB_DATA_ROLE pass values from enum PortDataRole. + * when type is HAL_USB_POWER_ROLE pass values from enum PortPowerRole. + * when type is HAL_USB_MODE pass values from enum PortMode. + */ + uint32_t role; +}; + +/* + * Used as the container to report data back to the caller. + * Represents the current connection status of a single USB port. + */ +struct PortStatus { + /* + * Name of the port. + * Used as the port's id by the caller. + */ + string portName; + + /* + * Data role of the port. + */ + PortDataRole currentDataRole; + + /* + * Power Role of thte port. + */ + PortPowerRole currentPowerRole; + + /* + * Mode in which the port is connected. + * Can be UFP or DFP. + */ + PortMode currentMode; + + /* + * True indicates that the port's mode can + * be changed. False otherwise. + */ + bool canChangeMode; + + /* + * True indicates that the port's data role + * can be changed. False otherwise. + * For example, true if Type-C PD PD_SWAP + * is supported. + */ + bool canChangeDataRole; + + /* + * True indicates that the port's power role + * can be changed. False otherwise. + * For example, true if Type-C PD PR_SWAP + * is supported. + */ + bool canChangePowerRole; + + /* + * Identifies the type of the local port. + * + * UFP - Indicates that port can only act as device for + * data and sink for power. + * DFP - Indicates the port can only act as host for data + * and source for power. + * DRP - Indicates can either act as UFP or DFP at a + * given point of time. + */ + PortMode supportedModes; +};
diff --git a/usb/1.0/vts/functional/Android.bp b/usb/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..7438bc7 --- /dev/null +++ b/usb/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@ +// +// Copyright (C) 2017 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. +// + +cc_test { + name: "VtsHalUsbV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalUsbV1_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "liblog", + "libcutils", + "libhidlbase", + "libhidltransport", + "libnativehelper", + "libutils", + "android.hardware.usb@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +}
diff --git a/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp b/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp new file mode 100644 index 0000000..54db8c2 --- /dev/null +++ b/usb/1.0/vts/functional/VtsHalUsbV1_0TargetTest.cpp
@@ -0,0 +1,351 @@ +/* + * Copyright (C) 2017 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. + */ + +#define LOG_TAG "VtsHalUsbV1_0TargetTest" +#include <android-base/logging.h> + +#include <android/hardware/usb/1.0/IUsb.h> +#include <android/hardware/usb/1.0/IUsbCallback.h> +#include <android/hardware/usb/1.0/types.h> + +#include <VtsHalHidlTargetTestBase.h> +#include <stdlib.h> +#include <chrono> +#include <condition_variable> +#include <mutex> + +#define TIMEOUT_PERIOD 10 + +using ::android::hardware::usb::V1_0::IUsbCallback; +using ::android::hardware::usb::V1_0::IUsb; +using ::android::hardware::usb::V1_0::PortDataRole; +using ::android::hardware::usb::V1_0::PortMode; +using ::android::hardware::usb::V1_0::PortPowerRole; +using ::android::hardware::usb::V1_0::PortRole; +using ::android::hardware::usb::V1_0::PortRoleType; +using ::android::hardware::usb::V1_0::PortStatus; +using ::android::hardware::usb::V1_0::Status; +using ::android::hidl::base::V1_0::IBase; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +#define USB_SERVICE_NAME "usb_hal" + +// The main test class for the USB hidl HAL +class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + // Callback class for the USB HIDL hal. + // Usb Hal will call this object upon role switch or port query. + class UsbCallback : public IUsbCallback { + UsbHidlTest& parent_; + int cookie; + + public: + UsbCallback(UsbHidlTest& parent, int cookie) + : parent_(parent), cookie(cookie){}; + + virtual ~UsbCallback() = default; + + // Callback method for the port status. + Return<void> notifyPortStatusChange( + const hidl_vec<PortStatus>& currentPortStatus, Status retval) override { + if (retval == Status::SUCCESS) { + parent_.usb_last_port_status.portName = + currentPortStatus[0].portName.c_str(); + parent_.usb_last_port_status.currentDataRole = + currentPortStatus[0].currentDataRole; + parent_.usb_last_port_status.currentPowerRole = + currentPortStatus[0].currentPowerRole; + parent_.usb_last_port_status.currentMode = + currentPortStatus[0].currentMode; + } + parent_.usb_last_cookie = cookie; + parent_.notify(); + return Void(); + }; + + // Callback method for the status of role switch operation. + Return<void> notifyRoleSwitchStatus(const hidl_string& /*portName*/, + const PortRole& newRole, + Status retval) override { + parent_.usb_last_status = retval; + parent_.usb_last_cookie = cookie; + parent_.usb_last_port_role = newRole; + parent_.usb_role_switch_done = true; + parent_.notify(); + return Void(); + }; + }; + + virtual void SetUp() override { + ALOGI("Setup"); + usb = ::testing::VtsHalHidlTargetTestBase::getService<IUsb>(USB_SERVICE_NAME); + ASSERT_NE(usb, nullptr); + + usb_cb_2 = new UsbCallback(*this, 2); + ASSERT_NE(usb_cb_2, nullptr); + Return<void> ret = usb->setCallback(usb_cb_2); + ASSERT_TRUE(ret.isOk()); + } + + virtual void TearDown() override { ALOGI("Teardown"); } + + // Used as a mechanism to inform the test about data/event callback. + inline void notify() { + std::unique_lock<std::mutex> lock(usb_mtx); + usb_count++; + usb_cv.notify_one(); + } + + // Test code calls this function to wait for data/event callback. + inline std::cv_status wait() { + std::unique_lock<std::mutex> lock(usb_mtx); + + std::cv_status status = std::cv_status::no_timeout; + auto now = std::chrono::system_clock::now(); + while (usb_count == 0) { + status = + usb_cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); + if (status == std::cv_status::timeout) { + ALOGI("timeout"); + return status; + } + } + usb_count--; + return status; + } + + // USB hidl hal Proxy + sp<IUsb> usb; + + // Callback objects for usb hidl + // Methods of these objects are called to notify port status updates. + sp<IUsbCallback> usb_cb_1, usb_cb_2; + + // The last conveyed status of the USB ports. + // Stores information of currentt_data_role, power_role for all the USB ports + PortStatus usb_last_port_status; + + // Status of the last role switch operation. + Status usb_last_status; + + // Port role information of the last role switch operation. + PortRole usb_last_port_role; + + // Flag to indicate the invocation of role switch callback. + bool usb_role_switch_done; + + // Identifier for the usb callback object. + // Stores the cookie of the last invoked usb callback object. + int usb_last_cookie; + + // synchronization primitives to coordinate between main test thread + // and the callback thread. + std::mutex usb_mtx; + std::condition_variable usb_cv; + int usb_count; +}; + +/* + * Test to see if setCallback succeeds. + * Callback oject is created and registered. + * Check to see if the hidl transaction succeeded. + */ +TEST_F(UsbHidlTest, setCallback) { + usb_cb_1 = new UsbCallback(*this, 1); + ASSERT_NE(usb_cb_1, nullptr); + Return<void> ret = usb->setCallback(usb_cb_1); + ASSERT_TRUE(ret.isOk()); +} + +/* + * Check to see if querying type-c + * port status succeeds. + */ +TEST_F(UsbHidlTest, queryPortStatus) { + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(2, usb_last_cookie); + ALOGI("rightafter: %s", usb_last_port_status.portName.c_str()); +} + +/* + * Trying to switch a non-existent port should fail. + * This test case tried to switch the port with empty + * name which is expected to fail. + */ +TEST_F(UsbHidlTest, switchEmptyPort) { + struct PortRole role; + role.type = PortRoleType::DATA_ROLE; + + Return<void> ret = usb->switchRole("", role); + ASSERT_TRUE(ret.isOk()); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(Status::ERROR, usb_last_status); + EXPECT_EQ(2, usb_last_cookie); +} + +/* + * Test switching the mode of usb port. + * Test case queries the usb ports present in device. + * If there is atleast one usb port, a mode switch + * to DFP is attempted for the port. + * The callback parametes are checked to see if the mode + * switch was successfull. Upon success, Status::SUCCESS + * is expected to be returned. + */ +TEST_F(UsbHidlTest, switchModetoDFP) { + struct PortRole role; + role.type = PortRoleType::MODE; + role.role = static_cast<uint32_t>(PortMode::DFP); + + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(2, usb_last_cookie); + + if (!usb_last_port_status.portName.empty()) { + hidl_string portBeingSwitched = usb_last_port_status.portName; + ALOGI("mode portname:%s", portBeingSwitched.c_str()); + usb_role_switch_done = false; + Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role); + ASSERT_TRUE(ret.isOk()); + + std::cv_status waitStatus = wait(); + while (waitStatus == std::cv_status::no_timeout && + usb_role_switch_done == false) + waitStatus = wait(); + + EXPECT_EQ(std::cv_status::no_timeout, waitStatus); + EXPECT_EQ(2, usb_last_cookie); + + EXPECT_EQ(static_cast<uint32_t>(PortRoleType::MODE), + static_cast<uint32_t>(usb_last_port_role.type)); + if (usb_last_status == Status::SUCCESS) { + EXPECT_EQ(static_cast<uint32_t>(PortMode::DFP), + static_cast<uint32_t>(usb_last_port_role.role)); + } else { + EXPECT_NE(static_cast<uint32_t>(PortMode::UFP), + static_cast<uint32_t>(usb_last_port_role.role)); + } + } +} + +/* + * Test switching the power role of usb port. + * Test case queries the usb ports present in device. + * If there is atleast one usb port, a power role switch + * to SOURCE is attempted for the port. + * The callback parametes are checked to see if the power role + * switch was successfull. Upon success, Status::SUCCESS + * is expected to be returned. + */ + +TEST_F(UsbHidlTest, switchPowerRole) { + struct PortRole role; + role.type = PortRoleType::POWER_ROLE; + role.role = static_cast<uint32_t>(PortPowerRole::SOURCE); + + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(2, usb_last_cookie); + + if (!usb_last_port_status.portName.empty()) { + hidl_string portBeingSwitched = usb_last_port_status.portName; + ALOGI("switchPower role portname:%s", portBeingSwitched.c_str()); + usb_role_switch_done = false; + Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role); + ASSERT_TRUE(ret.isOk()); + + std::cv_status waitStatus = wait(); + while (waitStatus == std::cv_status::no_timeout && + usb_role_switch_done == false) + waitStatus = wait(); + + EXPECT_EQ(std::cv_status::no_timeout, waitStatus); + EXPECT_EQ(2, usb_last_cookie); + + EXPECT_EQ(static_cast<uint32_t>(PortRoleType::POWER_ROLE), + static_cast<uint32_t>(usb_last_port_role.type)); + if (usb_last_status == Status::SUCCESS) { + EXPECT_EQ(static_cast<uint32_t>(PortPowerRole::SOURCE), + static_cast<uint32_t>(usb_last_port_role.role)); + } else { + EXPECT_NE(static_cast<uint32_t>(PortPowerRole::SINK), + static_cast<uint32_t>(usb_last_port_role.role)); + } + } +} + +/* + * Test switching the data role of usb port. + * Test case queries the usb ports present in device. + * If there is atleast one usb port, a power role switch + * to HOST is attempted for the port. + * The callback parametes are checked to see if the power role + * switch was successfull. Upon success, Status::SUCCESS + * is expected to be returned. + */ +TEST_F(UsbHidlTest, switchDataRole) { + struct PortRole role; + role.type = PortRoleType::DATA_ROLE; + role.role = static_cast<uint32_t>(PortDataRole::HOST); + + Return<void> ret = usb->queryPortStatus(); + ASSERT_TRUE(ret.isOk()); + EXPECT_EQ(std::cv_status::no_timeout, wait()); + EXPECT_EQ(2, usb_last_cookie); + + if (!usb_last_port_status.portName.empty()) { + hidl_string portBeingSwitched = usb_last_port_status.portName; + ALOGI("portname:%s", portBeingSwitched.c_str()); + usb_role_switch_done = false; + Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role); + ASSERT_TRUE(ret.isOk()); + + std::cv_status waitStatus = wait(); + while (waitStatus == std::cv_status::no_timeout && + usb_role_switch_done == false) + waitStatus = wait(); + + EXPECT_EQ(std::cv_status::no_timeout, waitStatus); + EXPECT_EQ(2, usb_last_cookie); + + EXPECT_EQ(static_cast<uint32_t>(PortRoleType::DATA_ROLE), + static_cast<uint32_t>(usb_last_port_role.type)); + if (usb_last_status == Status::SUCCESS) { + EXPECT_EQ(static_cast<uint32_t>(PortDataRole::HOST), + static_cast<uint32_t>(usb_last_port_role.role)); + } else { + EXPECT_NE(static_cast<uint32_t>(PortDataRole::DEVICE), + static_cast<uint32_t>(usb_last_port_role.role)); + } + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +}
diff --git a/usb/Android.bp b/usb/Android.bp new file mode 100644 index 0000000..33f70eb --- /dev/null +++ b/usb/Android.bp
@@ -0,0 +1,5 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/vts/functional", +]
diff --git a/vibrator/1.0/Android.bp b/vibrator/1.0/Android.bp new file mode 100644 index 0000000..d6813ea --- /dev/null +++ b/vibrator/1.0/Android.bp
@@ -0,0 +1,62 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.vibrator@1.0_hal", + srcs: [ + "types.hal", + "IVibrator.hal", + ], +} + +genrule { + name: "android.hardware.vibrator@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.vibrator@1.0", + srcs: [ + ":android.hardware.vibrator@1.0_hal", + ], + out: [ + "android/hardware/vibrator/1.0/types.cpp", + "android/hardware/vibrator/1.0/VibratorAll.cpp", + ], +} + +genrule { + name: "android.hardware.vibrator@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.vibrator@1.0", + srcs: [ + ":android.hardware.vibrator@1.0_hal", + ], + out: [ + "android/hardware/vibrator/1.0/types.h", + "android/hardware/vibrator/1.0/IVibrator.h", + "android/hardware/vibrator/1.0/IHwVibrator.h", + "android/hardware/vibrator/1.0/BnHwVibrator.h", + "android/hardware/vibrator/1.0/BpHwVibrator.h", + "android/hardware/vibrator/1.0/BsVibrator.h", + ], +} + +cc_library_shared { + name: "android.hardware.vibrator@1.0", + generated_sources: ["android.hardware.vibrator@1.0_genc++"], + generated_headers: ["android.hardware.vibrator@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.vibrator@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/vibrator/1.0/Android.mk b/vibrator/1.0/Android.mk new file mode 100644 index 0000000..4e1ba6a --- /dev/null +++ b/vibrator/1.0/Android.mk
@@ -0,0 +1,118 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.vibrator@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/vibrator/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.vibrator@1.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IVibrator.hal +# +GEN := $(intermediates)/android/hardware/vibrator/V1_0/IVibrator.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVibrator.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.vibrator@1.0::IVibrator + +$(GEN): $(LOCAL_PATH)/IVibrator.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.vibrator@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build types.hal (Status) +# +GEN := $(intermediates)/android/hardware/vibrator/V1_0/Status.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.vibrator@1.0::types.Status + +$(GEN): $(LOCAL_PATH)/types.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) + +# +# Build IVibrator.hal +# +GEN := $(intermediates)/android/hardware/vibrator/V1_0/IVibrator.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVibrator.hal +$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal +$(GEN): $(LOCAL_PATH)/types.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.vibrator@1.0::IVibrator + +$(GEN): $(LOCAL_PATH)/IVibrator.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/vibrator/1.0/IVibrator.hal b/vibrator/1.0/IVibrator.hal new file mode 100644 index 0000000..0a4ffca --- /dev/null +++ b/vibrator/1.0/IVibrator.hal
@@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 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.vibrator@1.0; + +interface IVibrator { + /** Turn on vibrator + * + * This function must only be called after the previous timeout has expired or + * was canceled (through off()). + * @param timeout_ms number of milliseconds to vibrate. + * @return vibratorOnRet whether vibrator command was successful or not. + */ + on(uint32_t timeoutMs) generates (Status vibratorOnRet); + + /** Turn off vibrator + * + * Cancel a previously-started vibration, if any. + * @return vibratorOffRet whether vibrator command was successful or not. + */ + off() generates (Status vibratorOffRet); +};
diff --git a/vibrator/1.0/default/Android.bp b/vibrator/1.0/default/Android.bp new file mode 100644 index 0000000..d4200da --- /dev/null +++ b/vibrator/1.0/default/Android.bp
@@ -0,0 +1,30 @@ +// +// Copyright (C) 2016 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. + +cc_library_shared { + name: "android.hardware.vibrator@1.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["Vibrator.cpp"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "liblog", + "libutils", + "libhardware", + "android.hardware.vibrator@1.0", + ], +}
diff --git a/vibrator/1.0/default/Android.mk b/vibrator/1.0/default/Android.mk new file mode 100644 index 0000000..af4a955 --- /dev/null +++ b/vibrator/1.0/default/Android.mk
@@ -0,0 +1,35 @@ +# +# Copyright (C) 2016 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. + + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.vibrator@1.0-service +LOCAL_INIT_RC := android.hardware.vibrator@1.0-service.rc +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libhidlbase \ + libhidltransport \ + liblog \ + libutils \ + libhardware \ + android.hardware.vibrator@1.0 + +include $(BUILD_EXECUTABLE)
diff --git a/vibrator/1.0/default/Vibrator.cpp b/vibrator/1.0/default/Vibrator.cpp new file mode 100644 index 0000000..8c82bcd --- /dev/null +++ b/vibrator/1.0/default/Vibrator.cpp
@@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "VibratorService" + +#include <log/log.h> + +#include <hardware/hardware.h> +#include <hardware/vibrator.h> + +#include "Vibrator.h" + +namespace android { +namespace hardware { +namespace vibrator { +namespace V1_0 { +namespace implementation { + +Vibrator::Vibrator(vibrator_device_t *device) : mDevice(device) {} + +// Methods from ::android::hardware::vibrator::V1_0::IVibrator follow. +Return<Status> Vibrator::on(uint32_t timeout_ms) { + int32_t ret = mDevice->vibrator_on(mDevice, timeout_ms); + if (ret != 0) { + ALOGE("on command failed : %s", strerror(-ret)); + return Status::ERR; + } + return Status::OK; +} + +Return<Status> Vibrator::off() { + int32_t ret = mDevice->vibrator_off(mDevice); + if (ret != 0) { + ALOGE("off command failed : %s", strerror(-ret)); + return Status::ERR; + } + return Status::OK; +} + +IVibrator* HIDL_FETCH_IVibrator(const char * /*hal*/) { + vibrator_device_t *vib_device; + const hw_module_t *hw_module = nullptr; + + int ret = hw_get_module(VIBRATOR_HARDWARE_MODULE_ID, &hw_module); + if (ret == 0) { + ret = vibrator_open(hw_module, &vib_device); + if (ret != 0) { + ALOGE("vibrator_open failed: %d", ret); + } + } else { + ALOGE("hw_get_module %s failed: %d", VIBRATOR_HARDWARE_MODULE_ID, ret); + } + + if (ret == 0) { + return new Vibrator(vib_device); + } else { + ALOGE("Passthrough failed to open legacy HAL."); + return nullptr; + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace vibrator +} // namespace hardware +} // namespace android
diff --git a/vibrator/1.0/default/Vibrator.h b/vibrator/1.0/default/Vibrator.h new file mode 100644 index 0000000..061b364 --- /dev/null +++ b/vibrator/1.0/default/Vibrator.h
@@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_VIBRATOR_V1_0_VIBRATOR_H +#define ANDROID_HARDWARE_VIBRATOR_V1_0_VIBRATOR_H + +#include <android/hardware/vibrator/1.0/IVibrator.h> +#include <hidl/Status.h> + +#include <hidl/MQDescriptor.h> +namespace android { +namespace hardware { +namespace vibrator { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::vibrator::V1_0::IVibrator; +using ::android::hardware::vibrator::V1_0::Status; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +struct Vibrator : public IVibrator { + Vibrator(vibrator_device_t *device); + + // Methods from ::android::hardware::vibrator::V1_0::IVibrator follow. + Return<Status> on(uint32_t timeoutMs) override; + Return<Status> off() override; + + private: + vibrator_device_t *mDevice; +}; + +extern "C" IVibrator* HIDL_FETCH_IVibrator(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace vibrator +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_VIBRATOR_V1_0_VIBRATOR_H
diff --git a/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc new file mode 100644 index 0000000..4153c44 --- /dev/null +++ b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
@@ -0,0 +1,4 @@ +service vibrator-1-0 /vendor/bin/hw/android.hardware.vibrator@1.0-service + class hal + user system + group system readproc
diff --git a/vibrator/1.0/default/service.cpp b/vibrator/1.0/default/service.cpp new file mode 100644 index 0000000..7cc0744 --- /dev/null +++ b/vibrator/1.0/default/service.cpp
@@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.vibrator@1.0-service" + +#include <android/hardware/vibrator/1.0/IVibrator.h> +#include <hidl/LegacySupport.h> + +using android::hardware::vibrator::V1_0::IVibrator; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IVibrator>(); +}
diff --git a/vibrator/1.0/types.hal b/vibrator/1.0/types.hal new file mode 100644 index 0000000..8fc5683 --- /dev/null +++ b/vibrator/1.0/types.hal
@@ -0,0 +1,22 @@ +/* + * Copyright (C) 2016 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.vibrator@1.0; + +enum Status: uint32_t { + OK = 0, + ERR = 1 +};
diff --git a/radio/1.0/vts/Android.mk b/vibrator/1.0/vts/Android.mk similarity index 100% copy from radio/1.0/vts/Android.mk copy to vibrator/1.0/vts/Android.mk
diff --git a/vibrator/1.0/vts/functional/Android.bp b/vibrator/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..9e25def --- /dev/null +++ b/vibrator/1.0/vts/functional/Android.bp
@@ -0,0 +1,34 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalVibratorV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalVibratorV1_0TargetTest.cpp"], + shared_libs: [ + "libbase", + "libhidlbase", + "liblog", + "libutils", + "android.hardware.vibrator@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ], +} +
diff --git a/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp new file mode 100644 index 0000000..a978f2c --- /dev/null +++ b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
@@ -0,0 +1,65 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "vibrator_hidl_hal_test" + +#include <android-base/logging.h> +#include <android/hardware/vibrator/1.0/IVibrator.h> +#include <android/hardware/vibrator/1.0/types.h> +#include <VtsHalHidlTargetTestBase.h> +#include <unistd.h> + +using ::android::hardware::vibrator::V1_0::IVibrator; +using ::android::hardware::vibrator::V1_0::Status; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +// The main test class for VIBRATOR HIDL HAL. +class VibratorHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>(); + ASSERT_NE(vibrator, nullptr); + } + + virtual void TearDown() override {} + + sp<IVibrator> vibrator; +}; + +// A class for test environment setup (kept since this file is a template). +class VibratorHidlEnvironment : public ::testing::Environment { + public: + virtual void SetUp() {} + virtual void TearDown() {} + + private: +}; + +TEST_F(VibratorHidlTest, OnThenOffBeforeTimeout) { + EXPECT_EQ(Status::OK, vibrator->on(2000)); + sleep(1); + EXPECT_EQ(Status::OK, vibrator->off()); +} + +int main(int argc, char **argv) { + ::testing::AddGlobalTestEnvironment(new VibratorHidlEnvironment); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; +}
diff --git a/vibrator/Android.bp b/vibrator/Android.bp new file mode 100644 index 0000000..ed19a37 --- /dev/null +++ b/vibrator/Android.bp
@@ -0,0 +1,6 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/default", + "1.0/vts/functional", +]
diff --git a/vr/1.0/Android.bp b/vr/1.0/Android.bp new file mode 100644 index 0000000..b48d010 --- /dev/null +++ b/vr/1.0/Android.bp
@@ -0,0 +1,59 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +filegroup { + name: "android.hardware.vr@1.0_hal", + srcs: [ + "IVr.hal", + ], +} + +genrule { + name: "android.hardware.vr@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.vr@1.0", + srcs: [ + ":android.hardware.vr@1.0_hal", + ], + out: [ + "android/hardware/vr/1.0/VrAll.cpp", + ], +} + +genrule { + name: "android.hardware.vr@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.vr@1.0", + srcs: [ + ":android.hardware.vr@1.0_hal", + ], + out: [ + "android/hardware/vr/1.0/IVr.h", + "android/hardware/vr/1.0/IHwVr.h", + "android/hardware/vr/1.0/BnHwVr.h", + "android/hardware/vr/1.0/BpHwVr.h", + "android/hardware/vr/1.0/BsVr.h", + ], +} + +cc_library_shared { + name: "android.hardware.vr@1.0", + generated_sources: ["android.hardware.vr@1.0_genc++"], + generated_headers: ["android.hardware.vr@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.vr@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "liblog", + "libutils", + "libcutils", + "android.hidl.base@1.0", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "android.hidl.base@1.0", + ], +}
diff --git a/vr/1.0/Android.mk b/vr/1.0/Android.mk new file mode 100644 index 0000000..0fbdaf7 --- /dev/null +++ b/vr/1.0/Android.mk
@@ -0,0 +1,76 @@ +# This file is autogenerated by hidl-gen. Do not edit manually. + +LOCAL_PATH := $(call my-dir) + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.vr@1.0-java +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java \ + + +# +# Build IVr.hal +# +GEN := $(intermediates)/android/hardware/vr/V1_0/IVr.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVr.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.vr@1.0::IVr + +$(GEN): $(LOCAL_PATH)/IVr.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_JAVA_LIBRARY) + + +################################################################################ + +include $(CLEAR_VARS) +LOCAL_MODULE := android.hardware.vr@1.0-java-static +LOCAL_MODULE_CLASS := JAVA_LIBRARIES + +intermediates := $(call local-generated-sources-dir, COMMON) + +HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android.hidl.base@1.0-java-static \ + + +# +# Build IVr.hal +# +GEN := $(intermediates)/android/hardware/vr/V1_0/IVr.java +$(GEN): $(HIDL) +$(GEN): PRIVATE_HIDL := $(HIDL) +$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVr.hal +$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates) +$(GEN): PRIVATE_CUSTOM_TOOL = \ + $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \ + -Ljava \ + -randroid.hardware:hardware/interfaces \ + -randroid.hidl:system/libhidl/transport \ + android.hardware.vr@1.0::IVr + +$(GEN): $(LOCAL_PATH)/IVr.hal + $(transform-generated-source) +LOCAL_GENERATED_SOURCES += $(GEN) +include $(BUILD_STATIC_JAVA_LIBRARY) + + + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/vr/1.0/IVr.hal b/vr/1.0/IVr.hal new file mode 100644 index 0000000..1f996e9 --- /dev/null +++ b/vr/1.0/IVr.hal
@@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 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.vr@1.0; + +interface IVr { + /** + * Convenience method to set up any state needed at runtime startup. This is + * called once from the VrManagerService during its boot phase. + */ + @callflow(next={"*"}) + @entry + @exit + init(); + + /** + * Set the VR mode state. Possible states of the enabled parameter are: + * false - VR mode is disabled, turn off all VR-specific settings. + * true - VR mode is enabled, turn on all VR-specific settings. + * + * This must be called whenever the the Android system enters or leaves VR + * mode. This will typically occur when the user switches to or from a VR + * application that is doing stereoscopic rendering. + */ + @callflow(next={"*"}) + @exit + setVrMode(bool enabled); +};
diff --git a/vr/1.0/default/Android.bp b/vr/1.0/default/Android.bp new file mode 100644 index 0000000..ddc1bfb --- /dev/null +++ b/vr/1.0/default/Android.bp
@@ -0,0 +1,36 @@ +cc_library_shared { + name: "android.hardware.vr@1.0-impl", + defaults: ["hidl_defaults"], + proprietary: true, + relative_install_path: "hw", + srcs: ["Vr.cpp"], + shared_libs: [ + "liblog", + "libcutils", + "libhardware", + "libbase", + "libcutils", + "libutils", + "libhidlbase", + "libhidltransport", + "android.hardware.vr@1.0", + ], +} + +cc_binary { + relative_install_path: "hw", + defaults: ["hidl_defaults"], + proprietary: true, + name: "android.hardware.vr@1.0-service", + init_rc: ["android.hardware.vr@1.0-service.rc"], + srcs: ["service.cpp"], + shared_libs: [ + "liblog", + "libdl", + "libutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "android.hardware.vr@1.0", + ], +}
diff --git a/vr/1.0/default/Vr.cpp b/vr/1.0/default/Vr.cpp new file mode 100644 index 0000000..4bba9eb --- /dev/null +++ b/vr/1.0/default/Vr.cpp
@@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "VrService" + +#include <log/log.h> + +#include <hardware/hardware.h> +#include <hardware/vr.h> + +#include "Vr.h" + +namespace android { +namespace hardware { +namespace vr { +namespace V1_0 { +namespace implementation { + +Vr::Vr(vr_module_t *device) : mDevice(device) {} + +// Methods from ::android::hardware::vr::V1_0::IVr follow. +Return<void> Vr::init() { + mDevice->init(mDevice); + return Void(); +} + +Return<void> Vr::setVrMode(bool enabled) { + mDevice->set_vr_mode(mDevice, enabled); + return Void(); +} + +IVr* HIDL_FETCH_IVr(const char * /*name*/) { + const hw_module_t *hw_module = NULL; + + int ret = hw_get_module(VR_HARDWARE_MODULE_ID, &hw_module); + if (ret == 0) { + return new Vr(reinterpret_cast<vr_module_t*>( + const_cast<hw_module_t*>(hw_module))); + } else { + ALOGE("hw_get_module %s failed: %d", VR_HARDWARE_MODULE_ID, ret); + return nullptr; + } +} + +} // namespace implementation +} // namespace V1_0 +} // namespace vr +} // namespace hardware +} // namespace android
diff --git a/vr/1.0/default/Vr.h b/vr/1.0/default/Vr.h new file mode 100644 index 0000000..dd5e764 --- /dev/null +++ b/vr/1.0/default/Vr.h
@@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 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. + */ +#ifndef ANDROID_HARDWARE_VR_V1_0_VR_H +#define ANDROID_HARDWARE_VR_V1_0_VR_H + +#include <android/hardware/vr/1.0/IVr.h> +#include <hardware/vr.h> +#include <hidl/MQDescriptor.h> + +namespace android { +namespace hardware { +namespace vr { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::vr::V1_0::IVr; +using ::android::hardware::Return; + +struct Vr : public IVr { + Vr(vr_module_t *device); + + // Methods from ::android::hardware::vr::V1_0::IVr follow. + Return<void> init() override; + Return<void> setVrMode(bool enabled) override; + + private: + vr_module_t *mDevice; +}; + +extern "C" IVr* HIDL_FETCH_IVr(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace vr +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_VR_V1_0_VR_H
diff --git a/vr/1.0/default/android.hardware.vr@1.0-service.rc b/vr/1.0/default/android.hardware.vr@1.0-service.rc new file mode 100644 index 0000000..ba43302 --- /dev/null +++ b/vr/1.0/default/android.hardware.vr@1.0-service.rc
@@ -0,0 +1,4 @@ +service vr-1-0 /vendor/bin/hw/android.hardware.vr@1.0-service + class hal + user system + group system readproc
diff --git a/vr/1.0/default/service.cpp b/vr/1.0/default/service.cpp new file mode 100644 index 0000000..22fb7d1 --- /dev/null +++ b/vr/1.0/default/service.cpp
@@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 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. + */ +#define LOG_TAG "android.hardware.vr@1.0-service" + +#include <android/hardware/vr/1.0/IVr.h> +#include <hidl/LegacySupport.h> + +// Generated HIDL files +using android::hardware::vr::V1_0::IVr; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation<IVr>(); +}
diff --git a/vr/1.0/vts/functional/Android.bp b/vr/1.0/vts/functional/Android.bp new file mode 100644 index 0000000..5d5a99a --- /dev/null +++ b/vr/1.0/vts/functional/Android.bp
@@ -0,0 +1,32 @@ +// +// Copyright (C) 2016 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. +// + +cc_test { + name: "VtsHalVrV1_0TargetTest", + defaults: ["hidl_defaults"], + srcs: ["VtsHalVrV1_0TargetTest.cpp"], + shared_libs: [ + "liblog", + "libhidlbase", + "libutils", + "android.hardware.vr@1.0", + ], + static_libs: ["VtsHalHidlTargetTestBase"], + cflags: [ + "-O0", + "-g", + ] +}
diff --git a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp new file mode 100644 index 0000000..a983731 --- /dev/null +++ b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
@@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 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. + */ + +#define LOG_TAG "vr_hidl_hal_test" +#include <android-base/logging.h> +#include <android/hardware/vr/1.0/IVr.h> +#include <android/log.h> +#include <VtsHalHidlTargetTestBase.h> +#include <hardware/vr.h> + +using ::android::hardware::vr::V1_0::IVr; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::sp; + +// The main test class for VR HIDL HAL. +class VrHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + void SetUp() override { + vr = ::testing::VtsHalHidlTargetTestBase::getService<IVr>(); + ASSERT_NE(vr, nullptr); + } + + void TearDown() override {} + + sp<IVr> vr; +}; + + +// A class for test environment setup (kept since this file is a template). +class VrHidlEnvironment : public ::testing::Environment { + public: + void SetUp() {} + void TearDown() {} + + private: +}; + +// Sanity check that Vr::init does not crash. +TEST_F(VrHidlTest, Init) { + EXPECT_TRUE(vr->init().isOk()); +} + +// Sanity check Vr::setVrMode is able to enable and disable VR mode. +TEST_F(VrHidlTest, SetVrMode) { + EXPECT_TRUE(vr->init().isOk()); + EXPECT_TRUE(vr->setVrMode(true).isOk()); + EXPECT_TRUE(vr->setVrMode(false).isOk()); +} + +// Sanity check that Vr::init and Vr::setVrMode can be used in any order. +TEST_F(VrHidlTest, ReInit) { + EXPECT_TRUE(vr->init().isOk()); + EXPECT_TRUE(vr->setVrMode(true).isOk()); + EXPECT_TRUE(vr->init().isOk()); + EXPECT_TRUE(vr->setVrMode(false).isOk()); + EXPECT_TRUE(vr->init().isOk()); + EXPECT_TRUE(vr->setVrMode(false).isOk()); +} + +int main(int argc, char **argv) { + ::testing::AddGlobalTestEnvironment(new VrHidlEnvironment); + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +}
diff --git a/vr/Android.bp b/vr/Android.bp new file mode 100644 index 0000000..ed19a37 --- /dev/null +++ b/vr/Android.bp
@@ -0,0 +1,6 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", + "1.0/default", + "1.0/vts/functional", +]