summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2024-03-07 06:10:54 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2024-03-07 06:10:54 +0000
commitd8f09cb61ae476969983d53e8adea12a26f1bc8b (patch)
treee93e2918c49035f8395a57e84565ba97cbc912ac
parent76167db6a857119b7c4746f9a92827290f81bfa2 (diff)
parent861942cb53f763292e57efdebe9195bd19a96d1d (diff)
downloadmedia-d8f09cb61ae476969983d53e8adea12a26f1bc8b.tar.gz
Merge "Merge Android 14 QPR2 to AOSP main" into main
-rw-r--r--audio/include/system/audio.h5
-rw-r--r--audio_utils/Android.bp13
-rw-r--r--audio_utils/benchmarks/Android.bp17
-rw-r--r--audio_utils/benchmarks/audio_mutex_benchmark.cpp337
-rw-r--r--audio_utils/fuzz/fdtostring_fuzzer/fdtostring_fuzzer.cpp6
-rw-r--r--audio_utils/include/audio_utils/FdToString.h193
-rw-r--r--audio_utils/include/audio_utils/mutex.h1360
-rw-r--r--audio_utils/include/audio_utils/safe_math.h57
-rw-r--r--audio_utils/include/audio_utils/threads.h146
-rw-r--r--audio_utils/mutex.cpp51
-rw-r--r--audio_utils/tests/Android.bp71
-rw-r--r--audio_utils/tests/audio_math_tests.cpp70
-rw-r--r--audio_utils/tests/audio_mutex_tests.cpp279
-rw-r--r--audio_utils/tests/audio_thread_tests.cpp64
-rw-r--r--audio_utils/tests/fdtostring_tests.cpp70
-rw-r--r--audio_utils/tests/generate_mutex_order.cpp32
-rw-r--r--audio_utils/threads.cpp89
-rw-r--r--camera/Android.bp2
-rw-r--r--camera/docs/CameraMetadataEnums.mako3
-rw-r--r--camera/docs/CameraMetadataKeys.mako6
-rw-r--r--camera/docs/camera_device_info.proto6
-rw-r--r--camera/docs/docs.html1330
-rw-r--r--camera/docs/metadata_definitions.xml529
-rw-r--r--camera/docs/metadata_definitions.xsd2
-rw-r--r--camera/docs/metadata_helpers.py5
-rw-r--r--camera/docs/metadata_model.py34
-rwxr-xr-xcamera/docs/metadata_parser_xml.py8
-rw-r--r--camera/docs/metadata_template.mako7
-rw-r--r--camera/include/system/camera_metadata_tags.h30
-rw-r--r--camera/src/camera_metadata_asserts.cpp30
-rw-r--r--camera/src/camera_metadata_tag_info.c161
31 files changed, 4673 insertions, 340 deletions
diff --git a/audio/include/system/audio.h b/audio/include/system/audio.h
index 2979ba3f..ffa8c69d 100644
--- a/audio/include/system/audio.h
+++ b/audio/include/system/audio.h
@@ -2441,6 +2441,11 @@ __END_DECLS
/* Query if HwModule supports variable Bluetooth latency control */
#define AUDIO_PARAMETER_BT_VARIABLE_LATENCY_SUPPORTED "isBtVariableLatencySupported"
+/* Reconfigure offloaded LE codec */
+#define AUDIO_PARAMETER_RECONFIG_LE "reconfigLe"
+/* Query if HwModule supports reconfiguration of offloaded LE codec */
+#define AUDIO_PARAMETER_LE_RECONFIG_SUPPORTED "isReconfigLeSupported"
+
/**
* For querying device supported encapsulation capabilities. All returned values are integer,
* which are bit fields composed from using encapsulation capability values as position bits.
diff --git a/audio_utils/Android.bp b/audio_utils/Android.bp
index 4b145d6a..45ae6e80 100644
--- a/audio_utils/Android.bp
+++ b/audio_utils/Android.bp
@@ -56,11 +56,13 @@ cc_library {
"Metadata.cpp",
"minifloat.c",
"mono_blend.cpp",
+ "mutex.cpp",
"power.cpp",
"PowerLog.cpp",
"primitives.c",
"roundup.c",
"sample.c",
+ "threads.cpp",
"hal_smoothness.c",
],
@@ -78,9 +80,13 @@ cc_library {
"libcutils",
"liblog",
"libutils",
+ "server_configurable_flags",
],
whole_static_libs: [
+ // if libaudioutils is added as a static lib AND flags are used in the utils object,
+ // then add server_configurable_flags as a shared lib.
+ "com.android.media.audioserver-aconfig-cc",
"libaudioutils_fastmath",
],
@@ -172,7 +178,10 @@ cc_library_static {
name: "libsndfile",
defaults: ["audio_utils_defaults"],
host_supported: true,
- srcs: ["tinysndfile.c"],
+ srcs: [
+ "primitives.c",
+ "tinysndfile.c",
+ ],
cflags: [
"-UHAVE_STDERR",
],
@@ -200,7 +209,7 @@ cc_library_static {
},
}
-cc_library_shared {
+cc_library {
name: "libaudiospdif",
host_supported: true,
defaults: ["audio_utils_defaults"],
diff --git a/audio_utils/benchmarks/Android.bp b/audio_utils/benchmarks/Android.bp
index cb7c41a0..1d7ab17d 100644
--- a/audio_utils/benchmarks/Android.bp
+++ b/audio_utils/benchmarks/Android.bp
@@ -9,6 +9,23 @@ package {
}
cc_benchmark {
+ name: "audio_mutex_benchmark",
+
+ srcs: ["audio_mutex_benchmark.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+}
+
+cc_benchmark {
name: "biquad_filter_benchmark",
host_supported: true,
diff --git a/audio_utils/benchmarks/audio_mutex_benchmark.cpp b/audio_utils/benchmarks/audio_mutex_benchmark.cpp
new file mode 100644
index 00000000..0280706b
--- /dev/null
+++ b/audio_utils/benchmarks/audio_mutex_benchmark.cpp
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <audio_utils/mutex.h>
+
+#include <benchmark/benchmark.h>
+#include <thread>
+#include <utils/Timers.h>
+
+/*
+On Pixel 7 U arm64-v8a
+
+Note: to bump up the scheduler clock frequency, one can use the toybox uclampset:
+$ adb shell uclampset -m 1024 /data/benchmarktest64/audio_mutex_benchmark/audio_mutex_benchmark
+
+For simplicity these tests use the regular invocation:
+$ atest audio_mutex_benchmark
+
+PI disabled
+Benchmark Time CPU Iteration
+audio_mutex_benchmark:
+ #BM_gettid 2.114707270012698 ns 2.1060503125712704 ns 316574041
+ #BM_systemTime 45.21805864916908 ns 45.026921817247256 ns 15550399
+ #BM_thread_8_variables 2.8218655987348464 ns 2.8084059508955304 ns 249245377
+ #BM_thread_local_8_variables 2.8193214063325636 ns 2.808094924629991 ns 249270437
+ #BM_StdMutexLockUnlock 18.284456262132316 ns 18.198265636345102 ns 38452720
+ #BM_AudioUtilsMutexLockUnlock 65.64444199789075 ns 65.27982033200155 ns 10727119
+ #BM_StdMutexInitializationLockUnlock 27.511005854186497 ns 27.400197055351832 ns 25576570
+ #BM_AudioUtilsMutexInitializationLockUnlock 80.13035874526041 ns 79.7832739530702 ns 8771433
+ #BM_StdMutexBlockingConditionVariable/threads:2 20162.129644197645 ns 23610.966860300927 ns 49578
+ #BM_AudioUtilsMutexBlockingConditionVariable/threads:2 15137.825614929703 ns 17290.483328991908 ns 53746
+ #BM_StdMutexScopedLockUnlock/threads:2 237.3259685000022 ns 471.24025449999993 ns 2000000
+ #BM_AudioUtilsMutexScopedLockUnlock/threads:2 1166.2574495961544 ns 2286.2857883742913 ns 696078
+ #BM_StdMutexReverseScopedLockUnlock/threads:2 78.13460285213144 ns 147.4075991604524 ns 4367114
+ #BM_AudioUtilsMutexReverseScopedLockUnlock/threads:2 652.4407601321186 ns 1260.665055303518 ns 729610
+ #BM_empty_while 0.3525216479999926 ns 0.35102758499999887 ns 1000000000
+
+PI enabled
+Benchmark Time CPU Iteration
+audio_mutex_benchmark:
+ #BM_gettid 2.1172475906830703 ns 2.1060892051984452 ns 320818635
+ #BM_systemTime 45.199132456479795 ns 45.00638566260978 ns 15548269
+ #BM_thread_8_variables 2.8225443366713554 ns 2.808487087931257 ns 249225013
+ #BM_thread_local_8_variables 2.821986069144024 ns 2.8082593311342396 ns 249257908
+ #BM_StdMutexLockUnlock 18.40590257629023 ns 18.181680287238002 ns 38568989
+ #BM_AudioUtilsMutexLockUnlock 67.93231825441279 ns 67.0807303508343 ns 10434985
+ #BM_StdMutexInitializationLockUnlock 27.68553624974349 ns 27.411678887121656 ns 25531919
+ #BM_AudioUtilsMutexInitializationLockUnlock 87.67312115717117 ns 86.83834669971819 ns 8058524
+ #BM_StdMutexBlockingConditionVariable/threads:2 17272.46593515828 ns 19906.88809450987 ns 78468
+ #BM_AudioUtilsMutexBlockingConditionVariable/threads:2 32005.869201264206 ns 37545.03395758123 ns 44320
+ #BM_StdMutexScopedLockUnlock/threads:2 486.46992430399723 ns 956.4308063689062 ns 1080374
+ #BM_AudioUtilsMutexScopedLockUnlock/threads:2 2054.297687080403 ns 2381.4833355667856 ns 462662
+ #BM_StdMutexReverseScopedLockUnlock/threads:2 82.48454541925697 ns 156.5002537866742 ns 3502942
+ #BM_AudioUtilsMutexReverseScopedLockUnlock/threads:2 7202.760827499759 ns 8601.367344999997 ns 200000
+ #BM_empty_while 0.3630271000000107 ns 0.3611862729999995 ns 1000000000
+
+*/
+
+// ---
+
+// Benchmark gettid(). The mutex class uses this to get the linux thread id.
+static void BM_gettid(benchmark::State &state) {
+ int32_t value = 0;
+ while (state.KeepRunning()) {
+ value ^= android::audio_utils::gettid_wrapper(); // ensure the return value used.
+ }
+ ALOGD("%s: value:%d", __func__, value);
+}
+
+BENCHMARK(BM_gettid);
+
+// Benchmark systemTime(). The mutex class uses this for timing.
+static void BM_systemTime(benchmark::State &state) {
+ int64_t value = 0;
+ while (state.KeepRunning()) {
+ value ^= systemTime();
+ }
+ ALOGD("%s: value:%lld", __func__, (long long)value);
+}
+
+BENCHMARK(BM_systemTime);
+
+// Benchmark access to 8 thread local storage variables by compiler built_in __thread.
+__thread volatile int tls_value1 = 1;
+__thread volatile int tls_value2 = 2;
+__thread volatile int tls_value3 = 3;
+__thread volatile int tls_value4 = 4;
+__thread volatile int tls_value5 = 5;
+__thread volatile int tls_value6 = 6;
+__thread volatile int tls_value7 = 7;
+__thread volatile int tls_value8 = 8;
+
+static void BM_thread_8_variables(benchmark::State &state) {
+ while (state.KeepRunning()) {
+ tls_value1 ^= tls_value1 ^ tls_value2 ^ tls_value3 ^ tls_value4 ^
+ tls_value5 ^ tls_value6 ^ tls_value7 ^ tls_value8;
+ }
+ ALOGD("%s: value:%d", __func__, tls_value1);
+}
+
+BENCHMARK(BM_thread_8_variables);
+
+// Benchmark access to 8 thread local storage variables through the
+// the C/C++ 11 standard thread_local.
+thread_local volatile int tlsa_value1 = 1;
+thread_local volatile int tlsa_value2 = 2;
+thread_local volatile int tlsa_value3 = 3;
+thread_local volatile int tlsa_value4 = 4;
+thread_local volatile int tlsa_value5 = 5;
+thread_local volatile int tlsa_value6 = 6;
+thread_local volatile int tlsa_value7 = 7;
+thread_local volatile int tlsa_value8 = 8;
+
+static void BM_thread_local_8_variables(benchmark::State &state) {
+ while (state.KeepRunning()) {
+ tlsa_value1 ^= tlsa_value1 ^ tlsa_value2 ^ tlsa_value3 ^ tlsa_value4 ^
+ tlsa_value5 ^ tlsa_value6 ^ tlsa_value7 ^ tlsa_value8;
+ }
+ ALOGD("%s: value:%d", __func__, tlsa_value1);
+}
+
+BENCHMARK(BM_thread_local_8_variables);
+
+// ---
+
+template <typename Mutex>
+void MutexLockUnlock(benchmark::State& state) {
+ Mutex m;
+ while (state.KeepRunning()) {
+ m.lock();
+ m.unlock();
+ }
+}
+
+static void BM_StdMutexLockUnlock(benchmark::State &state) {
+ MutexLockUnlock<std::mutex>(state);
+}
+
+// Benchmark repeated mutex lock/unlock from a single thread
+// using std::mutex.
+BENCHMARK(BM_StdMutexLockUnlock);
+
+static void BM_AudioUtilsMutexLockUnlock(benchmark::State &state) {
+ MutexLockUnlock<android::audio_utils::mutex>(state);
+}
+
+// Benchmark repeated mutex lock/unlock from a single thread
+// using audio_utils::mutex. This will differ when priority inheritance
+// is used or not.
+BENCHMARK(BM_AudioUtilsMutexLockUnlock);
+
+// ---
+
+template <typename Mutex>
+void MutexInitializationLockUnlock(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ Mutex m;
+ m.lock();
+ m.unlock();
+ }
+}
+
+static void BM_StdMutexInitializationLockUnlock(benchmark::State &state) {
+ MutexInitializationLockUnlock<std::mutex>(state);
+}
+
+// Benchmark repeated mutex creation then lock/unlock from a single thread
+// using std::mutex.
+BENCHMARK(BM_StdMutexInitializationLockUnlock);
+
+static void BM_AudioUtilsMutexInitializationLockUnlock(benchmark::State &state) {
+ MutexInitializationLockUnlock<android::audio_utils::mutex>(state);
+}
+
+// Benchmark repeated mutex creation then lock/unlock from a single thread
+// using audio_utils::mutex. This will differ when priority inheritance
+// is used or not.
+BENCHMARK(BM_AudioUtilsMutexInitializationLockUnlock);
+
+// ---
+
+static constexpr size_t THREADS = 2;
+
+template <typename Mutex, typename UniqueLock, typename ConditionVariable>
+class MutexBlockingConditionVariable {
+ Mutex m;
+ ConditionVariable cv[THREADS];
+ bool wake[THREADS];
+
+public:
+ void run(benchmark::State& state) {
+ const size_t local = state.thread_index();
+ const size_t remote = (local + 1) % THREADS;
+ if (local == 0) wake[local] = true;
+ for (auto _ : state) {
+ UniqueLock ul(m);
+ cv[local].wait(ul, [&]{ return wake[local]; });
+ wake[remote] = true;
+ wake[local] = false;
+ cv[remote].notify_one();
+ }
+ UniqueLock ul(m);
+ wake[remote] = true;
+ cv[remote].notify_one();
+ }
+};
+
+MutexBlockingConditionVariable<std::mutex,
+ std::unique_lock<std::mutex>,
+ std::condition_variable> CvStd;
+
+static void BM_StdMutexBlockingConditionVariable(benchmark::State &state) {
+ CvStd.run(state);
+}
+
+// Benchmark 2 threads that use condition variables to wake each other up,
+// where only one thread is active at a given time. This benchmark
+// uses std::mutex, std::unique_lock, and std::condition_variable.
+BENCHMARK(BM_StdMutexBlockingConditionVariable)->Threads(THREADS);
+
+MutexBlockingConditionVariable<android::audio_utils::mutex,
+ android::audio_utils::unique_lock,
+ android::audio_utils::condition_variable> CvAu;
+
+static void BM_AudioUtilsMutexBlockingConditionVariable(benchmark::State &state) {
+ CvAu.run(state);
+}
+
+// Benchmark 2 threads that use condition variables to wake each other up,
+// where only one thread is active at a given time. This benchmark
+// uses audio_utils::mutex, audio_utils::unique_lock, and audio_utils::condition_variable.
+//
+// Priority inheritance mutexes will affect the performance of this benchmark.
+BENCHMARK(BM_AudioUtilsMutexBlockingConditionVariable)->Threads(THREADS);
+
+// ---
+
+template <typename Mutex, typename ScopedLock>
+class MutexScopedLockUnlock {
+ const bool reverse_;
+ Mutex m1_, m2_;
+ int counter_ = 0;
+
+public:
+ MutexScopedLockUnlock(bool reverse = false) : reverse_(reverse) {}
+
+ void run(benchmark::State& state) {
+ const size_t index = state.thread_index();
+ for (auto _ : state) {
+ if (!reverse_ || index & 1) {
+ ScopedLock s1(m1_, m2_);
+ ++counter_;
+ } else {
+ ScopedLock s1(m2_, m1_);
+ ++counter_;
+ }
+ }
+ }
+};
+
+MutexScopedLockUnlock<std::mutex,
+ std::scoped_lock<std::mutex, std::mutex>> ScopedStd;
+
+static void BM_StdMutexScopedLockUnlock(benchmark::State &state) {
+ ScopedStd.run(state);
+}
+
+// Benchmark scoped_lock where two threads try to obtain the
+// same 2 locks with the same initial acquisition order.
+// This uses std::mutex, std::scoped_lock.
+BENCHMARK(BM_StdMutexScopedLockUnlock)->Threads(THREADS);
+
+MutexScopedLockUnlock<android::audio_utils::mutex,
+ android::audio_utils::scoped_lock<
+ android::audio_utils::mutex, android::audio_utils::mutex>> ScopedAu;
+
+static void BM_AudioUtilsMutexScopedLockUnlock(benchmark::State &state) {
+ ScopedAu.run(state);
+}
+
+// Benchmark scoped_lock where two threads try to obtain the
+// same 2 locks with the same initial acquisition order.
+// This uses audio_utils::mutex and audio_utils::scoped_lock.
+//
+// Priority inheritance mutexes will affect the performance of this benchmark.
+BENCHMARK(BM_AudioUtilsMutexScopedLockUnlock)->Threads(THREADS);
+
+MutexScopedLockUnlock<std::mutex,
+ std::scoped_lock<std::mutex, std::mutex>> ReverseScopedStd(true);
+
+static void BM_StdMutexReverseScopedLockUnlock(benchmark::State &state) {
+ ReverseScopedStd.run(state);
+}
+
+// Benchmark scoped_lock with odd thread having reversed scoped_lock mutex acquisition order.
+// This uses std::mutex, std::scoped_lock.
+BENCHMARK(BM_StdMutexReverseScopedLockUnlock)->Threads(THREADS);
+
+MutexScopedLockUnlock<android::audio_utils::mutex,
+ android::audio_utils::scoped_lock<
+ android::audio_utils::mutex, android::audio_utils::mutex>> ReverseScopedAu(true);
+
+static void BM_AudioUtilsMutexReverseScopedLockUnlock(benchmark::State &state) {
+ ReverseScopedAu.run(state);
+}
+
+// Benchmark scoped_lock with odd thread having reversed scoped_lock mutex acquisition order.
+// This uses audio_utils::mutex and audio_utils::scoped_lock.
+//
+// Priority inheritance mutexes will affect the performance of this benchmark.
+BENCHMARK(BM_AudioUtilsMutexReverseScopedLockUnlock)->Threads(THREADS);
+
+static void BM_empty_while(benchmark::State &state) {
+
+ while (state.KeepRunning()) {
+ ;
+ }
+ ALOGD("%s", android::audio_utils::mutex::all_stats_to_string().c_str());
+}
+
+// Benchmark to see the cost of doing nothing.
+BENCHMARK(BM_empty_while);
+
+BENCHMARK_MAIN();
diff --git a/audio_utils/fuzz/fdtostring_fuzzer/fdtostring_fuzzer.cpp b/audio_utils/fuzz/fdtostring_fuzzer/fdtostring_fuzzer.cpp
index 090ef5e2..bfee8789 100644
--- a/audio_utils/fuzz/fdtostring_fuzzer/fdtostring_fuzzer.cpp
+++ b/audio_utils/fuzz/fdtostring_fuzzer/fdtostring_fuzzer.cpp
@@ -30,10 +30,10 @@ extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size) {
const std::string PREFIX{data_str.substr(0, 3)};
const std::string TEST_STRING{data_str.substr(3)+"\n"};
- FdToString fdToString(PREFIX);
- const int fd = fdToString.fd();
+ auto writer = FdToString::createWriter(PREFIX);
+ const int fd = writer->borrowFdUnsafe();
write(fd, TEST_STRING.c_str(), TEST_STRING.size());
- (void)fdToString.getStringAndClose();
+ (void)FdToString::closeWriterAndGetString(std::move(*writer));
return 0;
}
diff --git a/audio_utils/include/audio_utils/FdToString.h b/audio_utils/include/audio_utils/FdToString.h
index 4ca0b8d4..64cb875d 100644
--- a/audio_utils/include/audio_utils/FdToString.h
+++ b/audio_utils/include/audio_utils/FdToString.h
@@ -17,12 +17,18 @@
#ifndef ANDROID_AUDIO_FD_TO_STRING_H
#define ANDROID_AUDIO_FD_TO_STRING_H
+#include <android-base/unique_fd.h>
#include <fcntl.h>
-#include <future>
#include <poll.h>
-#include <sstream>
#include <unistd.h>
#include <utils/Timers.h>
+#include <chrono>
+#include <future>
+#include <iostream>
+#include <optional>
+#include <sstream>
+#include <string>
+#include <string_view>
#include "clock.h"
@@ -30,22 +36,20 @@ namespace android {
namespace audio_utils {
/**
- * FdToString
+ * FdToStringOldImpl
*
* Captures string data written to a file descriptor.
* The class will furnish a writable file descriptor by fd().
- * The string may be read through getStringAndClose().
+ * The string may be read through closeAndGetString().
*/
-
-class FdToString {
-public:
+class FdToStringOldImpl {
+ public:
/**
* \param prefix is the prefix string prepended to each new line.
* \param timeoutMs is the total timeout to wait for obtaining data in milliseconds.
*/
- explicit FdToString(const std::string &prefix = "- ", int timeoutMs = 200)
- : mPrefix(prefix)
- , mTimeoutTimeNs(systemTime() + timeoutMs * NANOS_PER_MILLISECOND) {
+ explicit FdToStringOldImpl(const std::string& prefix = "- ", int timeoutMs = 200)
+ : mPrefix(prefix), mTimeoutTimeNs(systemTime() + timeoutMs * NANOS_PER_MILLISECOND) {
const int status = pipe2(mPipeFd, O_CLOEXEC);
if (status == 0) {
mOutput = std::async(std::launch::async, reader, mPipeFd[0], mTimeoutTimeNs, mPrefix);
@@ -53,8 +57,8 @@ public:
// on initialization failure fd() returns -1.
}
- ~FdToString() {
- for (auto &fd : mPipeFd) {
+ ~FdToStringOldImpl() {
+ for (auto& fd : mPipeFd) {
if (fd >= 0) {
close(fd);
fd = -1;
@@ -64,21 +68,19 @@ public:
/**
* Returns the write end of the pipe as a file descriptor or -1 if invalid or already closed.
- *
* Do not close this fd directly as this class should own the fd. Instead, use
- * getStringAndClose() to close the fd and return the string.
+ * closeAndGetString() to close the fd and return the string.
*/
- int fd() const {
- return mPipeFd[1];
- }
+ int borrowFdUnsafe() const { return mPipeFd[1]; }
/**
- * Returns the string representation of data written to the fd.
+ * Returns the string representation of data written to the fd. Awaits reader thread.
+ *
+ * All writers should have returned by this point.
*
- * An empty string is returned on failure (or timeout). It is acceptable to call this
- * method multiple times to obtain the final string; the fd is closed after the first call.
+ * An empty string is returned on initialization failure or timeout. Closes fd.
*/
- std::string getStringAndClose() {
+ std::string closeAndGetString() {
if (!mOutput.valid()) return "";
if (mPipeFd[1] >= 0) {
close(mPipeFd[1]);
@@ -89,7 +91,7 @@ public:
return status == std::future_status::ready ? mOutput.get() : "";
}
-private:
+ private:
static std::string reader(int fd, int64_t timeoutTimeNs, std::string prefix) {
char buf[4096];
int red;
@@ -98,18 +100,19 @@ private:
while (true) {
struct pollfd pfd = {
- .fd = fd,
- .events = POLLIN | POLLRDHUP,
+ .fd = fd,
+ .events = POLLIN | POLLRDHUP,
};
const int waitMs = toMillisecondTimeoutDelay(systemTime(), timeoutTimeNs);
// ALOGD("waitMs: %d", waitMs);
if (waitMs <= 0) break;
const int retval = poll(&pfd, 1 /* nfds*/, waitMs);
- if (retval <= 0 || (pfd.revents & POLLIN) != POLLIN) break; // error or timeout
- // data is available
+ // error, timeout, or hangup (without data to read)
+ if (retval <= 0 || (pfd.revents & POLLIN) != POLLIN) break;
+ // data should be available
if ((red = read(fd, buf, sizeof(buf))) <= 0) break;
char *delim, *bptr = buf;
- while (!prefix.empty() && (delim = (char *)memchr(bptr, '\n', red)) != nullptr) {
+ while (!prefix.empty() && (delim = (char*)memchr(bptr, '\n', red)) != nullptr) {
if (requiresPrefix) ss << prefix;
const size_t line = delim - bptr + 1;
ss.write(bptr, line);
@@ -132,7 +135,137 @@ private:
std::future<std::string> mOutput;
};
-} // namespace audio_utils
-} // namespace android
+/**
+ * Launch reader task which accumulates data written to the fd that this class exposes.
+ * Usage as follows:
+ * {
+ * writer = FdToString::createWriter(); // fork point, reader launched
+ * sendFdToWriters(writer.borrowFdUnsafe()); // fd is safe while writer is valid
+ * st = FdToString::closeWriterAndGetString(std::move(writer));
+ * // join point (writers must be done)
+ * } // writer dtor closes fd, joins reader if close not called
+ *
+ * This class expects that the write fd is unduped when close is called, otherwise the reader will
+ * always hit the timeout. We implicitly trust that the borrowed fd won't be duped (or that its
+ * dupes will be closed by closeWriterAndGetString()).
+ * Note, the reader closes the fd to signal which closes the read end of the pipe. If the writer is
+ * living in a process without signal(SIGPIPE, SIGIGN), they will crash.
+ */
+class FdToString {
+ public:
+ class Writer {
+ public:
+ /**
+ * Returns the write end of the pipe as a file descriptor.
+ * Non-Owning reference! This object must be valid to keep accessing the fd.
+ * Do not close this fd directly as this class should own the fd.
+ * Leaking dupes of this fd will keep the reader alive.
+ * Use closeWriterAndGetString(Writer&& w) to consume this object and return the string.
+ * The fd returned by this method is invalid after this point.
+ */
+ int borrowFdUnsafe() const { return mWriteFd.get(); }
+
+ const android::base::unique_fd& getFd() const { return mWriteFd; }
+
+ private:
+ friend FdToString;
+ // Pre-condition: fd and future both valid. Should only be called from create.
+ Writer(android::base::unique_fd writeFd, std::future<std::string> output)
+ : mOutput(std::move(output)), mWriteFd(std::move(writeFd)) {}
+
+ std::future<std::string> mOutput;
+ android::base::unique_fd mWriteFd; // order important! must be destroyed first to join
+ };
+
+ public:
+ /**
+ * Factory method for Writer object. Launches the async reader.
+ * \param prefix is the prefix string prepended to each new line.
+ * \param timeoutMs is the total timeout to wait for obtaining data in milliseconds.
+ * \returns nullopt on init error.
+ */
+ static std::optional<Writer> createWriter(
+ std::string_view prefix_ = "- ",
+ std::chrono::milliseconds timeout = std::chrono::milliseconds{200}) {
+ android::base::unique_fd readFd, writeFd;
+ if (!android::base::Pipe(&readFd, &writeFd)) return {};
+ const auto flags = fcntl(readFd.get(), F_GETFL);
+ if (flags < 0) return {};
+ // Set (only) the reader as non-blocking. We want to only read until the deadline.
+ if (fcntl(readFd, F_SETFL, flags | O_NONBLOCK) < 0) return {};
+ const auto deadline = systemTime() + std::chrono::nanoseconds{timeout}.count();
+ // Launch async reader task, will return after deadline
+ return Writer{
+ std::move(writeFd),
+ std::async(std::launch::async,
+ // reader task to follow, logically oneshot
+ [fd = std::move(readFd), deadline,
+ prefix = std::string{prefix_}]() mutable {
+ char buf[4096];
+ std::string out;
+ bool requiresPrefix = true;
+
+ while (true) {
+ struct pollfd pfd = {
+ .fd = fd.get(),
+ .events = POLLIN | POLLRDHUP,
+ };
+ const int waitMs =
+ toMillisecondTimeoutDelay(systemTime(), deadline);
+ if (waitMs <= 0) break;
+ const int retval = poll(&pfd, 1 /* nfds*/, waitMs);
+ // break on error or timeout
+ if (retval <= 0 || (pfd.revents & POLLIN) != POLLIN) break;
+ // data is available
+ int red = read(fd, buf, sizeof(buf));
+ if (red < 0) {
+ break;
+ } else if (red == 0) {
+ continue;
+ }
+
+ std::string_view sv{buf, static_cast<size_t>(red)};
+
+ if (!prefix.empty()) {
+ size_t ind;
+ while ((ind = sv.find('\n', 0)) != std::string_view::npos) {
+ if (requiresPrefix) {
+ out.append(prefix);
+ }
+ out.append(sv.data(), ind + 1);
+ sv.remove_prefix(ind + 1);
+ requiresPrefix = true;
+ }
+ if (sv.length() > 0) {
+ out.append(sv);
+ requiresPrefix = false;
+ }
+ } else {
+ out.append(sv);
+ }
+ }
+ // Explicit clear, because state is kept until future consumption
+ fd.reset();
+ return out;
+ })};
+ }
+
+ /**
+ * Closes the write side. Returns the string representation of data written to the fd.
+ * Awaits reader thread.
+ *
+ * All writers should have returned by this point.
+ *
+ */
+ static std::string closeWriterAndGetString(Writer&& writer) {
+ // Closes the fd, which finishes the reader
+ writer.mWriteFd.reset();
+ // moved out of future + NVRO
+ return writer.mOutput.get();
+ }
+};
+
+} // namespace audio_utils
+} // namespace android
-#endif // !ANDROID_AUDIO_FD_TO_STRING_H
+#endif // !ANDROID_AUDIO_FD_TO_STRING_H
diff --git a/audio_utils/include/audio_utils/mutex.h b/audio_utils/include/audio_utils/mutex.h
index 674228ac..c78860ff 100644
--- a/audio_utils/include/audio_utils/mutex.h
+++ b/audio_utils/include/audio_utils/mutex.h
@@ -17,9 +17,21 @@
#pragma once
#include <android-base/thread_annotations.h>
+#include <audio_utils/threads.h>
#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <map>
+#include <memory>
#include <mutex>
+#include <sys/syscall.h>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
#pragma push_macro("LOG_TAG")
#undef LOG_TAG
@@ -27,6 +39,892 @@
namespace android::audio_utils {
+// Define global capabilities for thread-safety annotation.
+//
+// These can be manually modified, or
+// compile generate_mutex_order.cpp in the tests directory
+// to generate this.
+
+// --- Begin generated section
+
+// Lock order
+enum class MutexOrder : uint32_t {
+ kEffectHandle_Mutex = 0,
+ kEffectBase_PolicyMutex = 1,
+ kAudioFlinger_Mutex = 2,
+ kAudioFlinger_HardwareMutex = 3,
+ kDeviceEffectManager_Mutex = 4,
+ kPatchCommandThread_Mutex = 5,
+ kThreadBase_Mutex = 6,
+ kAudioFlinger_ClientMutex = 7,
+ kMelReporter_Mutex = 8,
+ kEffectChain_Mutex = 9,
+ kDeviceEffectProxy_ProxyMutex = 10,
+ kEffectBase_Mutex = 11,
+ kAudioFlinger_UnregisteredWritersMutex = 12,
+ kAsyncCallbackThread_Mutex = 13,
+ kConfigEvent_Mutex = 14,
+ kOutputTrack_TrackMetadataMutex = 15,
+ kPassthruPatchRecord_ReadMutex = 16,
+ kPatchCommandThread_ListenerMutex = 17,
+ kPlaybackThread_AudioTrackCbMutex = 18,
+ kMediaLogNotifier_Mutex = 19,
+ kOtherMutex = 20,
+ kSize = 21,
+};
+
+// Lock by name
+inline constexpr const char* const gMutexNames[] = {
+ "EffectHandle_Mutex",
+ "EffectBase_PolicyMutex",
+ "AudioFlinger_Mutex",
+ "AudioFlinger_HardwareMutex",
+ "DeviceEffectManager_Mutex",
+ "PatchCommandThread_Mutex",
+ "ThreadBase_Mutex",
+ "AudioFlinger_ClientMutex",
+ "MelReporter_Mutex",
+ "EffectChain_Mutex",
+ "DeviceEffectProxy_ProxyMutex",
+ "EffectBase_Mutex",
+ "AudioFlinger_UnregisteredWritersMutex",
+ "AsyncCallbackThread_Mutex",
+ "ConfigEvent_Mutex",
+ "OutputTrack_TrackMetadataMutex",
+ "PassthruPatchRecord_ReadMutex",
+ "PatchCommandThread_ListenerMutex",
+ "PlaybackThread_AudioTrackCbMutex",
+ "MediaLogNotifier_Mutex",
+ "OtherMutex",
+};
+
+// Forward declarations
+class AudioMutexAttributes;
+template <typename T> class mutex_impl;
+using mutex = mutex_impl<AudioMutexAttributes>;
+
+// Capabilities in priority order
+// (declaration only, value is nullptr)
+inline mutex* EffectHandle_Mutex;
+inline mutex* EffectBase_PolicyMutex
+ ACQUIRED_AFTER(android::audio_utils::EffectHandle_Mutex);
+inline mutex* AudioFlinger_Mutex
+ ACQUIRED_AFTER(android::audio_utils::EffectBase_PolicyMutex);
+inline mutex* AudioFlinger_HardwareMutex
+ ACQUIRED_AFTER(android::audio_utils::AudioFlinger_Mutex);
+inline mutex* DeviceEffectManager_Mutex
+ ACQUIRED_AFTER(android::audio_utils::AudioFlinger_HardwareMutex);
+inline mutex* PatchCommandThread_Mutex
+ ACQUIRED_AFTER(android::audio_utils::DeviceEffectManager_Mutex);
+inline mutex* ThreadBase_Mutex
+ ACQUIRED_AFTER(android::audio_utils::PatchCommandThread_Mutex);
+inline mutex* AudioFlinger_ClientMutex
+ ACQUIRED_AFTER(android::audio_utils::ThreadBase_Mutex);
+inline mutex* MelReporter_Mutex
+ ACQUIRED_AFTER(android::audio_utils::AudioFlinger_ClientMutex);
+inline mutex* EffectChain_Mutex
+ ACQUIRED_AFTER(android::audio_utils::MelReporter_Mutex);
+inline mutex* DeviceEffectProxy_ProxyMutex
+ ACQUIRED_AFTER(android::audio_utils::EffectChain_Mutex);
+inline mutex* EffectBase_Mutex
+ ACQUIRED_AFTER(android::audio_utils::DeviceEffectProxy_ProxyMutex);
+inline mutex* AudioFlinger_UnregisteredWritersMutex
+ ACQUIRED_AFTER(android::audio_utils::EffectBase_Mutex);
+inline mutex* AsyncCallbackThread_Mutex
+ ACQUIRED_AFTER(android::audio_utils::AudioFlinger_UnregisteredWritersMutex);
+inline mutex* ConfigEvent_Mutex
+ ACQUIRED_AFTER(android::audio_utils::AsyncCallbackThread_Mutex);
+inline mutex* OutputTrack_TrackMetadataMutex
+ ACQUIRED_AFTER(android::audio_utils::ConfigEvent_Mutex);
+inline mutex* PassthruPatchRecord_ReadMutex
+ ACQUIRED_AFTER(android::audio_utils::OutputTrack_TrackMetadataMutex);
+inline mutex* PatchCommandThread_ListenerMutex
+ ACQUIRED_AFTER(android::audio_utils::PassthruPatchRecord_ReadMutex);
+inline mutex* PlaybackThread_AudioTrackCbMutex
+ ACQUIRED_AFTER(android::audio_utils::PatchCommandThread_ListenerMutex);
+inline mutex* MediaLogNotifier_Mutex
+ ACQUIRED_AFTER(android::audio_utils::PlaybackThread_AudioTrackCbMutex);
+inline mutex* OtherMutex
+ ACQUIRED_AFTER(android::audio_utils::MediaLogNotifier_Mutex);
+
+// Exclusion by capability
+#define EXCLUDES_BELOW_OtherMutex
+#define EXCLUDES_OtherMutex \
+ EXCLUDES(android::audio_utils::OtherMutex) \
+ EXCLUDES_BELOW_OtherMutex
+
+#define EXCLUDES_BELOW_MediaLogNotifier_Mutex \
+ EXCLUDES_OtherMutex
+#define EXCLUDES_MediaLogNotifier_Mutex \
+ EXCLUDES(android::audio_utils::MediaLogNotifier_Mutex) \
+ EXCLUDES_BELOW_MediaLogNotifier_Mutex
+
+#define EXCLUDES_BELOW_PlaybackThread_AudioTrackCbMutex \
+ EXCLUDES_MediaLogNotifier_Mutex
+#define EXCLUDES_PlaybackThread_AudioTrackCbMutex \
+ EXCLUDES(android::audio_utils::PlaybackThread_AudioTrackCbMutex) \
+ EXCLUDES_BELOW_PlaybackThread_AudioTrackCbMutex
+
+#define EXCLUDES_BELOW_PatchCommandThread_ListenerMutex \
+ EXCLUDES_PlaybackThread_AudioTrackCbMutex
+#define EXCLUDES_PatchCommandThread_ListenerMutex \
+ EXCLUDES(android::audio_utils::PatchCommandThread_ListenerMutex) \
+ EXCLUDES_BELOW_PatchCommandThread_ListenerMutex
+
+#define EXCLUDES_BELOW_PassthruPatchRecord_ReadMutex \
+ EXCLUDES_PatchCommandThread_ListenerMutex
+#define EXCLUDES_PassthruPatchRecord_ReadMutex \
+ EXCLUDES(android::audio_utils::PassthruPatchRecord_ReadMutex) \
+ EXCLUDES_BELOW_PassthruPatchRecord_ReadMutex
+
+#define EXCLUDES_BELOW_OutputTrack_TrackMetadataMutex \
+ EXCLUDES_PassthruPatchRecord_ReadMutex
+#define EXCLUDES_OutputTrack_TrackMetadataMutex \
+ EXCLUDES(android::audio_utils::OutputTrack_TrackMetadataMutex) \
+ EXCLUDES_BELOW_OutputTrack_TrackMetadataMutex
+
+#define EXCLUDES_BELOW_ConfigEvent_Mutex \
+ EXCLUDES_OutputTrack_TrackMetadataMutex
+#define EXCLUDES_ConfigEvent_Mutex \
+ EXCLUDES(android::audio_utils::ConfigEvent_Mutex) \
+ EXCLUDES_BELOW_ConfigEvent_Mutex
+
+#define EXCLUDES_BELOW_AsyncCallbackThread_Mutex \
+ EXCLUDES_ConfigEvent_Mutex
+#define EXCLUDES_AsyncCallbackThread_Mutex \
+ EXCLUDES(android::audio_utils::AsyncCallbackThread_Mutex) \
+ EXCLUDES_BELOW_AsyncCallbackThread_Mutex
+
+#define EXCLUDES_BELOW_AudioFlinger_UnregisteredWritersMutex \
+ EXCLUDES_AsyncCallbackThread_Mutex
+#define EXCLUDES_AudioFlinger_UnregisteredWritersMutex \
+ EXCLUDES(android::audio_utils::AudioFlinger_UnregisteredWritersMutex) \
+ EXCLUDES_BELOW_AudioFlinger_UnregisteredWritersMutex
+
+#define EXCLUDES_BELOW_EffectBase_Mutex \
+ EXCLUDES_AudioFlinger_UnregisteredWritersMutex
+#define EXCLUDES_EffectBase_Mutex \
+ EXCLUDES(android::audio_utils::EffectBase_Mutex) \
+ EXCLUDES_BELOW_EffectBase_Mutex
+
+#define EXCLUDES_BELOW_DeviceEffectProxy_ProxyMutex \
+ EXCLUDES_EffectBase_Mutex
+#define EXCLUDES_DeviceEffectProxy_ProxyMutex \
+ EXCLUDES(android::audio_utils::DeviceEffectProxy_ProxyMutex) \
+ EXCLUDES_BELOW_DeviceEffectProxy_ProxyMutex
+
+#define EXCLUDES_BELOW_EffectChain_Mutex \
+ EXCLUDES_DeviceEffectProxy_ProxyMutex
+#define EXCLUDES_EffectChain_Mutex \
+ EXCLUDES(android::audio_utils::EffectChain_Mutex) \
+ EXCLUDES_BELOW_EffectChain_Mutex
+
+#define EXCLUDES_BELOW_MelReporter_Mutex \
+ EXCLUDES_EffectChain_Mutex
+#define EXCLUDES_MelReporter_Mutex \
+ EXCLUDES(android::audio_utils::MelReporter_Mutex) \
+ EXCLUDES_BELOW_MelReporter_Mutex
+
+#define EXCLUDES_BELOW_AudioFlinger_ClientMutex \
+ EXCLUDES_MelReporter_Mutex
+#define EXCLUDES_AudioFlinger_ClientMutex \
+ EXCLUDES(android::audio_utils::AudioFlinger_ClientMutex) \
+ EXCLUDES_BELOW_AudioFlinger_ClientMutex
+
+#define EXCLUDES_BELOW_ThreadBase_Mutex \
+ EXCLUDES_AudioFlinger_ClientMutex
+#define EXCLUDES_ThreadBase_Mutex \
+ EXCLUDES(android::audio_utils::ThreadBase_Mutex) \
+ EXCLUDES_BELOW_ThreadBase_Mutex
+
+#define EXCLUDES_BELOW_PatchCommandThread_Mutex \
+ EXCLUDES_ThreadBase_Mutex
+#define EXCLUDES_PatchCommandThread_Mutex \
+ EXCLUDES(android::audio_utils::PatchCommandThread_Mutex) \
+ EXCLUDES_BELOW_PatchCommandThread_Mutex
+
+#define EXCLUDES_BELOW_DeviceEffectManager_Mutex \
+ EXCLUDES_PatchCommandThread_Mutex
+#define EXCLUDES_DeviceEffectManager_Mutex \
+ EXCLUDES(android::audio_utils::DeviceEffectManager_Mutex) \
+ EXCLUDES_BELOW_DeviceEffectManager_Mutex
+
+#define EXCLUDES_BELOW_AudioFlinger_HardwareMutex \
+ EXCLUDES_DeviceEffectManager_Mutex
+#define EXCLUDES_AudioFlinger_HardwareMutex \
+ EXCLUDES(android::audio_utils::AudioFlinger_HardwareMutex) \
+ EXCLUDES_BELOW_AudioFlinger_HardwareMutex
+
+#define EXCLUDES_BELOW_AudioFlinger_Mutex \
+ EXCLUDES_AudioFlinger_HardwareMutex
+#define EXCLUDES_AudioFlinger_Mutex \
+ EXCLUDES(android::audio_utils::AudioFlinger_Mutex) \
+ EXCLUDES_BELOW_AudioFlinger_Mutex
+
+#define EXCLUDES_BELOW_EffectBase_PolicyMutex \
+ EXCLUDES_AudioFlinger_Mutex
+#define EXCLUDES_EffectBase_PolicyMutex \
+ EXCLUDES(android::audio_utils::EffectBase_PolicyMutex) \
+ EXCLUDES_BELOW_EffectBase_PolicyMutex
+
+#define EXCLUDES_BELOW_EffectHandle_Mutex \
+ EXCLUDES_EffectBase_PolicyMutex
+#define EXCLUDES_EffectHandle_Mutex \
+ EXCLUDES(android::audio_utils::EffectHandle_Mutex) \
+ EXCLUDES_BELOW_EffectHandle_Mutex
+
+#define EXCLUDES_AUDIO_ALL \
+ EXCLUDES_EffectHandle_Mutex
+
+// --- End generated section
+
+/**
+ * AudioMutexAttributes is a collection of types and constexpr configuration
+ * used for the Android audio mutex.
+ *
+ * A different AudioMutexAttributes configuration will instantiate a completely
+ * independent set of mutex strategies, statics and thread locals,
+ * for a different type of mutexes.
+ */
+
+class AudioMutexAttributes {
+public:
+ // Order types, name arrays.
+ using order_t = MutexOrder;
+ static constexpr auto& order_names_ = gMutexNames;
+ static constexpr size_t order_size_ = static_cast<size_t>(MutexOrder::kSize);
+ static constexpr order_t order_default_ = MutexOrder::kOtherMutex;
+
+ // verify order information
+ static_assert(std::size(order_names_) == order_size_);
+ static_assert(static_cast<size_t>(order_default_) < order_size_);
+
+ // Set mutex_tracking_enabled_ to true to enable mutex
+ // statistics and debugging (order checking) features.
+ static constexpr bool mutex_tracking_enabled_ = true;
+
+ // Control the depth of the mutex stack per thread (the mutexes
+ // we track). Set this to the maximum expected
+ // number of mutexes held by a thread. If the depth is too small,
+ // deadlock detection, order checking, and recursion checking
+ // may result in a false negative. This is a static configuration
+ // because reallocating memory for the stack requires a lock for
+ // the reader.
+ static constexpr size_t mutex_stack_depth_ = 16;
+
+ // Enable or disable log always fatal.
+ // This also requires the mutex feature flag to be set.
+ static constexpr bool abort_on_order_check_ = true;
+ static constexpr bool abort_on_recursion_check_ = true;
+ static constexpr bool abort_on_invalid_unlock_ = true;
+};
+
+/**
+ * Helper method to accumulate floating point values to an atomic
+ * prior to C++23 support of atomic<float> atomic<double> accumulation.
+ */
+template <typename AccumulateType, typename ValueType>
+void atomic_add_to(std::atomic<AccumulateType> &dst, ValueType src) {
+ static_assert(std::atomic<AccumulateType>::is_always_lock_free);
+ AccumulateType expected;
+ do {
+ expected = dst;
+ } while (!dst.compare_exchange_weak(expected, expected + src));
+}
+
+/**
+ * mutex_stat is a struct composed of atomic members associated
+ * with usage of a particular mutex order.
+ *
+ * Access of a snapshot of this does not have a global lock, so the reader
+ * may experience temporal shear. Use of this by a different reader thread
+ * is for informative purposes only.
+ */
+
+// CounterType == uint64_t, AccumulatorType == double
+template <typename CounterType, typename AccumulatorType>
+struct mutex_stat {
+ static_assert(std::is_floating_point_v<AccumulatorType>);
+ static_assert(std::is_integral_v<CounterType>);
+ std::atomic<CounterType> locks = 0; // number of times locked
+ std::atomic<CounterType> unlocks = 0; // number of times unlocked
+ std::atomic<CounterType> waits = 0; // number of locks that waitedwa
+ std::atomic<AccumulatorType> wait_sum_ns = 0.; // sum of time waited.
+ std::atomic<AccumulatorType> wait_sumsq_ns = 0.; // sumsq of time waited.
+
+ template <typename WaitTimeType>
+ void add_wait_time(WaitTimeType wait_ns) {
+ AccumulatorType value_ns = wait_ns;
+ atomic_add_to(wait_sum_ns, value_ns);
+ atomic_add_to(wait_sumsq_ns, value_ns * value_ns);
+ }
+
+ std::string to_string() const {
+ CounterType uncontested = locks - waits;
+ AccumulatorType recip = waits == 0 ? 0. : 1. / waits;
+ AccumulatorType avg_wait_ms = waits == 0 ? 0. : wait_sum_ns * 1e-6 * recip;
+ AccumulatorType std_wait_ms = waits < 2 ? 0. :
+ std::sqrt(wait_sumsq_ns * recip * 1e-12 - avg_wait_ms * avg_wait_ms);
+ return std::string("locks: ").append(std::to_string(locks))
+ .append("\nuncontested: ").append(std::to_string(uncontested))
+ .append("\nwaits: ").append(std::to_string(waits))
+ .append("\nunlocks: ").append(std::to_string(unlocks))
+ .append("\navg_wait_ms: ").append(std::to_string(avg_wait_ms))
+ .append("\nstd_wait_ms: ").append(std::to_string(std_wait_ms))
+ .append("\n");
+ }
+};
+
+/**
+ * atomic_stack is a single writer, multiple reader object.
+ * Readers not on the same thread as the writer may experience temporal shear,
+ * but individual members are accessed atomic-safe, i.e. no partial member
+ * reads or delayed writes due to caching.
+ *
+ * For use with mutex checking, the atomic_stack maintains an ordering on
+ * P (payload) such that the top item pushed must always be greater than or
+ * equal to the P (payload) of items below it.
+ *
+ * Pushes always go to the top of the stack. Removes can occur
+ * from any place in the stack, but typically near the top.
+ *
+ * The atomic_stack never reallocates beyond its fixed capacity of N.
+ * This prevents a lockless reader from accessing invalid memory because
+ * the address region does not change.
+ *
+ * If the number of pushes exceed the capacity N, then items may be discarded.
+ * In that case, the stack is a subset stack of the "true" unlimited
+ * capacity stack. Nevertheless, a subset of an ordered stack
+ * with items deleted is also ordered.
+ *
+ * The size() of the atomic_stack is the size of the subset stack of tracked items.
+ * The true_size() is the size of the number of items pushed minus the
+ * number of items removed (the "true" size if capacity were unlimited).
+ * Since the capacity() is constant the true_size() may include
+ * items we don't track except by count. If true_size() == size() then
+ * the subset stack is complete.
+ *
+ * In this single writer, multiple reader model, we could get away with
+ * memory_order_relaxed as the reader is purely informative,
+ * but we choose memory_order_seq_cst which imposes the most
+ * restrictions on the compiler (variable access reordering) and the
+ * processor (memory access reordering). This means operations take effect
+ * in the order written. However, this isn't strictly needed - as there is
+ * only one writer, a read-modify-write operation is safe (no need for special
+ * memory instructions), and there isn't the acquire-release semantics with
+ * non-atomic memory access needed for a lockless fifo, for example.
+ */
+
+ /*
+ * For audio mutex purposes, one question arises - why don't we use
+ * a bitmask to represent the capabilities taken by a thread
+ * instead of a stack?
+ *
+ * A bitmask arrangement works if there exists a one-to-one relationship
+ * from a physical mutex to its capability. That may exist for some
+ * projects, but not AudioFlinger.
+ *
+ * As a consequence, we need the actual count and handle:
+ *
+ * 1) A single thread may hold multiple instances of some capabilities
+ * (e.g. ThreadBase_Mutex and EffectChain_Mutex).
+ * For example there may be multiple effect chains locked during mixing.
+ * There may be multiple PlaybackThreads locked during effect chain movement.
+ * A bit per capability can't count beyond 1.
+ *
+ * 2) Deadlock detection requires tracking the actual MutexHandle (a void*)
+ * to form a cycle, because there may be many mutexes associated with a
+ * given capability order.
+ * For example, each PlaybackThread or RecordThread will have its own mutex
+ * with the ThreadBase_Mutex capability.
+ *
+ */
+
+template <typename Item, typename Payload, size_t N>
+class atomic_stack {
+public:
+ using item_payload_pair_t = std::pair<std::atomic<Item>, std::atomic<Payload>>;
+
+ /**
+ * Puts the item at the top of the stack.
+ *
+ * If the stack depth is exceeded the item
+ * replaces the top.
+ *
+ * Mutexes when locked are always placed on the top of the stack;
+ * however, they may be unlocked in a non last-in-first-out (LIFO)
+ * order. It is rare to see a non LIFO order, but it can happen.
+ */
+ void push(const Item& item, const Payload& payload) {
+ size_t location = top_;
+ size_t increment = 1;
+ if (location >= N) {
+ // we exceed the top of stack.
+ //
+ // although we could ignore this item (subset is the oldest),
+ // the better solution is to replace the topmost entry as
+ // it allows quicker removal.
+ location = N - 1;
+ increment = 0;
+ }
+ // issue the operations close together.
+ pairs_[location].first = item;
+ pairs_[location].second = payload;
+ ++true_top_;
+ top_ += increment;
+ }
+
+ /**
+ * Removes the item which is expected at the top of the stack
+ * but may be lower. Mutexes are generally unlocked in stack
+ * order (LIFO), but this is not a strict requirement.
+ */
+ bool remove(const Item& item) {
+ if (true_top_ == 0) {
+ return false; // cannot remove.
+ }
+ // there is a temporary benign read race here where true_top_ != top_.
+ --true_top_;
+ for (size_t i = top_; i > 0; ) {
+ if (item == pairs_[--i].first) {
+ // We shift to preserve order.
+ // A reader may temporarily see a "duplicate" entry
+ // but that is preferable to a "missing" entry
+ // for the purposes of deadlock detection.
+ const size_t limit = top_ - 1;
+ while (i < limit) { // using atomics, we need to assign first, second separately.
+ pairs_[i].first = pairs_[i + 1].first.load();
+ pairs_[i].second = pairs_[i + 1].second.load();
+ ++i;
+ }
+ --top_; // now we restrict our range.
+ // on relaxed semantics, it might be better to clear out the last
+ // pair, but we are seq_cst.
+ return true;
+ }
+ }
+ // not found in our subset.
+ //
+ // we return true upon correct removal (true_top_ must always be >= top_).
+ if (true_top_ >= top_) return true;
+
+ // else recover and return false to notify that removal was invalid.
+ true_top_ = top_.load();
+ return false;
+ }
+
+ /**
+ * return the top of our atomic subset stack
+ * or the invalid_ (zero-initialized) entry if it doesn't exist.
+ */
+ // Consideration of using std::optional<> is a possibility
+ // but as std::atomic doesn't have a copy ctor (and does not make sense),
+ // we would want to directly return an optional on the non-atomic values,
+ // in a custom pair.
+ const item_payload_pair_t& top(size_t offset = 0) const {
+ const ssize_t top = static_cast<ssize_t>(top_) - static_cast<ssize_t>(offset);
+ if (top > 0 && top <= static_cast<ssize_t>(N)) return pairs_[top - 1];
+ return invalid_; // we don't know anything.
+ }
+
+ /**
+ * return the bottom (or base) of our atomic subset stack
+ * or the invalid_ (zero-initialized) entry if it doesn't exist.
+ */
+ const item_payload_pair_t& bottom(size_t offset = 0) const {
+ if (offset < top_) return pairs_[offset];
+ return invalid_; // we don't know anything.
+ }
+
+ /**
+ * prints the contents of the stack starting from the most recent first.
+ *
+ * If the thread is not the same as the writer thread, there could be
+ * temporal shear in the data printed.
+ */
+ std::string to_string() const {
+ std::string s("size: ");
+ s.append(std::to_string(size()))
+ .append(" true_size: ").append(std::to_string(true_size()))
+ .append(" items: [");
+ for (size_t i = 0; i < top_; ++i) {
+ s.append("{ ")
+ .append(std::to_string(reinterpret_cast<uintptr_t>(pairs_[i].first.load())))
+ .append(", ")
+ .append(std::to_string(static_cast<size_t>(pairs_[i].second.load())))
+ .append(" } ");
+ }
+ s.append("]");
+ return s;
+ }
+
+ /*
+ * stack configuration
+ */
+ static size_t capacity() { return N; }
+ size_t true_size() const { return true_top_; }
+ size_t size() const { return top_; }
+ const auto& invalid() const { return invalid_; }
+
+private:
+ std::atomic<size_t> top_ = 0; // ranges from 0 to N - 1
+ std::atomic<size_t> true_top_ = 0; // always >= top_.
+ // if true_top_ == top_ the subset stack is complete.
+
+ /*
+ * The subset stack entries are a pair of atomics rather than an atomic<pair>
+ * to prevent lock requirements if T and P are small enough, i.e. <= sizeof(size_t).
+ *
+ * As atomics are not composable from smaller atomics, there may be some
+ * temporary inconsistencies when reading from a different thread than the writer.
+ */
+ item_payload_pair_t pairs_[N]{};
+
+ /*
+ * The invalid pair is returned when top() is called without a tracked item.
+ * This might occur with an empty subset of the "true" stack.
+ */
+ static constexpr item_payload_pair_t invalid_{};
+};
+
+/**
+ * thread_mutex_info is a struct that is associated with every
+ * thread the first time a mutex is used on it. Writing will be through
+ * a single thread (essentially thread_local), but the thread_registry
+ * debug methods may access this through a different reader thread.
+ *
+ * If the thread does not use the audio_utils mutex, the allocation of this
+ * struct never occurs, although there is approx 16 bytes for a shared ptr and
+ * 1 byte for a thread local once bool.
+ *
+ * Here, we use for the MutexHandle a void*, which is used as an opaque unique ID
+ * representing the mutex.
+ *
+ * Since there is no global locking, the validity of the mutex* associated to
+ * the void* is unknown -- the mutex* could be deallocated in a different
+ * thread. Nevertheless the opaque ID can still be used to check deadlocks
+ * realizing there could be a false positive on a potential reader race
+ * where a new mutex is created at the same storage location.
+ */
+template <typename MutexHandle, typename Order, size_t N>
+class thread_mutex_info {
+public:
+ using atomic_stack_t = atomic_stack<MutexHandle, Order, N>;
+
+ thread_mutex_info(pid_t tid) : tid_(tid) {}
+
+ // the destructor releases the thread_mutex_info.
+ // declared here, defined below due to use of thread_registry.
+ ~thread_mutex_info();
+
+ void reset_waiter(MutexHandle waiter = nullptr) {
+ mutex_wait_ = waiter;
+ }
+
+ /**
+ * check_held returns the stack pair that conflicts
+ * with the existing mutex handle and order, or the invalid
+ * stack pair (empty mutex handle and empty order).
+ */
+ const typename atomic_stack_t::item_payload_pair_t&
+ check_held(MutexHandle mutex, Order order) const {
+ // validate mutex order.
+ const size_t size = mutexes_held_.size();
+ for (size_t i = 0; i < size; ++i) {
+ const auto& top = mutexes_held_.top(i);
+ const auto top_order = top.second.load();
+
+ if (top_order < order) break; // ok
+ if (top_order > order) return top; // inverted order
+ if (top.first.load() == mutex) return top; // recursive mutex
+ }
+ return mutexes_held_.invalid();
+ }
+
+ /*
+ * This is unverified push. Use check_held() prior to this to
+ * verify no lock inversion or replication.
+ */
+ void push_held(MutexHandle mutex, Order order) {
+ mutexes_held_.push(mutex, order);
+ }
+
+ bool remove_held(MutexHandle mutex) {
+ return mutexes_held_.remove(mutex);
+ }
+
+ /*
+ * Due to the fact that the thread_mutex_info contents are not globally locked,
+ * there may be temporal shear. The string representation is
+ * informative only.
+ */
+ std::string to_string() const {
+ std::string s;
+ s.append("tid: ").append(std::to_string(static_cast<int>(tid_)));
+ s.append("\nwaiting: ").append(std::to_string(
+ reinterpret_cast<uintptr_t>(mutex_wait_.load())));
+ s.append("\nheld: ").append(mutexes_held_.to_string());
+ return s;
+ }
+
+ /*
+ * empty() indicates that the thread is not waiting for or
+ * holding any mutexes.
+ */
+ bool empty() const {
+ return mutex_wait_ == nullptr && mutexes_held_.size() == 0;
+ }
+
+ const auto& stack() const {
+ return mutexes_held_;
+ }
+
+ const pid_t tid_; // me
+ std::atomic<MutexHandle> mutex_wait_{}; // mutex waiting for
+ atomic_stack_t mutexes_held_; // mutexes held
+};
+
+
+/**
+ * deadlock_info_t encapsulates the mutex wait / cycle information from
+ * thread_registry::deadlock_detection().
+ *
+ * If a cycle is detected, the last element of the vector chain represents
+ * a tid that is repeated somewhere earlier in the vector.
+ */
+struct deadlock_info_t {
+public:
+ explicit deadlock_info_t(pid_t tid_param) : tid(tid_param) {}
+
+ bool empty() const {
+ return chain.empty();
+ }
+
+ std::string to_string() const {
+ std::string description;
+
+ if (has_cycle) {
+ description.append("mutex cycle found (last tid repeated) ");
+ } else {
+ description.append("mutex wait chain ");
+ }
+ description.append("[ ").append(std::to_string(tid));
+ // Note: when we dump here, we add the timeout tid to the start of the wait chain.
+ for (const auto& [ tid2, name ] : chain) {
+ description.append(", ").append(std::to_string(tid2))
+ .append(" (holding ").append(name).append(")");
+ }
+ description.append(" ]");
+ return description;
+ }
+
+ const pid_t tid; // tid for which the deadlock was checked
+ bool has_cycle = false; // true if there is a cycle detected
+ std::vector<std::pair<pid_t, std::string>> chain; // wait chain of tids and mutexes.
+};
+
+/**
+ * The thread_registry is a thread-safe locked structure that
+ * maintains a list of the threads that contain thread_mutex_info.
+ *
+ * Only first mutex access from a new thread and the destruction of that
+ * thread will trigger an access to the thread_registry map.
+ *
+ * The debug methods to_string() and deadlock_detection() will also lock the struct
+ * long enough to copy the map and safely obtain the weak pointers,
+ * and then deal with the thread local data afterwards.
+ *
+ * It is recommended to keep a static singleton of the thread_registry for the
+ * type desired. The singleton should be associated properly with the object
+ * it should be unique for, which in this case is the mutex_impl template.
+ * This enables access to the elements as needed.
+ */
+template <typename ThreadInfo>
+class thread_registry {
+public:
+ bool add_to_registry(const std::shared_ptr<ThreadInfo>& tminfo) EXCLUDES(mutex_) {
+ ALOGV("%s: registered for %d", __func__, tminfo->tid_);
+ std::lock_guard l(mutex_);
+ if (registry_.count(tminfo->tid_) > 0) {
+ ALOGW_IF("%s: tid %d already exists", __func__, tminfo->tid_);
+ return false;
+ }
+ registry_[tminfo->tid_] = tminfo;
+ return true;
+ }
+
+ bool remove_from_registry(pid_t tid) EXCLUDES(mutex_) {
+ ALOGV("%s: unregistered for %d", __func__, tid);
+ std::lock_guard l(mutex_);
+ // don't crash here because it might be a test app.
+ const bool success = registry_.erase(tid) == 1;
+ ALOGW_IF(!success, "%s: Cannot find entry for tid:%d", __func__, tid);
+ return success;
+ }
+
+ // Returns a std::unordered_map for easy access on tid.
+ auto copy_map() EXCLUDES(mutex_) {
+ std::lock_guard l(mutex_);
+ return registry_;
+ }
+
+ // Returns a std::map sorted on tid for easy debug reading.
+ auto copy_ordered_map() EXCLUDES(mutex_) {
+ std::lock_guard l(mutex_);
+ std::map<pid_t, std::weak_ptr<ThreadInfo>> sorted(registry_.begin(), registry_.end());
+ return sorted;
+ }
+
+ /**
+ * Returns a string containing the thread mutex info for each
+ * thread that has accessed the audio_utils mutex.
+ */
+ std::string to_string() {
+ // for debug purposes it is much easier to see the tids in numeric order.
+ const auto registry_map = copy_ordered_map();
+ ALOGV("%s: dumping tids: %zu", __func__, registry_map.size());
+ std::string s("thread count: ");
+ s.append(std::to_string(registry_map.size())).append("\n");
+
+ std::vector<pid_t> empty;
+ for (const auto& [tid, weak_info] : registry_map) {
+ const auto info = weak_info.lock();
+ if (info) {
+ if (info->empty()) {
+ empty.push_back(tid);
+ } else {
+ s.append(info->to_string()).append("\n");
+ }
+ }
+ }
+
+ // dump remaining empty tids out
+ s.append("tids without current activity [ ");
+ for (const auto tid : empty) {
+ s.append(std::to_string(tid)).append(" ");
+ }
+ s.append("]\n");
+ return s;
+ }
+
+ /**
+ * Returns the tid mutex pointer (a void*) if it is waiting.
+ *
+ * It should use a copy of the registry map which is not changing
+ * as it does not take any lock.
+ */
+ static void* tid_to_mutex_wait(
+ const std::unordered_map<pid_t, std::weak_ptr<ThreadInfo>>& registry_map,
+ pid_t tid) {
+ const auto it = registry_map.find(tid);
+ if (it == registry_map.end()) return {};
+ const auto& weak_info = it->second; // unmapped returns empty weak_ptr.
+ const auto info = weak_info.lock();
+ if (!info) return {};
+ return info->mutex_wait_.load();
+ }
+
+ /**
+ * Returns a deadlock_info_t struct describing the mutex wait / cycle information.
+ *
+ * The deadlock_detection() method is not exceptionally fast
+ * and is not designed to be called for every mutex locked (and contended).
+ * It is designed to run as a diagnostic routine to enhance
+ * dumping for watchdogs, like TimeCheck, when a tid is believed blocked.
+ *
+ * Access of state is through atomics, so has minimal overhead on
+ * concurrent execution, with the possibility of (mostly) false
+ * negatives due to race.
+ *
+ * \param tid target tid which may be in a cycle or blocked.
+ * \param mutex_names a string array of mutex names indexed on capability order.
+ * \return a deadlock_info_t struct, which contains whether a cycle was found and
+ * a vector of tids and mutex names in the mutex wait chain.
+ */
+ template <typename StringArray>
+ deadlock_info_t deadlock_detection(pid_t tid, const StringArray& mutex_names) {
+ const auto registry_map = copy_map();
+ deadlock_info_t deadlock_info{tid};
+
+ // if tid not waiting, return.
+ void* m = tid_to_mutex_wait(registry_map, tid);
+ if (m == nullptr) return deadlock_info;
+
+ bool subset = false; // do we have missing mutex data per thread?
+
+ // Create helper map from mutex to tid.
+ //
+ // The helper map is built up from thread_local info rather than from
+ // a global mutex list.
+ //
+ // There are multiple reasons behind this.
+ // 1) There are many mutexes (mostly not held). We don't want to keep and
+ // manage a "global" list of them.
+ // 2) The mutex pointer itself may be deallocated from a different thread
+ // from the reader. To keep it alive requires either a mutex, or a
+ // weak_ptr to shared_ptr promotion.
+ // Lifetime management is expensive on a per-mutex basis as there are many
+ // of them, but cheaper on a per-thread basis as the threads are fewer.
+ // 3) The thread_local lookup is very inexpensive for thread info (special
+ // acceleration by C++ and the OS), but more complex for a mutex list
+ // which at best is a static concurrent hash map.
+ //
+ // Note that the mutex_ptr handle is opaque -- it may be deallocated from
+ // a different thread, so we use the tid from the thread registry map.
+ //
+ using pid_order_index_pair_t = std::pair<pid_t, size_t>;
+ std::unordered_map<void*, pid_order_index_pair_t> mutex_to_tid;
+ for (const auto& [tid2, weak_info] : registry_map) {
+ const auto info = weak_info.lock();
+ if (info == nullptr) continue;
+ const auto& stack = info->mutexes_held_;
+ subset = subset || stack.size() != stack.true_size();
+ for (size_t i = 0; i < stack.size(); ++i) {
+ const auto& mutex_order_pair = stack.bottom(i);
+ // if this method is not called by the writer thread
+ // it is possible for data to change.
+ const auto mutex_ptr = mutex_order_pair.first.load();
+ const auto order = static_cast<size_t>(mutex_order_pair.second.load());
+ if (mutex_ptr != nullptr) {
+ mutex_to_tid[mutex_ptr] = pid_order_index_pair_t{tid2, order};
+ }
+ }
+ }
+ ALOGD_IF(subset, "%s: mutex info only subset, deadlock detection may be inaccurate",
+ __func__);
+
+ // traverse from tid -> waiting mutex, then
+ // mutex -> tid holding
+ // until we get no more tids, or a tid cycle.
+ std::unordered_set<pid_t> visited;
+ visited.insert(tid); // mark the original tid, we start there for cycle detection.
+ while (true) {
+ // no tid associated with the mutex.
+ if (mutex_to_tid.count(m) == 0) return deadlock_info;
+ const auto [tid2, order] = mutex_to_tid[m];
+
+ // add to chain.
+ const auto name = order < std::size(mutex_names) ? mutex_names[order] : "unknown";
+ deadlock_info.chain.emplace_back(tid2, name);
+
+ // cycle detected
+ if (visited.count(tid2)) {
+ deadlock_info.has_cycle = true;
+ return deadlock_info;
+ }
+ visited.insert(tid2);
+
+ // if tid not waiting return (could be blocked on binder).
+ m = tid_to_mutex_wait(registry_map, tid2);
+ if (m == nullptr) return deadlock_info;
+ }
+ }
+
+private:
+ mutable std::mutex mutex_;
+ std::unordered_map<pid_t, std::weak_ptr<ThreadInfo>> registry_ GUARDED_BY(mutex_);
+};
+
// audio_utils::mutex, audio_utils::lock_guard, audio_utils::unique_lock,
// and audio_utils::condition_variable are method compatible versions
// of std::mutex, std::lock_guard, std::unique_lock, and std::condition_variable
@@ -36,14 +934,24 @@ namespace android::audio_utils {
// is inefficient. One is better off making a custom timed implementation using
// pthread_mutex_timedlock() on the mutex::native_handle().
-class CAPABILITY("mutex") mutex {
+extern bool mutex_get_enable_flag();
+
+template <typename Attributes>
+class CAPABILITY("mutex") mutex_impl {
public:
- static constexpr bool kPriorityInheritance = false;
+ using attributes_t = Attributes;
// We use composition here.
// No copy/move ctors as the member std::mutex has it deleted.
- mutex() {
- if constexpr (!kPriorityInheritance) return;
+ mutex_impl(typename Attributes::order_t order = Attributes::order_default_)
+ : order_(order)
+ , stat_{get_mutex_stat_array()[static_cast<size_t>(order)]}
+ {
+ LOG_ALWAYS_FATAL_IF(static_cast<size_t>(order) >= Attributes::order_size_,
+ "mutex order %u is equal to or greater than order limit:%zu",
+ order, Attributes::order_size_);
+
+ if (!mutex_get_enable_flag()) return;
pthread_mutexattr_t attr;
int ret = pthread_mutexattr_init(&attr);
@@ -59,12 +967,16 @@ public:
}
// use of the native_handle() is implementation defined.
- auto handle = m_.native_handle();
+ const auto handle = m_.native_handle();
ret = pthread_mutex_init(handle, &attr);
if (ret != 0) {
ALOGW("%s, pthread_mutex_init returned %d", __func__, ret);
}
- ALOGV("%s: audio_mutex initialized: %d", __func__, ret);
+ ALOGV("%s: audio_mutex initialized: ret:%d order:%u", __func__, ret, order_);
+ }
+
+ ~mutex_impl() {
+ // Note: std::mutex behavior is undefined if released holding ownership.
}
auto native_handle() {
@@ -72,15 +984,38 @@ public:
}
void lock() ACQUIRE() {
- m_.lock();
+ lock_scoped_stat_t::pre_lock(*this);
+ if (!m_.try_lock()) { // if we directly use futex, we can optimize this with m_.lock().
+ // lock_scoped_stat_t accumulates waiting time for the mutex lock call.
+ lock_scoped_stat_t ls(*this);
+ m_.lock();
+ }
+ lock_scoped_stat_t::post_lock(*this);
}
void unlock() RELEASE() {
+ lock_scoped_stat_t::pre_unlock(*this);
m_.unlock();
}
- bool try_lock() TRY_ACQUIRE(true) {
- return m_.try_lock();
+ bool try_lock(int64_t timeout_ns = 0) TRY_ACQUIRE(true) {
+ lock_scoped_stat_t::pre_lock(*this);
+ if (timeout_ns <= 0) {
+ if (!m_.try_lock()) return false;
+ } else {
+ const int64_t deadline_ns = timeout_ns + systemTime(SYSTEM_TIME_REALTIME);
+ const struct timespec ts = {
+ .tv_sec = static_cast<time_t>(deadline_ns / 1'000'000'000),
+ .tv_nsec = static_cast<long>(deadline_ns % 1'000'000'000),
+ };
+ lock_scoped_stat_t ls(*this);
+ if (pthread_mutex_timedlock(m_.native_handle(), &ts) != 0) {
+ ls.ignoreWaitTime(); // didn't get lock, don't count wait time
+ return false;
+ }
+ }
+ lock_scoped_stat_t::post_lock(*this);
+ return true;
}
// additional method to obtain the underlying std::mutex.
@@ -88,10 +1023,216 @@ public:
return m_;
}
+ using mutex_stat_t = mutex_stat<uint64_t, double>;
+
+ mutex_stat_t& get_stat() const {
+ return stat_;
+ }
+
+ /**
+ * Returns the locking statistics per mutex capability category.
+ */
+ static std::string all_stats_to_string() {
+ std::string out("mutex stats: priority inheritance ");
+ out.append(mutex_get_enable_flag() ? "enabled" : "disabled")
+ .append("\n");
+ const auto& stat_array = get_mutex_stat_array();
+ for (size_t i = 0; i < stat_array.size(); ++i) {
+ if (stat_array[i].locks != 0) {
+ out.append("Capability: ").append(Attributes::order_names_[i]).append("\n")
+ .append(stat_array[i].to_string());
+ }
+ }
+ return out;
+ }
+
+ /**
+ * Returns the thread locks held per tid.
+ */
+ static std::string all_threads_to_string() {
+ return get_registry().to_string();
+ }
+
+ /**
+ * Returns a pair of bool (whether a cycle is detected) and a vector
+ * of mutex wait dependencies.
+ *
+ * If a cycle is detected, the last element of the vector represents
+ * a tid that is repeated somewhere earlier in the vector.
+ *
+ * The deadlock_detection() method is not exceptionally fast
+ * and is not designed to be called for every mutex locked (and contended).
+ * It is designed to run as a diagnostic routine to enhance
+ * dumping for watchdogs, like TimeCheck, when a tid is believed blocked.
+ *
+ * Access of state is through atomics, so has minimal overhead on
+ * concurrent execution, with the possibility of (mostly) false
+ * negatives due to race.
+ */
+ static deadlock_info_t
+ deadlock_detection(pid_t tid) {
+ return get_registry().deadlock_detection(tid, Attributes::order_names_);
+ }
+
+ using thread_mutex_info_t = thread_mutex_info<
+ void* /* mutex handle */, MutexOrder, Attributes::mutex_stack_depth_>;
+
+ // get_thread_mutex_info is a thread-local "singleton".
+ //
+ // We write it like a Meyer's singleton with a single thread_local
+ // assignment that is guaranteed to be called on first time initialization.
+ // Since the variables are thread_local, there is no thread contention
+ // for initialization that would happen with a traditional Meyer's singleton,
+ // so really a simple thread-local bool will do for a once_flag.
+ static const std::shared_ptr<thread_mutex_info_t>& get_thread_mutex_info() {
+ thread_local std::shared_ptr<thread_mutex_info_t> tminfo = []() {
+ auto info = std::make_shared<thread_mutex_info_t>(gettid_wrapper());
+ get_registry().add_to_registry(info);
+ return info;
+ }();
+ return tminfo;
+ }
+
+ // helper class for registering statistics for a mutex lock.
+
+ class lock_scoped_stat_enabled {
+ public:
+ explicit lock_scoped_stat_enabled(mutex& m)
+ : mutex_(m)
+ , time_(systemTime()) {
+ ++mutex_.stat_.waits;
+ mutex_.get_thread_mutex_info()->reset_waiter(&mutex_);
+ }
+
+ ~lock_scoped_stat_enabled() {
+ if (!discard_wait_time_) mutex_.stat_.add_wait_time(systemTime() - time_);
+ mutex_.get_thread_mutex_info()->reset_waiter();
+ }
+
+ void ignoreWaitTime() {
+ discard_wait_time_ = true;
+ }
+
+ static void pre_unlock(mutex& m) {
+ ++m.stat_.unlocks;
+ const bool success = m.get_thread_mutex_info()->remove_held(&m);
+ LOG_ALWAYS_FATAL_IF(Attributes::abort_on_invalid_unlock_
+ && mutex_get_enable_flag()
+ && !success,
+ "%s: invalid mutex unlock when not previously held", __func__);
+ }
+
+ // before we lock, we check order and recursion.
+ static void pre_lock(mutex& m) {
+ if constexpr (!Attributes::abort_on_order_check_ &&
+ !Attributes::abort_on_recursion_check_) return;
+
+ const auto& p = m.get_thread_mutex_info()->check_held(&m, m.order_);
+ if (p.first == nullptr) return; // no problematic mutex.
+
+ // problem!
+ const size_t p_order = static_cast<size_t>(p.second.load());
+ const size_t m_order = static_cast<size_t>(m.order_);
+
+ // lock inversion
+ LOG_ALWAYS_FATAL_IF(Attributes::abort_on_order_check_
+ && mutex_get_enable_flag()
+ && p_order > m_order,
+ "%s: invalid mutex order (previous) %zu %s> (new) %zu %s",
+ __func__, p_order, Attributes::order_names_[p_order],
+ m_order, Attributes::order_names_[m_order]);
+
+ // lock recursion
+ LOG_ALWAYS_FATAL_IF(Attributes::abort_on_recursion_check_
+ && mutex_get_enable_flag()
+ && p_order == m_order,
+ "%s: recursive mutex access detected (order: %zu %s)",
+ __func__, p_order, Attributes::order_names_[p_order]);
+ }
+
+ static void post_lock(mutex& m) {
+ ++m.stat_.locks;
+ m.get_thread_mutex_info()->push_held(&m, m.order_);
+ }
+
+ private:
+ mutex& mutex_;
+ const int64_t time_;
+ bool discard_wait_time_ = false;
+ };
+
+ class lock_scoped_stat_disabled {
+ public:
+ explicit lock_scoped_stat_disabled(mutex&) {}
+
+ void ignoreWaitTime() {}
+
+ static void pre_unlock(mutex&) {}
+
+ static void pre_lock(mutex&) {}
+
+ static void post_lock(mutex&) {}
+ };
+
+ using lock_scoped_stat_t = std::conditional_t<Attributes::mutex_tracking_enabled_,
+ lock_scoped_stat_enabled, lock_scoped_stat_disabled>;
+
+ // helper class for registering statistics for a cv wait.
+ class cv_wait_scoped_stat_enabled {
+ public:
+ explicit cv_wait_scoped_stat_enabled(mutex& m) : mutex_(m) {
+ ++mutex_.stat_.unlocks;
+ const bool success = mutex_.get_thread_mutex_info()->remove_held(&mutex_);
+ LOG_ALWAYS_FATAL_IF(Attributes::abort_on_invalid_unlock_
+ && mutex_get_enable_flag()
+ && !success,
+ "%s: invalid mutex unlock when not previously held", __func__);
+ }
+
+ ~cv_wait_scoped_stat_enabled() {
+ ++mutex_.stat_.locks;
+ mutex_.get_thread_mutex_info()->push_held(&mutex_, mutex_.order_);
+ }
+ private:
+ mutex& mutex_;
+ };
+
+ class cv_wait_scoped_stat_disabled {
+ explicit cv_wait_scoped_stat_disabled(mutex&) {}
+ };
+
+ using cv_wait_scoped_stat_t = std::conditional_t<Attributes::mutex_tracking_enabled_,
+ cv_wait_scoped_stat_enabled, cv_wait_scoped_stat_disabled>;
+
+ using thread_registry_t = thread_registry<thread_mutex_info_t>;
+
+ // One per-process thread registry, one instance per template typename.
+ // Declared here but must be defined in a .cpp otherwise there will be multiple
+ // instances if the header is included into different shared libraries.
+ static thread_registry_t& get_registry();
+
+ using stat_array_t = std::array<mutex_stat_t, Attributes::order_size_>;
+
+ // One per-process mutex statistics array, one instance per template typename.
+ // Declared here but must be defined in a .cpp otherwise there will be multiple
+ // instances if the header is included into different shared libraries.
+ static stat_array_t& get_mutex_stat_array();
+
private:
+
std::mutex m_;
+ const typename Attributes::order_t order_;
+ mutex_stat_t& stat_; // set in ctor
};
+// define the destructor to remove from registry.
+template <typename MutexHandle, typename Order, size_t N>
+inline thread_mutex_info<MutexHandle, Order, N>::~thread_mutex_info() {
+ if (tid_ != 0) {
+ mutex::get_registry().remove_from_registry(tid_);
+ }
+}
+
// audio_utils::lock_guard only works with the defined mutex.
using lock_guard = std::lock_guard<mutex>;
@@ -108,32 +1249,57 @@ using lock_guard = std::lock_guard<mutex>;
class SCOPED_CAPABILITY unique_lock {
public:
explicit unique_lock(mutex& m) ACQUIRE(m)
- : ul_(m.std_mutex()) {}
+ : ul_(m.std_mutex(), std::defer_lock)
+ , mutex_(m) {
+ lock();
+ }
- ~unique_lock() RELEASE() = default;
+ ~unique_lock() RELEASE() {
+ if (held) unlock();
+ }
void lock() ACQUIRE() {
- ul_.lock();
+ mutex::lock_scoped_stat_t::pre_lock(mutex_);
+ if (!ul_.try_lock()) {
+ mutex::lock_scoped_stat_t ls(mutex_);
+ ul_.lock();
+ }
+ mutex::lock_scoped_stat_t::post_lock(mutex_);
+ held = true;
}
void unlock() RELEASE() {
+ mutex::lock_scoped_stat_t::pre_unlock(mutex_);
+ held = false;
ul_.unlock();
}
bool try_lock() TRY_ACQUIRE(true) {
- return ul_.try_lock();
+ mutex::lock_scoped_stat_t::pre_lock(mutex_);
+ if (!ul_.try_lock()) return false;
+ mutex::lock_scoped_stat_t::post_lock(mutex_);
+ held = true;
+ return true;
}
template<class Rep, class Period>
bool try_lock_for(const std::chrono::duration<Rep,Period>& timeout_duration)
TRY_ACQUIRE(true) {
- return ul_.try_lock_for(timeout_duration);
+ mutex::lock_scoped_stat_t::pre_lock(mutex_);
+ if (!ul_.try_lock_for(timeout_duration)) return false;
+ mutex::lock_scoped_stat_t::post_lock(mutex_);
+ held = true;
+ return true;
}
template<class Clock, class Duration>
bool try_lock_until(const std::chrono::time_point<Clock,Duration>& timeout_time)
TRY_ACQUIRE(true) {
- return ul_.try_lock_until(timeout_time);
+ mutex::lock_scoped_stat_t::pre_lock(mutex_);
+ if (!ul_.try_lock_until(timeout_time)) return false;
+ mutex::lock_scoped_stat_t::post_lock(mutex_);
+ held = true;
+ return true;
}
// additional method to obtain the underlying std::unique_lock
@@ -141,8 +1307,15 @@ public:
return ul_;
}
+ // additional method to obtain the underlying mutex
+ mutex& native_mutex() {
+ return mutex_;
+ }
+
private:
std::unique_lock<std::mutex> ul_;
+ bool held = false;
+ mutex& mutex_;
};
// audio_utils::condition_variable uses the optimized version of
@@ -161,17 +1334,20 @@ public:
}
void wait(unique_lock& lock) {
+ mutex::cv_wait_scoped_stat_t ws(lock.native_mutex());
cv_.wait(lock.std_unique_lock());
}
template<typename Predicate>
void wait(unique_lock& lock, Predicate stop_waiting) {
+ mutex::cv_wait_scoped_stat_t ws(lock.native_mutex());
cv_.wait(lock.std_unique_lock(), std::move(stop_waiting));
}
template<typename Rep, typename Period>
std::cv_status wait_for(unique_lock& lock,
const std::chrono::duration<Rep, Period>& rel_time) {
+ mutex::cv_wait_scoped_stat_t ws(lock.native_mutex());
return cv_.wait_for(lock.std_unique_lock(), rel_time);
}
@@ -179,12 +1355,14 @@ public:
bool wait_for(unique_lock& lock,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate stop_waiting) {
+ mutex::cv_wait_scoped_stat_t ws(lock.native_mutex());
return cv_.wait_for(lock.std_unique_lock(), rel_time, std::move(stop_waiting));
}
template<typename Clock, typename Duration>
std::cv_status wait_until(unique_lock& lock,
const std::chrono::time_point<Clock, Duration>& timeout_time) {
+ mutex::cv_wait_scoped_stat_t ws(lock.native_mutex());
return cv_.wait_until(lock.std_unique_lock(), timeout_time);
}
@@ -192,6 +1370,7 @@ public:
bool wait_until(unique_lock& lock,
const std::chrono::time_point<Clock, Duration>& timeout_time,
Predicate stop_waiting) {
+ mutex::cv_wait_scoped_stat_t ws(lock.native_mutex());
return cv_.wait_until(lock.std_unique_lock(), timeout_time, std::move(stop_waiting));
}
@@ -268,157 +1447,6 @@ public:
lock_guard_no_thread_safety_analysis(Mutex1& m) : std::lock_guard<Mutex1>(m) {}
};
-// Define global capabilities for thread-safety annotation.
-//
-// These can be manually modified, or
-// compile generate_mutex_order.cpp in the tests directory
-// to generate this.
-
-// --- Begin generated section
-
-// Capabilities in priority order
-// (declaration only, value is nullptr)
-inline mutex* AudioFlinger_Mutex;
-inline mutex* EffectHandle_Mutex
- ACQUIRED_AFTER(android::audio_utils::AudioFlinger_Mutex);
-inline mutex* AudioFlinger_HardwareMutex
- ACQUIRED_AFTER(android::audio_utils::EffectHandle_Mutex);
-inline mutex* DeviceEffectManager_Mutex
- ACQUIRED_AFTER(android::audio_utils::AudioFlinger_HardwareMutex);
-inline mutex* PatchCommandThread_Mutex
- ACQUIRED_AFTER(android::audio_utils::DeviceEffectManager_Mutex);
-inline mutex* ThreadBase_Mutex
- ACQUIRED_AFTER(android::audio_utils::PatchCommandThread_Mutex);
-inline mutex* AudioFlinger_ClientMutex
- ACQUIRED_AFTER(android::audio_utils::ThreadBase_Mutex);
-inline mutex* MelReporter_Mutex
- ACQUIRED_AFTER(android::audio_utils::AudioFlinger_ClientMutex);
-inline mutex* EffectChain_Mutex
- ACQUIRED_AFTER(android::audio_utils::MelReporter_Mutex);
-inline mutex* EffectBase_Mutex
- ACQUIRED_AFTER(android::audio_utils::EffectChain_Mutex);
-inline mutex* AudioFlinger_UnregisteredWritersMutex
- ACQUIRED_AFTER(android::audio_utils::EffectBase_Mutex);
-inline mutex* AsyncCallbackThread_Mutex
- ACQUIRED_AFTER(android::audio_utils::AudioFlinger_UnregisteredWritersMutex);
-inline mutex* ConfigEvent_Mutex
- ACQUIRED_AFTER(android::audio_utils::AsyncCallbackThread_Mutex);
-inline mutex* OutputTrack_TrackMetadataMutex
- ACQUIRED_AFTER(android::audio_utils::ConfigEvent_Mutex);
-inline mutex* PassthruPatchRecord_ReadMutex
- ACQUIRED_AFTER(android::audio_utils::OutputTrack_TrackMetadataMutex);
-inline mutex* PatchCommandThread_ListenerMutex
- ACQUIRED_AFTER(android::audio_utils::PassthruPatchRecord_ReadMutex);
-inline mutex* PlaybackThread_AudioTrackCbMutex
- ACQUIRED_AFTER(android::audio_utils::PatchCommandThread_ListenerMutex);
-
-// Exclusion by capability
-#define EXCLUDES_BELOW_PlaybackThread_AudioTrackCbMutex
-#define EXCLUDES_PlaybackThread_AudioTrackCbMutex \
- EXCLUDES(android::audio_utils::PlaybackThread_AudioTrackCbMutex) \
- EXCLUDES_BELOW_PlaybackThread_AudioTrackCbMutex
-
-#define EXCLUDES_BELOW_PatchCommandThread_ListenerMutex \
- EXCLUDES_PlaybackThread_AudioTrackCbMutex
-#define EXCLUDES_PatchCommandThread_ListenerMutex \
- EXCLUDES(android::audio_utils::PatchCommandThread_ListenerMutex) \
- EXCLUDES_BELOW_PatchCommandThread_ListenerMutex
-
-#define EXCLUDES_BELOW_PassthruPatchRecord_ReadMutex \
- EXCLUDES_PatchCommandThread_ListenerMutex
-#define EXCLUDES_PassthruPatchRecord_ReadMutex \
- EXCLUDES(android::audio_utils::PassthruPatchRecord_ReadMutex) \
- EXCLUDES_BELOW_PassthruPatchRecord_ReadMutex
-
-#define EXCLUDES_BELOW_OutputTrack_TrackMetadataMutex \
- EXCLUDES_PassthruPatchRecord_ReadMutex
-#define EXCLUDES_OutputTrack_TrackMetadataMutex \
- EXCLUDES(android::audio_utils::OutputTrack_TrackMetadataMutex) \
- EXCLUDES_BELOW_OutputTrack_TrackMetadataMutex
-
-#define EXCLUDES_BELOW_ConfigEvent_Mutex \
- EXCLUDES_OutputTrack_TrackMetadataMutex
-#define EXCLUDES_ConfigEvent_Mutex \
- EXCLUDES(android::audio_utils::ConfigEvent_Mutex) \
- EXCLUDES_BELOW_ConfigEvent_Mutex
-
-#define EXCLUDES_BELOW_AsyncCallbackThread_Mutex \
- EXCLUDES_ConfigEvent_Mutex
-#define EXCLUDES_AsyncCallbackThread_Mutex \
- EXCLUDES(android::audio_utils::AsyncCallbackThread_Mutex) \
- EXCLUDES_BELOW_AsyncCallbackThread_Mutex
-
-#define EXCLUDES_BELOW_AudioFlinger_UnregisteredWritersMutex \
- EXCLUDES_AsyncCallbackThread_Mutex
-#define EXCLUDES_AudioFlinger_UnregisteredWritersMutex \
- EXCLUDES(android::audio_utils::AudioFlinger_UnregisteredWritersMutex) \
- EXCLUDES_BELOW_AudioFlinger_UnregisteredWritersMutex
-
-#define EXCLUDES_BELOW_EffectBase_Mutex \
- EXCLUDES_AudioFlinger_UnregisteredWritersMutex
-#define EXCLUDES_EffectBase_Mutex \
- EXCLUDES(android::audio_utils::EffectBase_Mutex) \
- EXCLUDES_BELOW_EffectBase_Mutex
-
-#define EXCLUDES_BELOW_EffectChain_Mutex \
- EXCLUDES_EffectBase_Mutex
-#define EXCLUDES_EffectChain_Mutex \
- EXCLUDES(android::audio_utils::EffectChain_Mutex) \
- EXCLUDES_BELOW_EffectChain_Mutex
-
-#define EXCLUDES_BELOW_MelReporter_Mutex \
- EXCLUDES_EffectChain_Mutex
-#define EXCLUDES_MelReporter_Mutex \
- EXCLUDES(android::audio_utils::MelReporter_Mutex) \
- EXCLUDES_BELOW_MelReporter_Mutex
-
-#define EXCLUDES_BELOW_AudioFlinger_ClientMutex \
- EXCLUDES_MelReporter_Mutex
-#define EXCLUDES_AudioFlinger_ClientMutex \
- EXCLUDES(android::audio_utils::AudioFlinger_ClientMutex) \
- EXCLUDES_BELOW_AudioFlinger_ClientMutex
-
-#define EXCLUDES_BELOW_ThreadBase_Mutex \
- EXCLUDES_AudioFlinger_ClientMutex
-#define EXCLUDES_ThreadBase_Mutex \
- EXCLUDES(android::audio_utils::ThreadBase_Mutex) \
- EXCLUDES_BELOW_ThreadBase_Mutex
-
-#define EXCLUDES_BELOW_PatchCommandThread_Mutex \
- EXCLUDES_ThreadBase_Mutex
-#define EXCLUDES_PatchCommandThread_Mutex \
- EXCLUDES(android::audio_utils::PatchCommandThread_Mutex) \
- EXCLUDES_BELOW_PatchCommandThread_Mutex
-
-#define EXCLUDES_BELOW_DeviceEffectManager_Mutex \
- EXCLUDES_PatchCommandThread_Mutex
-#define EXCLUDES_DeviceEffectManager_Mutex \
- EXCLUDES(android::audio_utils::DeviceEffectManager_Mutex) \
- EXCLUDES_BELOW_DeviceEffectManager_Mutex
-
-#define EXCLUDES_BELOW_AudioFlinger_HardwareMutex \
- EXCLUDES_DeviceEffectManager_Mutex
-#define EXCLUDES_AudioFlinger_HardwareMutex \
- EXCLUDES(android::audio_utils::AudioFlinger_HardwareMutex) \
- EXCLUDES_BELOW_AudioFlinger_HardwareMutex
-
-#define EXCLUDES_BELOW_EffectHandle_Mutex \
- EXCLUDES_AudioFlinger_HardwareMutex
-#define EXCLUDES_EffectHandle_Mutex \
- EXCLUDES(android::audio_utils::EffectHandle_Mutex) \
- EXCLUDES_BELOW_EffectHandle_Mutex
-
-#define EXCLUDES_BELOW_AudioFlinger_Mutex \
- EXCLUDES_EffectHandle_Mutex
-#define EXCLUDES_AudioFlinger_Mutex \
- EXCLUDES(android::audio_utils::AudioFlinger_Mutex) \
- EXCLUDES_BELOW_AudioFlinger_Mutex
-
-#define EXCLUDES_AUDIO_ALL \
- EXCLUDES_AudioFlinger_Mutex
-
-// --- End generated section
-
} // namespace android::audio_utils
#pragma pop_macro("LOG_TAG")
diff --git a/audio_utils/include/audio_utils/safe_math.h b/audio_utils/include/audio_utils/safe_math.h
index 7dcab3f5..7397fe1e 100644
--- a/audio_utils/include/audio_utils/safe_math.h
+++ b/audio_utils/include/audio_utils/safe_math.h
@@ -14,8 +14,65 @@
* limitations under the License.
*/
+#pragma once
+
+#include <bit>
+#include <cmath>
+
namespace android::audio_utils {
+/*
+ * The compilation option
+ * -ffast-math
+ *
+ * https://gcc.gnu.org/wiki/FloatingPointMath
+ *
+ * enables the following flags:
+ *
+ * -fno-trapping-math
+ * -funsafe-math-optimizations
+ * -ffinite-math-only
+ * -fno-errno-math
+ * -fno-signaling-nans
+ * -fno-rounding-math
+ * -fcx-limited-range
+ * -fno-signed-zeros.
+ *
+ * -ffinite-math-only means isnan() and isinf() detection may not work properly.
+ */
+
+/**
+ * Returns the unsigned integer layout of a float.
+ */
+inline constexpr unsigned float_as_unsigned(float f) {
+ // gnu++20 does not include std::bit_cast, so we use the builtin
+ // supported by gnu and clang. That being said, the latest gnu, clang, and msvc
+ // compilers all support std::bit_cast so update when language support is upgraded.
+ // return std::bit_cast<unsigned>(f);
+
+ return __builtin_bit_cast(unsigned, f);
+}
+
+/**
+ * Returns true if the float is nan regardless of -ffast-math compilation.
+ */
+inline constexpr bool safe_isnan(float f) {
+ // float is signed-magnitude, so shift sign bit out to do nan comparison.
+ // (This works for ILP32 / LP64 as the sign bit is removed by the shift).
+ // https://en.wikipedia.org/wiki/Single-precision_floating-point_format
+ return float_as_unsigned(f) << 1 >= 0xff800001 << 1;
+}
+
+/**
+ * Returns true if the float is infinite (pos or neg) regardless of -ffast-math compilation.
+ */
+inline constexpr bool safe_isinf(float f) {
+ // float is signed-magnitude, so shift sign bit out to do inf comparison.
+ // (This works for ILP32 / LP64 as the sign bit is removed by the shift).
+ // https://en.wikipedia.org/wiki/Single-precision_floating-point_format
+ return float_as_unsigned(f) << 1 == 0xff800000 << 1;
+}
+
// safe_sub_overflow is used ensure that subtraction occurs in the same native
// type with proper 2's complement overflow. Without calling this function, it
// is possible, for example, that optimizing compilers may elect to treat 32 bit
diff --git a/audio_utils/include/audio_utils/threads.h b/audio_utils/include/audio_utils/threads.h
new file mode 100644
index 00000000..2bf59eba
--- /dev/null
+++ b/audio_utils/include/audio_utils/threads.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <sys/syscall.h> // SYS_gettid
+#include <unistd.h> // bionic gettid
+#include <utils/Errors.h> // status_t
+
+namespace android::audio_utils {
+
+/*
+ * Some basic priority definitions from linux,
+ * see MACROs in common/include/linux/sched/prio.h.
+ *
+ * On device limits may be found with the following command $ adb shell chrt -m
+ */
+inline constexpr int kMaxNice = 19; // inclusive
+inline constexpr int kMinNice = -20; // inclusive
+inline constexpr int kNiceWidth = (kMaxNice - kMinNice + 1);
+inline constexpr int kMinRtPrio = 1; // inclusive
+inline constexpr int kMaxRtPrio = 100; // [sic] exclusive
+inline constexpr int kMaxPrio = kMaxRtPrio + kNiceWidth; // [sic] exclusive
+inline constexpr int kDefaultPrio = kMaxRtPrio + kNiceWidth / 2;
+
+/*
+ * The following conversion routines follow the linux equivalent.
+ * Here we use the term "unified priority" as the linux normal_prio.
+ *
+ * See common/kernel/sched/core.c __normal_prio().
+ */
+
+/**
+ * Convert CFS (SCHED_OTHER) nice to unified priority.
+ */
+inline int nice_to_unified_priority(int nice) {
+ return kDefaultPrio + nice;
+}
+
+/**
+ * Convert unified priority to CFS (SCHED_OTHER) nice.
+ *
+ * Some unified priorities are not CFS, they will be clamped in range.
+ * Use is_cfs_priority() to check if a CFS priority.
+ */
+inline int unified_priority_to_nice(int priority) {
+ return std::clamp(priority - kDefaultPrio, kMinNice, kMaxNice);
+}
+
+/**
+ * Convert SCHED_FIFO/SCHED_RR rtprio 1 - 99 to unified priority 98 to 0.
+ */
+inline int rtprio_to_unified_priority(int rtprio) {
+ return kMaxRtPrio - 1 - rtprio;
+}
+
+/**
+ * Convert unified priority 0 to 98 to SCHED_FIFO/SCHED_RR rtprio 99 to 1.
+ *
+ * Some unified priorities are not real time, they will be clamped in range.
+ * Use is_realtime_priority() to check if real time priority.
+ */
+inline int unified_priority_to_rtprio(int priority) {
+ return std::clamp(kMaxRtPrio - 1 - priority, kMinRtPrio, kMaxRtPrio - 1);
+}
+
+/**
+ * Returns whether the unified priority is realtime.
+ */
+inline bool is_realtime_priority(int priority) {
+ return priority >= 0 && priority < kMaxRtPrio; // note this allows the unified value 99.
+}
+
+/**
+ * Returns whether the unified priority is CFS.
+ */
+inline bool is_cfs_priority(int priority) {
+ return priority >= kMaxRtPrio && priority < kMaxPrio;
+}
+
+/**
+ * Returns the linux thread id.
+ *
+ * We use gettid() which is available on bionic libc and modern glibc;
+ * for other libc, we syscall directly.
+ *
+ * This is not the same as std::thread::get_id() which returns pthread_self().
+ */
+pid_t inline gettid_wrapper() {
+#if defined(__BIONIC__)
+ return ::gettid();
+#else
+ return syscall(SYS_gettid);
+#endif
+}
+
+/*
+ * set_thread_priority() and get_thread_priority()
+ * both use the unified scheduler priority, where a lower value represents
+ * increasing priority.
+ *
+ * The linux kernel unified scheduler priority values are as follows:
+ * 0 - 98 (A real time priority rtprio between 99 and 1)
+ * 100 - 139 (A Completely Fair Scheduler niceness between -20 and 19)
+ *
+ * Real time schedulers (SCHED_FIFO and SCHED_RR) have rtprio between 1 and 99,
+ * where 1 is the lowest and 99 is the highest.
+ *
+ * The Completely Fair Scheduler (also known as SCHED_OTHER) has a
+ * nice value between 19 and -20, where 19 is the lowest and -20 the highest.
+ *
+ * Note: the unified priority is reported on /proc/<tid>/stat file as "prio".
+ *
+ * See common/kernel/sched/debug.c proc_sched_show_task().
+ */
+
+/**
+ * Sets the priority of tid to a unified priority.
+ *
+ * The range of priority is 0 through 139, inclusive.
+ * A priority value of 99 is changed to 98.
+ */
+status_t set_thread_priority(pid_t tid, int priority);
+
+/**
+ * Returns the unified priority of the tid.
+ *
+ * A negative number represents error.
+ */
+int get_thread_priority(int tid);
+
+} // namespace android::audio_utils
diff --git a/audio_utils/mutex.cpp b/audio_utils/mutex.cpp
new file mode 100644
index 00000000..a219614c
--- /dev/null
+++ b/audio_utils/mutex.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <audio_utils/mutex.h>
+
+#define LOG_TAG "audio_utils::mutex"
+#include <utils/Log.h>
+
+#include <com_android_media_audioserver.h>
+
+namespace android::audio_utils {
+
+bool mutex_get_enable_flag() {
+ static const bool enable = []() {
+ const bool flag = com::android::media::audioserver::mutex_priority_inheritance();
+ ALOGD("get_enable_flag: mutex_priority_inheritance: %s", flag ? "true" : "false");
+ return flag;
+ }();
+ return enable;
+}
+
+// Define mutex::get_mutex_stat_array here because header-only ODR inline linking
+// results in multiple objects if included into multiple shared libraries.
+template<>
+mutex::stat_array_t& mutex::get_mutex_stat_array() {
+ static stat_array_t stat_array{};
+ return stat_array;
+}
+
+// Define mutex::get_registry here because header-only ODR inline linking
+// results in multiple objects if included into multiple shared libraries.
+template<>
+mutex::thread_registry_t& mutex::get_registry() {
+ static thread_registry_t thread_registry{};
+ return thread_registry;
+}
+
+} // namespace android::audio_utils
diff --git a/audio_utils/tests/Android.bp b/audio_utils/tests/Android.bp
index 4533e56a..fbf09617 100644
--- a/audio_utils/tests/Android.bp
+++ b/audio_utils/tests/Android.bp
@@ -8,6 +8,49 @@ package {
default_applicable_licenses: ["system_media_license"],
}
+cc_defaults {
+ name: "audio_math_test_defaults",
+ host_supported: true,
+
+ srcs: [
+ "audio_math_tests.cpp"
+ ],
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libaudioutils",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
+
+cc_test {
+ name: "audio_fast_math_tests",
+ defaults: [
+ "audio_math_test_defaults",
+ ],
+ cflags: [
+ "-DFAST_MATH_ENABLED",
+ "-ffast-math",
+ ],
+}
+
+cc_test {
+ name: "audio_math_tests",
+ defaults: [
+ "audio_math_test_defaults",
+ ],
+}
+
cc_test {
name: "audio_mutex_tests",
host_supported: true,
@@ -16,10 +59,36 @@ cc_test {
"audio_mutex_tests.cpp",
],
- static_libs: [
+ shared_libs: [
"libaudioutils",
"libbase",
"liblog",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wthread-safety",
+ ],
+}
+
+cc_test {
+ name: "audio_thread_tests",
+
+ srcs: [
+ "audio_thread_tests.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libaudioutils",
],
cflags: [
diff --git a/audio_utils/tests/audio_math_tests.cpp b/audio_utils/tests/audio_math_tests.cpp
new file mode 100644
index 00000000..45df16d5
--- /dev/null
+++ b/audio_utils/tests/audio_math_tests.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "audio_math_tests"
+
+#include <audio_utils/safe_math.h>
+
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+TEST(audio_math_tests, safe_isnan) {
+ const auto nf = std::nanf("");
+ const bool std_isnan = std::isnan(nf);
+ const bool eq_isnan = nf != nf;
+ const bool au_isnan = android::audio_utils::safe_isnan(nf);
+
+#ifndef FAST_MATH_ENABLED
+ EXPECT_TRUE(std_isnan); // not always true for -ffast-math, assumed false
+ EXPECT_TRUE(eq_isnan); // not always true for -ffast-math
+#endif
+
+ EXPECT_TRUE(au_isnan);
+ constexpr bool not_a_nan = android::audio_utils::safe_isnan(1.f);
+ EXPECT_FALSE(not_a_nan);
+ EXPECT_FALSE(android::audio_utils::safe_isnan(std::numeric_limits<float>::infinity()));
+ EXPECT_FALSE(android::audio_utils::safe_isnan(std::numeric_limits<float>::max()));
+ EXPECT_FALSE(android::audio_utils::safe_isnan(std::numeric_limits<float>::min()));
+
+ EXPECT_TRUE(android::audio_utils::safe_isnan(nan("")));
+
+ ALOGD("%s: std::isnan:%d eq_isnan:%d audio_utils::isnan:%d",
+ __func__, std_isnan, eq_isnan, au_isnan);
+}
+
+TEST(audio_math_tests, safe_isinf) {
+ const auto inf = std::numeric_limits<float>::infinity();
+ const bool std_isinf = std::isinf(inf);
+ const bool eq_isinf = inf == std::numeric_limits<float>::infinity();
+ const bool au_isinf = android::audio_utils::safe_isinf(inf);
+
+#ifndef FAST_MATH_ENABLED
+ EXPECT_TRUE(std_isinf); // not always true for -ffast-math, assumed false
+#endif
+
+ EXPECT_TRUE(eq_isinf);
+ EXPECT_TRUE(au_isinf);
+ constexpr bool not_a_inf = android::audio_utils::safe_isinf(1.f);
+ EXPECT_FALSE(not_a_inf);
+ EXPECT_FALSE(android::audio_utils::safe_isinf(std::nanf("")));
+ EXPECT_FALSE(android::audio_utils::safe_isinf(std::numeric_limits<float>::max()));
+ EXPECT_FALSE(android::audio_utils::safe_isinf(std::numeric_limits<float>::min()));
+
+ EXPECT_TRUE(android::audio_utils::safe_isinf(std::numeric_limits<double>::infinity()));
+
+ ALOGD("%s: std::isinf:%d eq_isinf:%d audio_utils::isinf:%d",
+ __func__, std_isinf, eq_isinf, au_isinf);
+}
diff --git a/audio_utils/tests/audio_mutex_tests.cpp b/audio_utils/tests/audio_mutex_tests.cpp
index 3e6c2695..17e98744 100644
--- a/audio_utils/tests/audio_mutex_tests.cpp
+++ b/audio_utils/tests/audio_mutex_tests.cpp
@@ -17,6 +17,15 @@
#include <audio_utils/mutex.h>
#include <gtest/gtest.h>
+#include <thread>
+
+// Currently tests mutex priority-inheritance (or not) based on flag
+// adb shell setprop \
+// persist.device_config.aconfig_flags.media_audio.\
+// com.android.media.audio.flags.mutex_priority_inheritance true
+//
+// TODO(b/209491695) enable both PI/non-PI mutex tests regardless of flag.
+
namespace android {
namespace audio_locks {
@@ -213,7 +222,7 @@ private:
int v3_ GUARDED_BY(cap3) = 3;
};
-TEST(audio_lock_tests, Container) {
+TEST(audio_mutex_tests, Container) {
Container c;
EXPECT_EQ(1, c.value1()); // success
@@ -236,7 +245,7 @@ TEST(audio_lock_tests, Container) {
// see that mutex checking is done without knowledge of
// the actual implementation.
-TEST(audio_lock_tests, Interface) {
+TEST(audio_mutex_tests, Interface) {
Container c;
IContainer *i = static_cast<IContainer*>(&c);
@@ -254,6 +263,272 @@ TEST(audio_lock_tests, Interface) {
audio_utils::lock_guard l(i->mutex1());
EXPECT_EQ(3, i->combo12_l()); // success
}
+
+ ALOGD("%s: %s", __func__, audio_utils::mutex::all_stats_to_string().c_str());
+}
+
+TEST(audio_mutex_tests, Stack) {
+ android::audio_utils::atomic_stack<int, int, 2> as;
+
+ // set up stack
+ EXPECT_EQ(0UL, as.size());
+ as.push(1, 10);
+ EXPECT_EQ(1UL, as.size());
+ as.push(2, 20);
+ EXPECT_EQ(2UL, as.size());
+
+ // 3rd item exceeds the stack capacity.
+ as.push(3, 30);
+ // 2 items tracked (subset)
+ EXPECT_EQ(2UL, as.size());
+ // 3 items total.
+ EXPECT_EQ(3UL, as.true_size());
+
+ const auto& bot = as.bottom();
+ const auto& top = as.top();
+
+ // these are the 2 items tracked:
+ EXPECT_EQ(1, bot.first.load());
+ EXPECT_EQ(10, bot.second.load());
+
+ EXPECT_EQ(3, top.first.load());
+ EXPECT_EQ(30, top.second.load());
+
+ // remove the bottom item.
+ EXPECT_EQ(true, as.remove(1));
+ EXPECT_EQ(1UL, as.size());
+ EXPECT_EQ(2UL, as.true_size());
+
+ // now remove the "virtual" item.
+ // (actually any non-existing item value works).
+ EXPECT_EQ(true, as.remove(2));
+ EXPECT_EQ(1UL, as.size());
+ EXPECT_EQ(1UL, as.true_size());
+
+ // now an invalid removal
+ EXPECT_EQ(false, as.remove(5));
+ EXPECT_EQ(1UL, as.size());
+ EXPECT_EQ(1UL, as.true_size());
+
+ // now remove the final item.
+ EXPECT_EQ(true, as.remove(3));
+ EXPECT_EQ(0UL, as.size());
+ EXPECT_EQ(0UL, as.true_size());
+}
+
+TEST(audio_mutex_tests, RecursiveLockDetection) {
+ constexpr pid_t pid = 0; // avoid registry shutdown.
+ android::audio_utils::thread_mutex_info<int, int, 8 /* stack depth */> tmi(pid);
+
+ // set up stack
+ tmi.push_held(50, 1);
+ tmi.push_held(40, 2);
+ tmi.push_held(30, 3);
+ EXPECT_EQ(3UL, tmi.stack().size());
+
+ // remove bottom.
+ tmi.remove_held(50);
+ EXPECT_EQ(2UL, tmi.stack().size());
+
+ // test recursive lock detection.
+
+ // same order, same item is recursive.
+ const auto& recursive = tmi.check_held(30, 3);
+ EXPECT_EQ(30, recursive.first.load());
+ EXPECT_EQ(3, recursive.second.load());
+
+ // same order but different item (10 != 30) is OK.
+ const auto& nil = tmi.check_held(10, 3);
+ EXPECT_EQ(0, nil.first.load());
+ EXPECT_EQ(0, nil.second.load());
+}
+
+TEST(audio_mutex_tests, OrderDetection) {
+ constexpr pid_t pid = 0; // avoid registry shutdown.
+ android::audio_utils::thread_mutex_info<int, int, 8 /* stack depth */> tmi(pid);
+
+ // set up stack
+ tmi.push_held(50, 1);
+ tmi.push_held(40, 2);
+ tmi.push_held(30, 3);
+ EXPECT_EQ(3UL, tmi.stack().size());
+
+ // remove middle
+ tmi.remove_held(40);
+ EXPECT_EQ(2UL, tmi.stack().size());
+
+ // test inversion detection.
+
+ // lower order is a problem 1 < 3.
+ const auto& inversion = tmi.check_held(1, 1);
+ EXPECT_EQ(30, inversion.first.load());
+ EXPECT_EQ(3, inversion.second.load());
+
+ // higher order is OK.
+ const auto& nil2 = tmi.check_held(4, 4);
+ EXPECT_EQ(0, nil2.first.load());
+ EXPECT_EQ(0, nil2.second.load());
+}
+
+// Test that the mutex aborts on recursion (if the abort flag is set).
+
+TEST(audio_mutex_tests, FatalRecursiveMutex)
+NO_THREAD_SAFETY_ANALYSIS {
+ if (!android::audio_utils::AudioMutexAttributes::abort_on_recursion_check_
+ || !audio_utils::mutex_get_enable_flag()) {
+ ALOGD("Test FatalRecursiveMutex skipped");
+ return;
+ }
+
+ using Mutex = android::audio_utils::mutex;
+ using LockGuard = android::audio_utils::lock_guard;
+
+ Mutex m;
+ LockGuard lg(m);
+
+ // Can't lock ourselves again.
+ ASSERT_DEATH(m.lock(), ".*recursive mutex.*");
+}
+
+// Test that the mutex aborts on lock order inversion (if the abort flag is set).
+
+TEST(audio_mutex_tests, FatalLockOrder)
+NO_THREAD_SAFETY_ANALYSIS {
+ if (!android::audio_utils::AudioMutexAttributes::abort_on_order_check_
+ || !audio_utils::mutex_get_enable_flag()) {
+ ALOGD("Test FatalLockOrder skipped");
+ return;
+ }
+
+ using Mutex = android::audio_utils::mutex;
+ using LockGuard = android::audio_utils::lock_guard;
+
+ Mutex m1{(android::audio_utils::AudioMutexAttributes::order_t)1};
+ Mutex m2{(android::audio_utils::AudioMutexAttributes::order_t)2};
+
+ LockGuard lg2(m2);
+ // m1 must be locked before m2 as 1 < 2.
+ ASSERT_DEATH(m1.lock(), ".*mutex order.*");
+}
+
+// Test that the mutex aborts on lock order inversion (if the abort flag is set).
+
+TEST(audio_mutex_tests, UnexpectedUnlock)
+NO_THREAD_SAFETY_ANALYSIS {
+ if (!android::audio_utils::AudioMutexAttributes::abort_on_invalid_unlock_
+ || !audio_utils::mutex_get_enable_flag()) {
+ ALOGD("Test UnexpectedUnlock skipped");
+ return;
+ }
+
+ using Mutex = android::audio_utils::mutex;
+
+ Mutex m1{(android::audio_utils::AudioMutexAttributes::order_t)1};
+ ASSERT_DEATH(m1.unlock(), ".*mutex unlock.*");
+}
+
+// Test the deadlock detection algorithm for a single wait chain
+// (no cycle).
+
+TEST(audio_mutex_tests, DeadlockDetection) {
+ using Mutex = android::audio_utils::mutex;
+ using UniqueLock = android::audio_utils::unique_lock;
+ using ConditionVariable = android::audio_utils::condition_variable;
+
+ // order checked below.
+ constexpr size_t kOrder1 = 1;
+ constexpr size_t kOrder2 = 2;
+ constexpr size_t kOrder3 = 3;
+ static_assert(Mutex::attributes_t::order_size_ > kOrder3);
+
+ Mutex m1{static_cast<Mutex::attributes_t::order_t>(kOrder1)};
+ Mutex m2{static_cast<Mutex::attributes_t::order_t>(kOrder2)};
+ Mutex m3{static_cast<Mutex::attributes_t::order_t>(kOrder3)};
+ Mutex m4;
+ Mutex m;
+ ConditionVariable cv;
+ bool quit = false; // GUARDED_BY(m)
+ std::atomic<pid_t> tid1{}, tid2{}, tid3{}, tid4{};
+
+ std::thread t4([&]() {
+ UniqueLock ul4(m4);
+ UniqueLock ul(m);
+ tid4 = android::audio_utils::gettid_wrapper();
+ while (!quit) {
+ cv.wait(ul, [&]{ return quit; });
+ if (quit) break;
+ }
+ });
+
+ while (tid4 == 0) { usleep(1000); }
+
+ std::thread t3([&]() {
+ UniqueLock ul3(m3);
+ tid3 = android::audio_utils::gettid_wrapper();
+ UniqueLock ul4(m4);
+ });
+
+ while (tid3 == 0) { usleep(1000); }
+
+ std::thread t2([&]() {
+ UniqueLock ul2(m2);
+ tid2 = android::audio_utils::gettid_wrapper();
+ UniqueLock ul3(m3);
+ });
+
+ while (tid2 == 0) { usleep(1000); }
+
+ std::thread t1([&]() {
+ UniqueLock ul1(m1);
+ tid1 = android::audio_utils::gettid_wrapper();
+ UniqueLock ul2(m2);
+ });
+
+ while (tid1 == 0) { usleep(1000); }
+
+ // we know that the threads will now block in the proper order.
+ // however, we need to wait for the block to happen.
+ // this part is racy unless we check the thread state or use
+ // futexes directly in our mutex (which allows atomic accuracy of wait).
+ usleep(20000);
+
+ const auto deadlockInfo = android::audio_utils::mutex::deadlock_detection(tid1);
+
+ // no cycle.
+ EXPECT_EQ(false, deadlockInfo.has_cycle);
+
+ // thread1 is waiting on a chain of 3 other threads.
+ const auto chain = deadlockInfo.chain;
+ const size_t chain_size = chain.size();
+ EXPECT_EQ(3u, chain_size);
+
+ const auto default_idx = static_cast<size_t>(Mutex::attributes_t::order_default_);
+ if (chain_size > 0) {
+ EXPECT_EQ(tid2, chain[0].first);
+ EXPECT_EQ(Mutex::attributes_t::order_names_[kOrder2], chain[0].second);
+ }
+ if (chain_size > 1) {
+ EXPECT_EQ(tid3, chain[1].first);
+ EXPECT_EQ(Mutex::attributes_t::order_names_[kOrder3], chain[1].second);
+ }
+ if (chain_size > 2) {
+ EXPECT_EQ(tid4, chain[2].first);
+ EXPECT_EQ(Mutex::attributes_t::order_names_[default_idx], chain[2].second);
+ }
+
+ ALOGD("%s", android::audio_utils::mutex::all_threads_to_string().c_str());
+
+ {
+ UniqueLock ul(m);
+
+ quit = true;
+ cv.notify_one();
+ }
+
+ t4.join();
+ t3.join();
+ t2.join();
+ t1.join();
}
} // namespace android
diff --git a/audio_utils/tests/audio_thread_tests.cpp b/audio_utils/tests/audio_thread_tests.cpp
new file mode 100644
index 00000000..360fc3ad
--- /dev/null
+++ b/audio_utils/tests/audio_thread_tests.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <audio_utils/threads.h>
+#include <gtest/gtest.h>
+
+using namespace android;
+using namespace android::audio_utils;
+
+TEST(audio_thread_tests, conversion) {
+ EXPECT_EQ(120, kDefaultPrio);
+
+ EXPECT_EQ(kMaxRtPrio, nice_to_unified_priority(kMinNice));
+ EXPECT_EQ(kMaxPrio - 1, nice_to_unified_priority(kMaxNice));
+
+ EXPECT_EQ(kMinNice, unified_priority_to_nice(kMaxRtPrio));
+ EXPECT_EQ(kMaxNice, unified_priority_to_nice(kMaxPrio - 1));
+
+ EXPECT_EQ(kMaxRtPrio - 1, unified_priority_to_rtprio(0));
+ EXPECT_EQ(kMinRtPrio, unified_priority_to_rtprio(98));
+
+ EXPECT_EQ(0, rtprio_to_unified_priority(kMaxRtPrio - 1));
+ EXPECT_EQ(98, rtprio_to_unified_priority(kMinRtPrio));
+
+ EXPECT_FALSE(is_cfs_priority(kMaxRtPrio-1));
+ EXPECT_TRUE(is_cfs_priority(kMaxRtPrio)); // note the bound is exclusive
+
+ EXPECT_TRUE(is_realtime_priority(kMaxRtPrio-1));
+ EXPECT_FALSE(is_realtime_priority(kMaxRtPrio)); // the bound is exclusive.
+}
+
+TEST(audio_thread_tests, priority) {
+ const auto tid = gettid_wrapper();
+ const int priority = get_thread_priority(tid);
+ ASSERT_GE(priority, 0);
+
+ constexpr int kPriority110 = 110;
+ EXPECT_EQ(NO_ERROR, set_thread_priority(tid, kPriority110));
+ EXPECT_EQ(kPriority110, get_thread_priority(tid));
+
+ constexpr int kPriority130 = 130;
+ EXPECT_EQ(NO_ERROR, set_thread_priority(tid, kPriority130));
+ EXPECT_EQ(kPriority130, get_thread_priority(tid));
+
+ // Requires privilege to go RT.
+ // constexpr int kPriority98 = 98;
+ // EXPECT_EQ(NO_ERROR, set_thread_priority(tid, kPriority98));
+ // EXPECT_EQ(kPriority98, get_thread_priority(tid));
+
+ EXPECT_EQ(NO_ERROR, set_thread_priority(tid, priority));
+}
diff --git a/audio_utils/tests/fdtostring_tests.cpp b/audio_utils/tests/fdtostring_tests.cpp
index 683ca562..ab785ab2 100644
--- a/audio_utils/tests/fdtostring_tests.cpp
+++ b/audio_utils/tests/fdtostring_tests.cpp
@@ -14,45 +14,75 @@
* limitations under the License.
*/
-//#define LOG_NDEBUG 0
-#define LOG_TAG "audio_utils_fdtostring_tests"
-#include <log/log.h>
-
#include <audio_utils/FdToString.h>
+
+#include <signal.h>
+#include <chrono>
+
#include <gtest/gtest.h>
using namespace android::audio_utils;
TEST(audio_utils_fdtostring, basic) {
+ signal(SIGPIPE, SIG_IGN);
const std::string PREFIX{"aa "};
- const std::string TEST_STRING{"hello world"};
+ const std::string TEST_STRING{"hello world\n"};
- FdToString fdToString(PREFIX);
- const int fd = fdToString.fd();
+ auto writer_opt = FdToString::createWriter(PREFIX);
+ ASSERT_TRUE(writer_opt.has_value());
+ FdToString::Writer& writer = *writer_opt;
+ const int fd = writer.borrowFdUnsafe();
ASSERT_TRUE(fd >= 0);
write(fd, TEST_STRING.c_str(), TEST_STRING.size());
- const std::string result = fdToString.getStringAndClose();
-
+ const std::string result = FdToString::closeWriterAndGetString(std::move(writer));
ASSERT_EQ((PREFIX + TEST_STRING), result);
}
-TEST(audio_utils_fdtostring, multilines) {
+TEST(audio_utils_fdtostring, multiline) {
+ signal(SIGPIPE, SIG_IGN);
const std::string PREFIX{"aa "};
- const std::string DELIM{"\n"};
- const std::string TEST_STRING1{"hello world\n"};
- const std::string TEST_STRING2{"goodbye\n"};
+ const std::string INPUT[] = {"hello\n", "pt1", "pt2 ", "\n", "\n", "pt3\n", "pt4"};
+ const std::string GOLDEN = "aa hello\naa pt1pt2 \naa \naa pt3\npt4";
+
+ auto writer_opt = FdToString::createWriter(PREFIX);
+ ASSERT_TRUE(writer_opt.has_value());
+ FdToString::Writer& writer = *writer_opt;
+ const int fd = writer.borrowFdUnsafe();
+ ASSERT_TRUE(fd >= 0);
+
+ for (const auto& str : INPUT) {
+ write(fd, str.c_str(), str.size());
+ }
+
+ ASSERT_EQ(FdToString::closeWriterAndGetString(std::move(writer)), GOLDEN);
+}
+
+TEST(audio_utils_fdtostring, blocking) {
+ signal(SIGPIPE, SIG_IGN);
+ const std::string PREFIX{"- "};
+ const std::string INPUT[] = {"1\n", "2\n", "3\n", "4\n", "5\n"};
+ const std::string GOLDEN = "- 1\n- 2\n- 3\n- 4\n- 5\n";
+
+ auto writer_opt = FdToString::createWriter(PREFIX, std::chrono::milliseconds{200});
- FdToString fdToString(PREFIX);
- const int fd = fdToString.fd();
+ ASSERT_TRUE(writer_opt.has_value());
+ FdToString::Writer& writer = *writer_opt;
+ const int fd = writer.borrowFdUnsafe();
ASSERT_TRUE(fd >= 0);
- write(fd, TEST_STRING1.c_str(), TEST_STRING1.size());
- write(fd, DELIM.c_str(), DELIM.size()); // double newline
- write(fd, TEST_STRING2.c_str(), TEST_STRING2.size());
+ // Chosen so that we shouldn't finish the entire array before the timeout
+ constexpr auto WAIT = std::chrono::milliseconds{90};
- const std::string result = fdToString.getStringAndClose();
+ int count = 0;
+ for (const auto& str : INPUT) {
+ ASSERT_LT(count, 4) << "The reader has timed out, write should have failed by now";
+ if (write(fd, str.c_str(), str.size()) < 0) break;
+ std::this_thread::sleep_for(WAIT);
+ count++;
+ }
- ASSERT_EQ((PREFIX + TEST_STRING1 + PREFIX + DELIM + PREFIX + TEST_STRING2), result);
+ ASSERT_EQ(FdToString::closeWriterAndGetString(std::move(writer)).substr(0, 8),
+ GOLDEN.substr(0, 8)) << "Format mistake";
}
diff --git a/audio_utils/tests/generate_mutex_order.cpp b/audio_utils/tests/generate_mutex_order.cpp
index 29cea791..0f9f45dd 100644
--- a/audio_utils/tests/generate_mutex_order.cpp
+++ b/audio_utils/tests/generate_mutex_order.cpp
@@ -41,8 +41,10 @@ constexpr const char* mutexes[] {
// 4) AudioFlinger -> ThreadBase -> EffectChain -> EffectBase(EffectModule)
// 5) EffectHandle -> ThreadBase -> EffectChain -> EffectBase(EffectModule)
- "AudioFlinger_Mutex",
"EffectHandle_Mutex",
+ "EffectBase_PolicyMutex", // held for AudioSystem::registerEffect, must come
+ // after EffectHandle_Mutex.
+ "AudioFlinger_Mutex",
"AudioFlinger_HardwareMutex",
"DeviceEffectManager_Mutex",
"PatchCommandThread_Mutex",
@@ -50,6 +52,7 @@ constexpr const char* mutexes[] {
"AudioFlinger_ClientMutex",
"MelReporter_Mutex",
"EffectChain_Mutex",
+ "DeviceEffectProxy_ProxyMutex", // used for device effects (which have no chain).
"EffectBase_Mutex",
// These mutexes are in leaf objects
@@ -62,6 +65,10 @@ constexpr const char* mutexes[] {
"PassthruPatchRecord_ReadMutex",
"PatchCommandThread_ListenerMutex",
"PlaybackThread_AudioTrackCbMutex",
+ "MediaLogNotifier_Mutex",
+ "OtherMutex", // DO NOT CHANGE THIS: OtherMutex is used for mutexes without a specified order.
+ // An OtherMutex will always be the lowest order mutex and cannot acquire
+ // another named mutex while being held.
};
using namespace std;
@@ -70,7 +77,28 @@ using namespace std;
// ordering and exclusion as listed above.
int main() {
- cout << "// Capabilities in priority order\n"
+ cout << "// Lock order\n";
+ cout << "enum class MutexOrder : uint32_t {\n";
+
+ for (size_t i = 0; i < size(mutexes); ++i) {
+ cout << " k" << mutexes[i] << " = " << i << ",\n";
+ }
+ cout << " kSize = " << size(mutexes) << ",\n";
+ cout << "};\n";
+
+ cout << "\n// Lock by name\n";
+ cout << "inline constexpr const char* const gMutexNames[] = {\n";
+ for (size_t i = 0; i < size(mutexes); ++i) {
+ cout << " \"" << mutexes[i] << "\",\n";
+ }
+ cout << "};\n";
+
+ cout << "\n// Forward declarations\n";
+ cout << "class AudioMutexAttributes;\n";
+ cout << "template <typename T> class mutex_impl;\n";
+ cout << "using mutex = mutex_impl<AudioMutexAttributes>;\n";
+
+ cout << "\n// Capabilities in priority order\n"
<< "// (declaration only, value is nullptr)\n";
const char *last = nullptr;
for (auto mutex : mutexes) {
diff --git a/audio_utils/threads.cpp b/audio_utils/threads.cpp
new file mode 100644
index 00000000..aeaf59af
--- /dev/null
+++ b/audio_utils/threads.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "audio_utils::threads"
+
+#include <audio_utils/threads.h>
+
+#include <algorithm> // std::clamp
+#include <errno.h>
+#include <sched.h> // scheduler
+#include <sys/resource.h>
+#include <utils/Errors.h> // status_t
+#include <utils/Log.h>
+
+namespace android::audio_utils {
+
+/**
+ * Sets the unified priority of the tid.
+ */
+status_t set_thread_priority(pid_t tid, int priority) {
+ if (is_realtime_priority(priority)) {
+ // audio processes are designed to work with FIFO, not RR.
+ constexpr int new_policy = SCHED_FIFO;
+ const int rtprio = unified_priority_to_rtprio(priority);
+ struct sched_param param {
+ .sched_priority = rtprio,
+ };
+ if (sched_setscheduler(tid, new_policy, &param) != 0) {
+ ALOGW("%s: Cannot set FIFO priority for tid %d to policy %d rtprio %d %s",
+ __func__, tid, new_policy, rtprio, strerror(errno));
+ return -errno;
+ }
+ return NO_ERROR;
+ } else if (is_cfs_priority(priority)) {
+ const int policy = sched_getscheduler(tid);
+ const int nice = unified_priority_to_nice(priority);
+ if (policy != SCHED_OTHER) {
+ struct sched_param param{};
+ constexpr int new_policy = SCHED_OTHER;
+ if (sched_setscheduler(tid, new_policy, &param) != 0) {
+ ALOGW("%s: Cannot set CFS priority for tid %d to policy %d nice %d %s",
+ __func__, tid, new_policy, nice, strerror(errno));
+ return -errno;
+ }
+ }
+ if (setpriority(PRIO_PROCESS, tid, nice) != 0) return -errno;
+ return NO_ERROR;
+ } else {
+ return BAD_VALUE;
+ }
+}
+
+/**
+ * Returns the unified priority of the tid.
+ *
+ * A negative number represents error.
+ */
+int get_thread_priority(int tid) {
+ const int policy = sched_getscheduler(tid);
+ if (policy < 0) return -errno;
+
+ if (policy == SCHED_OTHER) {
+ errno = 0; // negative return value valid, so check errno change.
+ const int nice = getpriority(PRIO_PROCESS, tid);
+ if (errno != 0) return -errno;
+ return nice_to_unified_priority(nice);
+ } else if (policy == SCHED_FIFO || policy == SCHED_RR) {
+ struct sched_param param{};
+ if (sched_getparam(tid, &param) < 0) return -errno;
+ return rtprio_to_unified_priority(param.sched_priority);
+ } else {
+ return INVALID_OPERATION;
+ }
+}
+
+} // namespace android::audio_utils
diff --git a/camera/Android.bp b/camera/Android.bp
index 019e892e..f144e29f 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -67,7 +67,7 @@ cc_library_shared {
local_include_dirs: ["include"],
static_libs: [
- "android.hardware.camera.metadata-V2-ndk",
+ "android.hardware.camera.metadata-V3-ndk",
],
cflags: [
diff --git a/camera/docs/CameraMetadataEnums.mako b/camera/docs/CameraMetadataEnums.mako
index ee2431e0..0ed6ad64 100644
--- a/camera/docs/CameraMetadataEnums.mako
+++ b/camera/docs/CameraMetadataEnums.mako
@@ -51,6 +51,9 @@ ${value.sdk_notes | javadoc(metadata)}\
% if value.visibility == 'test':
@TestApi
% endif
+ % if value.aconfig_flag:
+ @FlaggedApi(Flags.FLAG_${value.aconfig_flag | jkey_identifier})
+ % endif
public static final int ${jenum_value(entry, value)} = ${enum_calculate_value_string(value)};
% endfor
diff --git a/camera/docs/CameraMetadataKeys.mako b/camera/docs/CameraMetadataKeys.mako
index 6af0cdf9..376b5cea 100644
--- a/camera/docs/CameraMetadataKeys.mako
+++ b/camera/docs/CameraMetadataKeys.mako
@@ -42,10 +42,11 @@
concatenated_info = description + details + extra_detail
%>\
## Glue description and details together before javadoc-izing. Otherwise @see in middle of javadoc.
+## Avoid @see across differently-flagged API entries for now.
${concatenated_info | javadoc(metadata)}\
% if entry.enum and not (entry.typedef and entry.typedef.languages.get('java')):
% for value in entry.enum.values:
- % if not value.hidden:
+ % if not value.hidden and (value.aconfig_flag == entry.aconfig_flag):
* @see #${jenum_value(entry, value)}
% endif
% endfor
@@ -68,6 +69,9 @@ ${entry.deprecation_description | javadoc(metadata)}
% if entry.synthetic:
@SyntheticKey
% endif
+ % if entry.aconfig_flag:
+ @FlaggedApi(Flags.FLAG_${entry.aconfig_flag | jkey_identifier})
+ % endif
public static final Key<${jtype_boxed(entry)}> ${entry.name | jkey_identifier} =
new Key<${jtype_boxed(entry)}>("${entry.name}", ${jkey_type_token(entry)});
</%def>\
diff --git a/camera/docs/camera_device_info.proto b/camera/docs/camera_device_info.proto
index 2f922cbd..3c58eda2 100644
--- a/camera/docs/camera_device_info.proto
+++ b/camera/docs/camera_device_info.proto
@@ -141,7 +141,12 @@ message CameraDeviceInfo {
optional RangeFloat android_control_zoomRatioRange = 131090;
repeated int32 android_control_availableSettingsOverrides = 131091;
optional bool android_control_autoframingAvailable = 131092;
+ optional RangeFloat android_control_lowLightBoostInfoLuminanceRange = 131093;
repeated int32 android_edge_availableEdgeModes = 262144;
+ optional int32 android_flash_singleStrengthMaxLevel = 327680;
+ optional int32 android_flash_singleStrengthDefaultLevel = 327681;
+ optional int32 android_flash_torchStrengthMaxLevel = 327682;
+ optional int32 android_flash_torchStrengthDefaultLevel = 327683;
optional bool android_flash_info_available = 393216;
optional int32 android_flash_info_strengthMaximumLevel = 393217;
optional int32 android_flash_info_strengthDefaultLevel = 393218;
@@ -223,6 +228,7 @@ message CameraDeviceInfo {
optional int32 android_info_supportedHardwareLevel = 1441792;
optional string android_info_version = 1441793;
optional DeviceStateSensorOrientationMap android_info_deviceStateSensorOrientationMap = 1441794;
+ optional int32 android_info_sessionConfigurationQueryVersion = 1441795;
optional int32 android_sync_maxLatency = 1572864;
optional int32 android_reprocess_maxCaptureStall = 1638400;
optional bool android_depth_depthIsExclusive = 1703936;
diff --git a/camera/docs/docs.html b/camera/docs/docs.html
index 2ead8826..055ff2a6 100644
--- a/camera/docs/docs.html
+++ b/camera/docs/docs.html
@@ -266,6 +266,8 @@
><a href="#static_android.control.availableSettingsOverrides">android.control.availableSettingsOverrides</a></li>
<li
><a href="#static_android.control.autoframingAvailable">android.control.autoframingAvailable</a></li>
+ <li
+ ><a href="#static_android.control.lowLightBoostInfoLuminanceRange">android.control.lowLightBoostInfoLuminanceRange</a></li>
</ul>
</li>
<li>
@@ -337,6 +339,8 @@
><a href="#dynamic_android.control.autoframing">android.control.autoframing</a></li>
<li
><a href="#dynamic_android.control.autoframingState">android.control.autoframingState</a></li>
+ <li
+ ><a href="#dynamic_android.control.lowLightBoostState">android.control.lowLightBoostState</a></li>
</ul>
</li>
</ul> <!-- toc_section -->
@@ -393,6 +397,8 @@
><a href="#controls_android.flash.firingTime">android.flash.firingTime</a></li>
<li
><a href="#controls_android.flash.mode">android.flash.mode</a></li>
+ <li
+ ><a href="#controls_android.flash.strengthLevel">android.flash.strengthLevel</a></li>
</ul>
</li>
<li>
@@ -412,6 +418,14 @@
><a href="#static_android.flash.colorTemperature">android.flash.colorTemperature</a></li>
<li
><a href="#static_android.flash.maxEnergy">android.flash.maxEnergy</a></li>
+ <li
+ ><a href="#static_android.flash.singleStrengthMaxLevel">android.flash.singleStrengthMaxLevel</a></li>
+ <li
+ ><a href="#static_android.flash.singleStrengthDefaultLevel">android.flash.singleStrengthDefaultLevel</a></li>
+ <li
+ ><a href="#static_android.flash.torchStrengthMaxLevel">android.flash.torchStrengthMaxLevel</a></li>
+ <li
+ ><a href="#static_android.flash.torchStrengthDefaultLevel">android.flash.torchStrengthDefaultLevel</a></li>
</ul>
</li>
<li>
@@ -425,6 +439,8 @@
><a href="#dynamic_android.flash.mode">android.flash.mode</a></li>
<li
><a href="#dynamic_android.flash.state">android.flash.state</a></li>
+ <li
+ ><a href="#dynamic_android.flash.strengthLevel">android.flash.strengthLevel</a></li>
</ul>
</li>
</ul> <!-- toc_section -->
@@ -1115,6 +1131,12 @@
><a href="#dynamic_android.statistics.oisYShifts">android.statistics.oisYShifts</a></li>
<li
><a href="#dynamic_android.statistics.oisSamples">android.statistics.oisSamples</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.lensIntrinsicsSamples">android.statistics.lensIntrinsicsSamples</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.lensIntrinsicTimestamps">android.statistics.lensIntrinsicTimestamps</a></li>
+ <li
+ ><a href="#dynamic_android.statistics.lensIntrinsicSamples">android.statistics.lensIntrinsicSamples</a></li>
</ul>
</li>
</ul> <!-- toc_section -->
@@ -1213,6 +1235,8 @@
><a href="#static_android.info.deviceStateSensorOrientationMap">android.info.deviceStateSensorOrientationMap</a></li>
<li
><a href="#static_android.info.deviceStateOrientations">android.info.deviceStateOrientations</a></li>
+ <li
+ ><a href="#static_android.info.sessionConfigurationQueryVersion">android.info.sessionConfigurationQueryVersion</a></li>
</ul>
</li>
</ul> <!-- toc_section -->
@@ -1338,6 +1362,8 @@
<ul class="toc_section">
<li
><a href="#dynamic_android.logicalMultiCamera.activePhysicalId">android.logicalMultiCamera.activePhysicalId</a></li>
+ <li
+ ><a href="#dynamic_android.logicalMultiCamera.activePhysicalSensorCropRegion">android.logicalMultiCamera.activePhysicalSensorCropRegion</a></li>
</ul>
</li>
</ul> <!-- toc_section -->
@@ -2766,6 +2792,39 @@ other available AE modes.<wbr/></p>
be FLASH_<wbr/>REQUIRED after the camera device finishes AE scan and it's too dark without
flash.<wbr/></p></span>
</li>
+ <li>
+ <span class="entry_type_enum_name">ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY (v3.9)</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Like 'ON' but applies additional brightness boost in low light scenes.<wbr/></p>
+<p>When the scene lighting conditions are within the range defined by
+<a href="#static_android.control.lowLightBoostInfoLuminanceRange">android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<wbr/>Info<wbr/>Luminance<wbr/>Range</a> this mode will apply additional
+brightness boost.<wbr/></p>
+<p>This mode will automatically adjust the intensity of low light boost applied
+according to the scene lighting conditions.<wbr/> A darker scene will receive more boost
+while a brighter scene will receive less boost.<wbr/></p>
+<p>This mode can ignore the set target frame rate to allow more light to be captured
+which can result in choppier motion.<wbr/> The frame rate can extend to lower than the
+<a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a> but will not go below 10 FPS.<wbr/> This mode
+can also increase the sensor sensitivity gain which can result in increased luma
+and chroma noise.<wbr/> The sensor sensitivity gain can extend to higher values beyond
+<a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a>.<wbr/> This mode may also apply additional
+processing to recover details in dark and bright areas of the image,<wbr/>and noise
+reduction at high sensitivity gain settings to manage the trade-off between light
+sensitivity and capture noise.<wbr/></p>
+<p>This mode is restricted to two output surfaces.<wbr/> One output surface type can either
+be SurfaceView or TextureView.<wbr/> Another output surface type can either be MediaCodec
+or MediaRecorder.<wbr/> This mode cannot be used with a target FPS range higher than 30
+FPS.<wbr/></p>
+<p>If the session configuration is not supported,<wbr/> the AE mode reported in the
+CaptureResult will be 'ON' instead of 'ON_<wbr/>LOW_<wbr/>LIGHT_<wbr/>BOOST_<wbr/>BRIGHTNESS_<wbr/>PRIORITY'.<wbr/></p>
+<p>The application can observe the CapturerResult field
+<a href="#dynamic_android.control.lowLightBoostState">android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<wbr/>State</a> to determine when low light boost is 'ACTIVE' or
+'INACTIVE'.<wbr/></p>
+<p>The low light boost is 'ACTIVE' once the scene lighting condition is less than the
+upper bound lux value defined by <a href="#static_android.control.lowLightBoostInfoLuminanceRange">android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<wbr/>Info<wbr/>Luminance<wbr/>Range</a>.<wbr/>
+This mode will be 'INACTIVE' once the scene lighting condition is greater than the
+upper bound lux value defined by <a href="#static_android.control.lowLightBoostInfoLuminanceRange">android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<wbr/>Info<wbr/>Luminance<wbr/>Range</a>.<wbr/></p></span>
+ </li>
</ul>
</td> <!-- entry_type -->
@@ -3030,7 +3089,7 @@ all configured streams is 33ms,<wbr/> the maximum framerate won't be 60fps,<wbr/
<p>To start a CaptureSession with a target FPS range different from the
capture request template's default value,<wbr/> the application
is strongly recommended to call
-<a href="https://developer.android.com/reference/SessionConfiguration.html#setSessionParameters">SessionConfiguration#setSessionParameters</a>
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/SessionConfiguration.html#setSessionParameters">SessionConfiguration#setSessionParameters</a>
with the target fps range before creating the capture session.<wbr/> The aeTargetFpsRange is
typically a session parameter.<wbr/> Specifying it at session creation time helps avoid
session reconfiguration delays in cases like 60fps or high speed recording.<wbr/></p>
@@ -4790,7 +4849,7 @@ frame rate is less than or equal to 30fps.<wbr/> At other sizes,<wbr/> the Capt
OFF if the recording output is not stabilized,<wbr/> or if there are no output
Surface types that can be stabilized.<wbr/></p>
<p>The application is strongly recommended to call
-<a href="https://developer.android.com/reference/SessionConfiguration.html#setSessionParameters">SessionConfiguration#setSessionParameters</a>
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/SessionConfiguration.html#setSessionParameters">SessionConfiguration#setSessionParameters</a>
with the desired video stabilization mode before creating the capture session.<wbr/>
Video stabilization mode is a session parameter on many devices.<wbr/> Specifying
it at session creation time helps avoid reconfiguration delay caused by difference
@@ -7580,6 +7639,61 @@ CaptureRequest keys for each override.<wbr/></p>
<tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="static_android.control.lowLightBoostInfoLuminanceRange">
+ <td class="entry_name
+ " rowspan="1">
+ android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<wbr/>Info<wbr/>Luminance<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 rangeFloat]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The operating luminance range of low light boost measured in lux (lx).<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p>The lower bound indicates the lowest scene luminance value the AE mode
+'ON_<wbr/>LOW_<wbr/>LIGHT_<wbr/>BOOST_<wbr/>BRIGHTNESS_<wbr/>PRIORITY' can operate within.<wbr/> Scenes of lower luminance
+than this may receive less brightening,<wbr/> increased noise,<wbr/> or artifacts.<wbr/></p>
+<p>The upper bound indicates the luminance threshold at the point when the mode is enabled.<wbr/>
+For example,<wbr/> 'Range[0.<wbr/>3,<wbr/> 30.<wbr/>0]' defines 0.<wbr/>3 lux being the lowest scene luminance the
+mode can reliably support.<wbr/> 30.<wbr/>0 lux represents the threshold when this mode is
+activated.<wbr/> Scenes measured at less than or equal to 30 lux will activate low light
+boost.<wbr/></p>
+<p>If this key is defined,<wbr/> then the AE mode 'ON_<wbr/>LOW_<wbr/>LIGHT_<wbr/>BOOST_<wbr/>BRIGHTNESS_<wbr/>PRIORITY' will
+also be present.<wbr/></p>
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
@@ -8050,6 +8164,39 @@ other available AE modes.<wbr/></p>
be FLASH_<wbr/>REQUIRED after the camera device finishes AE scan and it's too dark without
flash.<wbr/></p></span>
</li>
+ <li>
+ <span class="entry_type_enum_name">ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY (v3.9)</span>
+ <span class="entry_type_enum_optional">[optional]</span>
+ <span class="entry_type_enum_notes"><p>Like 'ON' but applies additional brightness boost in low light scenes.<wbr/></p>
+<p>When the scene lighting conditions are within the range defined by
+<a href="#static_android.control.lowLightBoostInfoLuminanceRange">android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<wbr/>Info<wbr/>Luminance<wbr/>Range</a> this mode will apply additional
+brightness boost.<wbr/></p>
+<p>This mode will automatically adjust the intensity of low light boost applied
+according to the scene lighting conditions.<wbr/> A darker scene will receive more boost
+while a brighter scene will receive less boost.<wbr/></p>
+<p>This mode can ignore the set target frame rate to allow more light to be captured
+which can result in choppier motion.<wbr/> The frame rate can extend to lower than the
+<a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a> but will not go below 10 FPS.<wbr/> This mode
+can also increase the sensor sensitivity gain which can result in increased luma
+and chroma noise.<wbr/> The sensor sensitivity gain can extend to higher values beyond
+<a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a>.<wbr/> This mode may also apply additional
+processing to recover details in dark and bright areas of the image,<wbr/>and noise
+reduction at high sensitivity gain settings to manage the trade-off between light
+sensitivity and capture noise.<wbr/></p>
+<p>This mode is restricted to two output surfaces.<wbr/> One output surface type can either
+be SurfaceView or TextureView.<wbr/> Another output surface type can either be MediaCodec
+or MediaRecorder.<wbr/> This mode cannot be used with a target FPS range higher than 30
+FPS.<wbr/></p>
+<p>If the session configuration is not supported,<wbr/> the AE mode reported in the
+CaptureResult will be 'ON' instead of 'ON_<wbr/>LOW_<wbr/>LIGHT_<wbr/>BOOST_<wbr/>BRIGHTNESS_<wbr/>PRIORITY'.<wbr/></p>
+<p>The application can observe the CapturerResult field
+<a href="#dynamic_android.control.lowLightBoostState">android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<wbr/>State</a> to determine when low light boost is 'ACTIVE' or
+'INACTIVE'.<wbr/></p>
+<p>The low light boost is 'ACTIVE' once the scene lighting condition is less than the
+upper bound lux value defined by <a href="#static_android.control.lowLightBoostInfoLuminanceRange">android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<wbr/>Info<wbr/>Luminance<wbr/>Range</a>.<wbr/>
+This mode will be 'INACTIVE' once the scene lighting condition is greater than the
+upper bound lux value defined by <a href="#static_android.control.lowLightBoostInfoLuminanceRange">android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<wbr/>Info<wbr/>Luminance<wbr/>Range</a>.<wbr/></p></span>
+ </li>
</ul>
</td> <!-- entry_type -->
@@ -8314,7 +8461,7 @@ all configured streams is 33ms,<wbr/> the maximum framerate won't be 60fps,<wbr/
<p>To start a CaptureSession with a target FPS range different from the
capture request template's default value,<wbr/> the application
is strongly recommended to call
-<a href="https://developer.android.com/reference/SessionConfiguration.html#setSessionParameters">SessionConfiguration#setSessionParameters</a>
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/SessionConfiguration.html#setSessionParameters">SessionConfiguration#setSessionParameters</a>
with the target fps range before creating the capture session.<wbr/> The aeTargetFpsRange is
typically a session parameter.<wbr/> Specifying it at session creation time helps avoid
session reconfiguration delays in cases like 60fps or high speed recording.<wbr/></p>
@@ -11117,7 +11264,7 @@ frame rate is less than or equal to 30fps.<wbr/> At other sizes,<wbr/> the Capt
OFF if the recording output is not stabilized,<wbr/> or if there are no output
Surface types that can be stabilized.<wbr/></p>
<p>The application is strongly recommended to call
-<a href="https://developer.android.com/reference/SessionConfiguration.html#setSessionParameters">SessionConfiguration#setSessionParameters</a>
+<a href="https://developer.android.com/reference/android/hardware/camera2/params/SessionConfiguration.html#setSessionParameters">SessionConfiguration#setSessionParameters</a>
with the desired video stabilization mode before creating the capture session.<wbr/>
Video stabilization mode is a session parameter on many devices.<wbr/> Specifying
it at session creation time helps avoid reconfiguration delay caused by difference
@@ -11988,6 +12135,71 @@ state will be CONVERGED.<wbr/></li>
<tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="dynamic_android.control.lowLightBoostState">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>control.<wbr/>low<wbr/>Light<wbr/>Boost<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>
+
+
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">INACTIVE (v3.9)</span>
+ <span class="entry_type_enum_notes"><p>The AE mode 'ON_<wbr/>LOW_<wbr/>LIGHT_<wbr/>BOOST_<wbr/>BRIGHTNESS_<wbr/>PRIORITY' is enabled but not applied.<wbr/></p></span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">ACTIVE (v3.9)</span>
+ <span class="entry_type_enum_notes"><p>The AE mode 'ON_<wbr/>LOW_<wbr/>LIGHT_<wbr/>BOOST_<wbr/>BRIGHTNESS_<wbr/>PRIORITY' is enabled and applied.<wbr/></p></span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>Current state of the low light boost AE mode.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>When low light boost is enabled by setting the AE mode to
+'ON_<wbr/>LOW_<wbr/>LIGHT_<wbr/>BOOST_<wbr/>BRIGHTNESS_<wbr/>PRIORITY',<wbr/> it can dynamically apply a low light
+boost when the light level threshold is exceeded.<wbr/></p>
+<p>This state indicates when low light boost is 'ACTIVE' and applied.<wbr/> Similarly,<wbr/> it can
+indicate when it is not being applied by returning 'INACTIVE'.<wbr/></p>
+<p>This key will be absent from the CaptureResult if AE mode is not set to
+'ON_<wbr/>LOW_<wbr/>LIGHT_<wbr/>BOOST_<wbr/>BRIGHTNESS_<wbr/>PRIORITY.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
@@ -12758,6 +12970,81 @@ for use cases such as preview,<wbr/> auto-focus assist,<wbr/> still capture,<wbr
<tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="controls_android.flash.strengthLevel">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>strength<wbr/>Level
+ </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>Flash strength level to be used when manual flash control is active.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><code>[1-android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level]</code> when the <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> is
+set to TORCH;
+<code>[1-android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level]</code> when the <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> is
+set to SINGLE</p>
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>Flash strength level to use in capture mode i.<wbr/>e.<wbr/> when the applications control
+flash with either SINGLE or TORCH mode.<wbr/></p>
+<p>Use android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level and
+android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level to check whether the device supports
+flash strength control or not.<wbr/>
+If the values of android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level and
+android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level are greater than 1,<wbr/>
+then the device supports manual flash strength control.<wbr/></p>
+<p>If the <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> <code>==</code> TORCH the value must be &gt;= 1
+and &lt;= android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level.<wbr/>
+If the application doesn't set the key and
+android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level &gt; 1,<wbr/>
+then the flash will be fired at the default level set by HAL in
+android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Default<wbr/>Level.<wbr/>
+If the <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> <code>==</code> SINGLE,<wbr/> then the value must be &gt;= 1
+and &lt;= android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level.<wbr/>
+If the application does not set this key and
+android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level &gt; 1,<wbr/>
+then the flash will be fired at the default level set by HAL
+in android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Default<wbr/>Level.<wbr/>
+If <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is set to any of ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/>
+ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE,<wbr/> ON_<wbr/>EXTERNAL_<wbr/>FLASH values,<wbr/> then the strengthLevel will be ignored.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
@@ -13121,6 +13408,226 @@ power single flash</p>
<tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="static_android.flash.singleStrengthMaxLevel">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level
+ </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>Maximum flash brightness level for manual flash control in SINGLE mode.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>Maximum flash brightness level in camera capture mode and
+<a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> set to SINGLE.<wbr/>
+Value will be &gt; 1 if the manual flash strength control feature is supported,<wbr/>
+otherwise the value will be equal to 1.<wbr/>
+Note that this level is just a number of supported levels (the granularity of control).<wbr/>
+There is no actual physical power units tied to this level.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.flash.singleStrengthDefaultLevel">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>single<wbr/>Strength<wbr/>Default<wbr/>Level
+ </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>Default flash brightness level for manual flash control in SINGLE mode.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>If flash unit is available this will be greater than or equal to 1 and less
+or equal to <code>android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level</code>.<wbr/>
+Note for devices that do not support the manual flash strength control
+feature,<wbr/> this level will always be equal to 1.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.flash.torchStrengthMaxLevel">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level
+ </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>Maximum flash brightness level for manual flash control in TORCH mode</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>Maximum flash brightness level in camera capture mode and
+<a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> set to TORCH.<wbr/>
+Value will be &gt; 1 if the manual flash strength control feature is supported,<wbr/>
+otherwise the value will be equal to 1.<wbr/></p>
+<p>Note that this level is just a number of supported levels(the granularity of control).<wbr/>
+There is no actual physical power units tied to this level.<wbr/>
+There is no relation between android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level and
+android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level i.<wbr/>e.<wbr/> the ratio of
+android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level:android.<wbr/>flash.<wbr/>info.<wbr/>singleStrengthMaxLevel
+is not guaranteed to be the ratio of actual brightness.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="static_android.flash.torchStrengthDefaultLevel">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>torch<wbr/>Strength<wbr/>Default<wbr/>Level
+ </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>Default flash brightness level for manual flash control in TORCH mode</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>If flash unit is available this will be greater than or equal to 1 and less
+or equal to android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level.<wbr/>
+Note for the devices that do not support the manual flash strength control feature,<wbr/>
+this level will always be equal to 1.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
@@ -13429,6 +13936,81 @@ LEGACY devices (i.<wbr/>e.<wbr/> it will be <code>null</code>).<wbr/></p>
<tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="dynamic_android.flash.strengthLevel">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>flash.<wbr/>strength<wbr/>Level
+ </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>Flash strength level to be used when manual flash control is active.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ <p><code>[1-android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level]</code> when the <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> is
+set to TORCH;
+<code>[1-android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level]</code> when the <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> is
+set to SINGLE</p>
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>Flash strength level to use in capture mode i.<wbr/>e.<wbr/> when the applications control
+flash with either SINGLE or TORCH mode.<wbr/></p>
+<p>Use android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level and
+android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level to check whether the device supports
+flash strength control or not.<wbr/>
+If the values of android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level and
+android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level are greater than 1,<wbr/>
+then the device supports manual flash strength control.<wbr/></p>
+<p>If the <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> <code>==</code> TORCH the value must be &gt;= 1
+and &lt;= android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level.<wbr/>
+If the application doesn't set the key and
+android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Max<wbr/>Level &gt; 1,<wbr/>
+then the flash will be fired at the default level set by HAL in
+android.<wbr/>flash.<wbr/>info.<wbr/>torch<wbr/>Strength<wbr/>Default<wbr/>Level.<wbr/>
+If the <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> <code>==</code> SINGLE,<wbr/> then the value must be &gt;= 1
+and &lt;= android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level.<wbr/>
+If the application does not set this key and
+android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Max<wbr/>Level &gt; 1,<wbr/>
+then the flash will be fired at the default level set by HAL
+in android.<wbr/>flash.<wbr/>info.<wbr/>single<wbr/>Strength<wbr/>Default<wbr/>Level.<wbr/>
+If <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is set to any of ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/>
+ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE,<wbr/> ON_<wbr/>EXTERNAL_<wbr/>FLASH values,<wbr/> then the strengthLevel will be ignored.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
@@ -19999,10 +20581,10 @@ callback.<wbr/></li>
</ul>
<p>Combinations of logical and physical streams,<wbr/> or physical streams from different
physical cameras are not guaranteed.<wbr/> However,<wbr/> if the camera device supports
-<a href="https://developer.android.com/reference/CameraDevice.html#isSessionConfigurationSupported">CameraDevice#isSessionConfigurationSupported</a>,<wbr/>
+<a href="https://developer.android.com/reference/CameraManager.html#isSessionConfigurationWithParametersSupported">CameraManager#isSessionConfigurationWithParametersSupported</a>,<wbr/>
application must be able to query whether a stream combination involving physical
streams is supported by calling
-<a href="https://developer.android.com/reference/CameraDevice.html#isSessionConfigurationSupported">CameraDevice#isSessionConfigurationSupported</a>.<wbr/></p>
+<a href="https://developer.android.com/reference/CameraManager.html#isSessionConfigurationWithParametersSupported">CameraManager#isSessionConfigurationWithParametersSupported</a>.<wbr/></p>
<p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
camera in the system.<wbr/> For an application that switches between front and back cameras,<wbr/>
the recommendation is to switch between the first rear camera and the first front
@@ -20265,8 +20847,7 @@ Cameras that enable this capability must also support the following:</p>
<ul>
<li>Profile <a href="https://developer.android.com/reference/android/hardware/camera2/params/DynamicRangeProfiles.html#HLG10">DynamicRangeProfiles#HLG10</a></li>
<li>All mandatory stream combinations for this specific capability as per
- documentation
- <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#10-bit-output-additional-guaranteed-configurations">CameraDevice#10-bit-output-additional-guaranteed-configurations</a></li>
+ <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#10-bit-output-additional-guaranteed-configurations">documentation</a></li>
<li>In case the device is not able to capture some combination of supported
standard 8-bit and/<wbr/>or 10-bit dynamic range profiles within the same capture request,<wbr/>
then those constraints must be listed in
@@ -20304,8 +20885,8 @@ stream use cases:</p>
</ul>
<p><a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SCALER_AVAILABLE_STREAM_USE_CASES">Camera<wbr/>Characteristics#SCALER_<wbr/>AVAILABLE_<wbr/>STREAM_<wbr/>USE_<wbr/>CASES</a>
lists all of the supported stream use cases.<wbr/></p>
-<p>Refer to
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#stream-use-case-capability-additional-guaranteed-configurations">CameraDevice#stream-use-case-capability-additional-guaranteed-configurations</a>
+<p>Refer to the
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations">guideline</a>
for the mandatory stream combinations involving stream use cases,<wbr/> which can also be
queried via <a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">MandatoryStreamCombination</a>.<wbr/></p></span>
</li>
@@ -23763,7 +24344,7 @@ or if the camera device isn't a primary rear/<wbr/>front camera,<wbr/> the minim
stream configurations are the same as for applications targeting SDK version older than
31.<wbr/></p>
<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#legacy-level-guaranteed-configurations">CameraDevice#legacy-level-guaranteed-configurations</a>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations">the table</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>
@@ -24201,7 +24782,7 @@ configuration see
<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#INFO_SUPPORTED_HARDWARE_LEVEL">Camera<wbr/>Characteristics#INFO_<wbr/>SUPPORTED_<wbr/>HARDWARE_<wbr/>LEVEL</a>
and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES">Camera<wbr/>Characteristics#REQUEST_<wbr/>AVAILABLE_<wbr/>CAPABILITIES</a>.<wbr/>
This is an app-readable conversion of the mandatory stream combination
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#legacy-level-guaranteed-configurations">tables</a>.<wbr/></p>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations">tables</a>.<wbr/></p>
</td>
<td class="entry_units">
@@ -24226,7 +24807,8 @@ This is an app-readable conversion of the mandatory stream combination
<p>The array of
<a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">combinations</a> is
generated according to the documented
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#legacy-level-guaranteed-configurations">guideline</a> based on specific device level and capabilities.<wbr/>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations">guideline</a>.<wbr/>
+based on specific device level and capabilities.<wbr/>
Clients can use the array as a quick reference to find an appropriate camera stream
combination.<wbr/>
As per documentation,<wbr/> the stream combinations with given PREVIEW,<wbr/> RECORD and
@@ -24281,7 +24863,7 @@ backward compatible.<wbr/></p>
<td class="entry_description">
<p>An array of mandatory concurrent stream combinations.<wbr/>
This is an app-readable conversion of the concurrent mandatory stream combination
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#concurrent-stream-guaranteed-configurations">tables</a>.<wbr/></p>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#concurrent-stream-guaranteed-configurations">tables</a>.<wbr/></p>
</td>
<td class="entry_units">
@@ -24306,7 +24888,8 @@ This is an app-readable conversion of the concurrent mandatory stream combinatio
<p>The array of
<a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">combinations</a> is
generated according to the documented
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#concurrent-stream-guaranteed-configurations">guideline</a> for each device which has its Id present in the set returned by
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#concurrent-stream-guaranteed-configurations">guideline</a>
+for each device which has its Id present in the set returned by
<a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#getConcurrentCameraIds">CameraManager#getConcurrentCameraIds</a>.<wbr/>
Clients can use the array as a quick reference to find an appropriate camera stream
combination.<wbr/>
@@ -24440,7 +25023,7 @@ if the camera device does not list SECURE_<wbr/>IMAGE_<wbr/>DATA capability.<wbr
<p>When the key is present,<wbr/> only a PRIVATE/<wbr/>YUV output of the specified size is guaranteed
to be supported by the camera HAL in the secure camera mode.<wbr/> Any other format or
resolutions might not be supported.<wbr/> Use
-<a href="https://developer.android.com/reference/CameraDevice.html#isSessionConfigurationSupported">CameraDevice#isSessionConfigurationSupported</a>
+<a href="https://developer.android.com/reference/CameraManager.html#isSessionConfigurationWithParametersSupported">CameraManager#isSessionConfigurationWithParametersSupported</a>
API to query if a secure session configuration is supported if the device supports this
API.<wbr/></p>
<p>If this key returns null on a device with SECURE_<wbr/>IMAGE_<wbr/>DATA capability,<wbr/> the application
@@ -24605,7 +25188,7 @@ supported format with the MultiResolutionStreamInfo group queried by <a href="ht
<p>If a camera device supports multi-resolution output streams for a particular format,<wbr/> for
each of its mandatory stream combinations,<wbr/> the camera device will support using a
MultiResolutionImageReader for the MAXIMUM stream of supported formats.<wbr/> Refer to
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs">CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs</a>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs">the table</a>
for additional details.<wbr/></p>
<p>To use multi-resolution input streams,<wbr/> the supported formats can be queried by <a href="https://developer.android.com/reference/android/hardware/camera2/params/MultiResolutionStreamConfigurationMap.html#getInputFormats">MultiResolutionStreamConfigurationMap#getInputFormats</a>.<wbr/>
A reprocessable CameraCaptureSession can then be created using an <a href="https://developer.android.com/reference/android/hardware/camera2/params/InputConfiguration.html">InputConfiguration</a> constructed with
@@ -24614,7 +25197,7 @@ the input MultiResolutionStreamInfo group,<wbr/> queried by <a href="https://dev
{@code YUV} output,<wbr/> or multi-resolution {@code PRIVATE} input and multi-resolution
{@code PRIVATE} output,<wbr/> {@code JPEG} and {@code YUV} are guaranteed to be supported
multi-resolution output stream formats.<wbr/> Refer to
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs">CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs</a>}
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs">the table</a>
for details about the additional mandatory stream combinations in this case.<wbr/></p>
</td>
</tr>
@@ -25007,7 +25590,7 @@ camera device for input streams,<wbr/> to their corresponding output formats,<wb
<a href="https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html">CaptureRequest</a> has <a href="#controls_android.sensor.pixelMode">android.<wbr/>sensor.<wbr/>pixel<wbr/>Mode</a> set
to <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">Camera<wbr/>Metadata#SENSOR_<wbr/>PIXEL_<wbr/>MODE_<wbr/>MAXIMUM_<wbr/>RESOLUTION</a>.<wbr/>
This is an app-readable conversion of the maximum resolution mandatory stream combination
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#additional-guaranteed-combinations-for-ultra-high-resolution-sensors">tables</a>.<wbr/></p>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors">tables</a>.<wbr/></p>
</td>
<td class="entry_units">
@@ -25032,7 +25615,8 @@ This is an app-readable conversion of the maximum resolution mandatory stream co
<p>The array of
<a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">combinations</a> is
generated according to the documented
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#additional-guaranteed-combinations-for-ultra-high-resolution-sensors">guideline</a> for each device which has the
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors">guideline</a>
+for each device which has the
<a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR">Camera<wbr/>Metadata#REQUEST_<wbr/>AVAILABLE_<wbr/>CAPABILITIES_<wbr/>ULTRA_<wbr/>HIGH_<wbr/>RESOLUTION_<wbr/>SENSOR</a>
capability.<wbr/>
Clients can use the array as a quick reference to find an appropriate camera stream
@@ -25084,7 +25668,7 @@ device.<wbr/></p>
10-bit output capability
<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT">Camera<wbr/>Characteristics#REQUEST_<wbr/>AVAILABLE_<wbr/>CAPABILITIES_<wbr/>DYNAMIC_<wbr/>RANGE_<wbr/>TEN_<wbr/>BIT</a>
This is an app-readable conversion of the 10 bit output mandatory stream combination
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#10-bit-output-additional-guaranteed-configurations">tables</a>.<wbr/></p>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#10-bit-output-additional-guaranteed-configurations">tables</a>.<wbr/></p>
</td>
<td class="entry_units">
@@ -25109,7 +25693,8 @@ This is an app-readable conversion of the 10 bit output mandatory stream combina
<p>The array of
<a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">combinations</a> is
generated according to the documented
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#10-bit-output-additional-guaranteed-configurations">guideline</a> for each device which has the
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#10-bit-output-additional-guaranteed-configurations">guideline</a>
+for each device which has the
<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT">Camera<wbr/>Characteristics#REQUEST_<wbr/>AVAILABLE_<wbr/>CAPABILITIES_<wbr/>DYNAMIC_<wbr/>RANGE_<wbr/>TEN_<wbr/>BIT</a>
capability.<wbr/>
Clients can use the array as a quick reference to find an appropriate camera stream
@@ -25161,7 +25746,7 @@ device.<wbr/></p>
{@code PREVIEW_<wbr/>STABILIZATION} in <a href="#static_android.control.availableVideoStabilizationModes">android.<wbr/>control.<wbr/>available<wbr/>Video<wbr/>Stabilization<wbr/>Modes</a>.<wbr/>
This is an app-readable conversion of the preview stabilization mandatory stream
combination
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#preview-stabilization-guaranteed-stream-configurations">tables</a>.<wbr/></p>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#preview-stabilization-guaranteed-stream-configurations">tables</a>.<wbr/></p>
</td>
<td class="entry_units">
@@ -25186,7 +25771,8 @@ combination
<p>The array of
<a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">combinations</a> is
generated according to the documented
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#preview-stabilization-guaranteed-stream-configurations">guideline</a> for each device which supports {@code PREVIEW_<wbr/>STABILIZATION}
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#preview-stabilization-guaranteed-stream-configurations">guideline</a>
+for each device which supports {@code PREVIEW_<wbr/>STABILIZATION}
Clients can use the array as a quick reference to find an appropriate camera stream
combination.<wbr/>
The mandatory stream combination array will be {@code null} in case the device does not
@@ -25480,8 +26066,8 @@ capability must support the following stream use cases:</p>
<p>The guaranteed stream combinations related to stream use case for a camera device with
<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE">Camera<wbr/>Characteristics#REQUEST_<wbr/>AVAILABLE_<wbr/>CAPABILITIES_<wbr/>STREAM_<wbr/>USE_<wbr/>CASE</a>
capability is documented in the camera device
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#stream-use-case-capability-additional-guaranteed-configurations">guideline</a>.<wbr/> The application is strongly recommended to use one of the guaranteed stream
-combinations.<wbr/>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations">guideline</a>.<wbr/>
+The application is strongly recommended to use one of the guaranteed stream combinations.<wbr/>
If the application creates a session with a stream combination not in the guaranteed
list,<wbr/> or with mixed DEFAULT and non-DEFAULT use cases within the same session,<wbr/>
the camera device may ignore some stream use cases due to hardware constraints
@@ -25532,7 +26118,8 @@ framework sets it to DEFAULT.<wbr/></p>
<td class="entry_description">
<p>An array of mandatory stream combinations with stream use cases.<wbr/>
This is an app-readable conversion of the mandatory stream combination
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#stream-use-case-capability-additional-guaranteed-configurations">tables</a> with each stream's use case being set.<wbr/></p>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations">tables</a>
+with each stream's use case being set.<wbr/></p>
</td>
<td class="entry_units">
@@ -25557,7 +26144,8 @@ This is an app-readable conversion of the mandatory stream combination
<p>The array of
<a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">combinations</a> is
generated according to the documented
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#stream-use-case-capability-additional-guaranteed-configurations">guideline</a> for a camera device with
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations">guildeline</a>
+for a camera device with
<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE">Camera<wbr/>Characteristics#REQUEST_<wbr/>AVAILABLE_<wbr/>CAPABILITIES_<wbr/>STREAM_<wbr/>USE_<wbr/>CASE</a>
capability.<wbr/>
The mandatory stream combination array will be {@code null} in case the device doesn't
@@ -26155,8 +26743,8 @@ OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
</td> <!-- entry_type -->
<td class="entry_description">
- <p>Duration from start of frame exposure to
-start of next frame exposure.<wbr/></p>
+ <p>Duration from start of frame readout to
+start of next frame readout.<wbr/></p>
</td>
<td class="entry_units">
@@ -26244,6 +26832,10 @@ buffers from the previous <code>Rstall</code> have already been delivered.<wbr/>
<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>
+<p><em>Note:</em> Prior to Android 13,<wbr/> this field was described as measuring the duration from
+start of frame exposure to start of next frame exposure,<wbr/> which doesn't reflect the
+definition from sensor manufacturer.<wbr/> A mobile sensor defines the frame duration as
+intervals between sensor readouts.<wbr/></p>
</td>
</tr>
@@ -29381,8 +29973,8 @@ OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
</td> <!-- entry_type -->
<td class="entry_description">
- <p>Duration from start of frame exposure to
-start of next frame exposure.<wbr/></p>
+ <p>Duration from start of frame readout to
+start of next frame readout.<wbr/></p>
</td>
<td class="entry_units">
@@ -29470,6 +30062,10 @@ buffers from the previous <code>Rstall</code> have already been delivered.<wbr/>
<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>
+<p><em>Note:</em> Prior to Android 13,<wbr/> this field was described as measuring the duration from
+start of frame exposure to start of next frame exposure,<wbr/> which doesn't reflect the
+definition from sensor manufacturer.<wbr/> A mobile sensor defines the frame duration as
+intervals between sensor readouts.<wbr/></p>
</td>
</tr>
@@ -33753,6 +34349,181 @@ is needed.<wbr/></p>
<tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="dynamic_android.statistics.lensIntrinsicsSamples">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>lens<wbr/>Intrinsics<wbr/>Samples
+ </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"> [java_public as lensIntrinsicsSample]</span>
+
+ <span class="entry_type_synthetic">[synthetic] </span>
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>An array of intra-frame lens intrinsic samples.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>Contains an array of intra-frame <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> updates.<wbr/> This must
+not be confused or compared to <a href="#dynamic_android.statistics.oisSamples">android.<wbr/>statistics.<wbr/>ois<wbr/>Samples</a>.<wbr/> Although OIS could be the
+main driver,<wbr/> all relevant factors such as focus distance and optical zoom must also
+be included.<wbr/> Do note that OIS samples must not be applied on top of the lens intrinsic
+samples.<wbr/>
+Support for this capture result can be queried via
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureResultKeys">CameraCharacteristics#getAvailableCaptureResultKeys</a>.<wbr/>
+If available,<wbr/> clients can expect multiple samples per capture result.<wbr/> The specific
+amount will depend on current frame duration and sampling rate.<wbr/> Generally a sampling rate
+greater than or equal to 200Hz is considered sufficient for high quality results.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.lensIntrinsicTimestamps">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>lens<wbr/>Intrinsic<wbr/>Timestamps
+ </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"> [ndk_public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>An array of timestamps of lens intrinsics samples,<wbr/> in nanoseconds.<wbr/></p>
+ </td>
+
+ <td class="entry_units">
+ nanoseconds
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>The array contains the timestamps of lens intrinsics samples.<wbr/> The timestamps are in the
+same timebase as and comparable to <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a>.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
+
+ <tr class="entry" id="dynamic_android.statistics.lensIntrinsicSamples">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>statistics.<wbr/>lens<wbr/>Intrinsic<wbr/>Samples
+ </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 x n
+ </span>
+ <span class="entry_type_visibility"> [ndk_public]</span>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>An array of intra-frame lens intrinsics.<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_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>The data layout and contents of individual array entries matches with
+<a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a>.<wbr/></p>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
@@ -35418,9 +36189,9 @@ doesn't violate the above rules.<wbr/></p>
<span class="entry_type_enum_name">LIMITED (v3.2)</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#limited-level-additional-guaranteed-configurations">CameraDevice#limited-level-additional-guaranteed-configurations</a>
-documentation are guaranteed to be supported.<wbr/></p>
+<p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#limited-level-additional-guaranteed-configurations">tables</a>
+in the 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
@@ -35438,9 +36209,9 @@ can be checked for in <a href="#static_android.request.availableCapabilities">an
<li>
<span class="entry_type_enum_name">FULL (v3.2)</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#full-level-additional-guaranteed-configurations">CameraDevice#full-level-additional-guaranteed-configurations</a>
-documentation are guaranteed to be supported.<wbr/></p>
+<p>The stream configurations listed in the <code>FULL</code>,<wbr/> <code>LEGACY</code> and <code>LIMITED</code>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#full-level-additional-guaranteed-configurations">tables</a>
+in the 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
@@ -35460,9 +36231,9 @@ Pre-API level 23,<wbr/> FULL devices also supported arbitrary cropping region
<li>
<span class="entry_type_enum_name">LEGACY (v3.2)</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#legacy-level-guaranteed-configurations">CameraDevice#legacy-level-guaranteed-configurations</a>
-documentation are supported.<wbr/></p>
+<p>Only the stream configurations listed in the <code>LEGACY</code>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations">table</a>
+in the 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
@@ -35480,9 +36251,9 @@ enable the flash.<wbr/></p>
<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#level-3-additional-guaranteed-configurations">CameraDevice#level-3-additional-guaranteed-configurations</a>
-documentation are guaranteed to be supported.<wbr/></p>
+<code>LIMITED</code>
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#level-3-additional-guaranteed-configurations">tables</a>
+in the 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
@@ -35708,6 +36479,13 @@ It must not exceed 256 characters.<wbr/></p>
<span class="entry_type_enum_notes"><p>This camera device supports and opts in to the buffer management APIs provided by
HIDL ICameraDevice version 3.<wbr/>5.<wbr/></p></span>
</li>
+ <li>
+ <span class="entry_type_enum_name">SESSION_CONFIGURABLE (v3.9)</span>
+ <span class="entry_type_enum_notes"><p>This camera device supports the buffer management APIs provided by AIDL ICameraDevice
+version 1.<wbr/> It also supports the ICameraDeviceSession.<wbr/>configureStreamsV2 call to
+inform the camera framework whether HAL buffer manager must be used for the
+particular session configured.<wbr/></p></span>
+ </li>
</ul>
</td> <!-- entry_type -->
@@ -35860,6 +36638,339 @@ supported device state bitwise combination.<wbr/></p>
<tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="static_android.info.sessionConfigurationQueryVersion">
+ <td class="entry_name
+ " rowspan="3">
+ android.<wbr/>info.<wbr/>session<wbr/>Configuration<wbr/>Query<wbr/>Version
+ </td>
+ <td class="entry_type">
+ <span class="entry_type_name entry_type_name_enum">int32</span>
+
+ <span class="entry_type_visibility"> [fwk_java_public as versionCode]</span>
+
+
+ <span class="entry_type_hwlevel">[legacy] </span>
+
+
+
+ <ul class="entry_type_enum">
+ <li>
+ <span class="entry_type_enum_name">UPSIDE_DOWN_CAKE (v3.2)</span>
+ <span class="entry_type_enum_value">34</span>
+ </li>
+ <li>
+ <span class="entry_type_enum_name">VANILLA_ICE_CREAM (v3.2)</span>
+ <span class="entry_type_enum_value">35</span>
+ </li>
+ </ul>
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The version of the session configuration query
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#isSessionConfigurationWithParametersSupported">CameraManager#isSessionConfigurationWithParametersSupported</a>
+API</p>
+ </td>
+
+ <td class="entry_units">
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>2</p>
+ </td>
+
+ <td class="entry_tags">
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>The possible values in this key correspond to the values defined in
+android.<wbr/>os.<wbr/>Build.<wbr/>VERSION_<wbr/>CODES.<wbr/> Each version defines a set of feature combinations the
+camera device must reliably report whether they are supported via
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#isSessionConfigurationWithParametersSupported">CameraManager#isSessionConfigurationWithParametersSupported</a>
+API.<wbr/> And the version is always less or equal to android.<wbr/>os.<wbr/>Build.<wbr/>VERSION.<wbr/>SDK_<wbr/>INT.<wbr/></p>
+<p>If set to UPSIDE_<wbr/>DOWN_<wbr/>CAKE,<wbr/> this camera device doesn't support
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#isSessionConfigurationWithParametersSupported">CameraManager#isSessionConfigurationWithParametersSupported</a>.<wbr/>
+Calling the method for this camera ID throws an UnsupportedOperationException.<wbr/></p>
+<p>If set to VANILLA_<wbr/>ICE_<wbr/>CREAM,<wbr/> the application can call
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraManager.html#isSessionConfigurationWithParametersSupported">CameraManager#isSessionConfigurationWithParametersSupported</a>
+to check if the combinations of below features are supported.<wbr/></p>
+<ul>
+<li>A subset of LIMITED-level device stream combinations.<wbr/></li>
+</ul>
+<table>
+<thead>
+<tr>
+<th style="text-align: center;">Target 1</th>
+<th style="text-align: center;">Size</th>
+<th style="text-align: center;">Target 2</th>
+<th style="text-align: center;">Size</th>
+<th style="text-align: center;">Sample use case(s)</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;">Simple preview,<wbr/> GPU video processing,<wbr/> or no-preview video recording.<wbr/></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">PREVIEW</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;">In-application video/<wbr/>image processing.<wbr/></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">PREVIEW</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">PREVIEW</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;">Standard still imaging.<wbr/></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">PREVIEW</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;">In-app processing plus still capture.<wbr/></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">MAXIMUM</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;">JPEG</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">PREVIEW</td>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">PREVIEW</td>
+<td style="text-align: center;">Standard recording.<wbr/></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">PREVIEW</td>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">PREVIEW</td>
+<td style="text-align: center;">Preview plus in-app processing.<wbr/></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S1440P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S1080P</td>
+<td style="text-align: center;"></td>
+</tr>
+<tr>
+<td style="text-align: center;">PRIV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;">YUV</td>
+<td style="text-align: center;">S720P</td>
+<td style="text-align: center;"></td>
+</tr>
+</tbody>
+</table>
+<pre><code>- {@code MAXIMUM} size refers to the camera device's maximum output resolution for
+ that format from {@code StreamConfigurationMap#getOutputSizes}.<wbr/> {@code PREVIEW} size
+ refers to the best size match to the device's screen resolution,<wbr/> or to 1080p
+ (@code 1920x1080},<wbr/> whichever is smaller.<wbr/> Both sizes are guaranteed to be supported.<wbr/>
+
+- {@code S1440P} refers to {@code 1920x1440 (4:3)} and {@code 2560x1440 (16:9)}.<wbr/>
+ {@code S1080P} refers to {@code 1440x1080 (4:3)} and {@code 1920x1080 (16:9)}.<wbr/>
+ And {@code S720P} refers to {@code 960x720 (4:3)} and {@code 1280x720 (16:9)}.<wbr/>
+
+- If a combination contains a S1440P,<wbr/> S1080P,<wbr/> or S720P stream,<wbr/>
+ both 4:3 and 16:9 aspect ratio sizes can be queried.<wbr/> For example,<wbr/> for the
+ stream combination of {PRIV,<wbr/> S1440P,<wbr/> JPEG,<wbr/> MAXIMUM},<wbr/> and if MAXIMUM ==
+ 4032 x 3024,<wbr/> the application will be able to query both
+ {PRIV,<wbr/> 1920 x 1440,<wbr/> JPEG,<wbr/> 4032 x 3024} and {PRIV,<wbr/> 2560 x 1440,<wbr/> JPEG,<wbr/> 4032 x 2268}
+ without an exception being thrown.<wbr/>
+</code></pre>
+<ul>
+<li>VIDEO_<wbr/>STABILIZATION_<wbr/>MODES: {OFF,<wbr/> PREVIEW}</li>
+<li>AE_<wbr/>TARGET_<wbr/>FPS_<wbr/>RANGE: {{<em>,<wbr/> 30},<wbr/> {</em>,<wbr/> 60}}</li>
+<li>DYNAMIC_<wbr/>RANGE_<wbr/>PROFILE: {STANDARD,<wbr/> HLG10}</li>
+</ul>
+ </td>
+ </tr>
+
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
@@ -37888,7 +38999,7 @@ at the HAL layer.<wbr/></p>
<tr class="entry" id="static_android.logicalMultiCamera.physicalIds">
<td class="entry_name
- " rowspan="3">
+ " rowspan="5">
android.<wbr/>logical<wbr/>Multi<wbr/>Camera.<wbr/>physical<wbr/>Ids
</td>
<td class="entry_type">
@@ -37944,6 +39055,28 @@ value of this tag will be ['2',<wbr/> '\0',<wbr/> '3',<wbr/> '\0'].<wbr/></p>
</td>
</tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>Each physical camera id should uniquely identify a camera lens in the system.<wbr/>
+So if each camera lens only backs one logical camera,<wbr/> all camera IDs in the system,<wbr/>
+physical IDs or non-physical IDs,<wbr/> should be unique.<wbr/></p>
+<p>In rare cases,<wbr/> one camera lens backs two different logical cameras,<wbr/> the
+physicalIds of both logical cameras should contain a physical camera ID
+identifying that same camera lens.<wbr/> For example,<wbr/> if the mobile device has 3 rear facing
+cameras and no front facing cameras,<wbr/> and the 3 rear facing lenses may be modelled as
+2 logical cameras:</p>
+<ul>
+<li>"device@1.<wbr/>0/<wbr/>internal/<wbr/>10": physicalIds: "camera0",<wbr/> "camera42"</li>
+<li>"device@1.<wbr/>0/<wbr/>internal/<wbr/>11": physicalIds: "camera1",<wbr/> "camera42"</li>
+</ul>
+<p>In this case,<wbr/> the two logical cameras are conflicting devices because they are backed
+by a common lens.<wbr/></p>
+<p>Physical camera IDs can be an arbitrary string not containing '\0'.<wbr/></p>
+ </td>
+ </tr>
<tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
<!-- end of entry -->
@@ -38127,6 +39260,106 @@ result metadata to indicate current active physical camera ID.<wbr/></p>
<tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
<!-- end of entry -->
+
+ <tr class="entry" id="dynamic_android.logicalMultiCamera.activePhysicalSensorCropRegion">
+ <td class="entry_name
+ " rowspan="5">
+ android.<wbr/>logical<wbr/>Multi<wbr/>Camera.<wbr/>active<wbr/>Physical<wbr/>Sensor<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>
+
+
+
+
+
+
+ </td> <!-- entry_type -->
+
+ <td class="entry_description">
+ <p>The current region of the active physical sensor that will be 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 or
+ android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size of the currently
+ android.<wbr/>logical<wbr/>Multi<wbr/>Camera.<wbr/>active<wbr/>Physical<wbr/>Id depending on distortion correction capability
+ and mode
+ </td>
+
+ <td class="entry_range">
+ </td>
+
+ <td class="entry_hal_version">
+ <p>3.<wbr/>9</p>
+ </td>
+
+ <td class="entry_tags">
+ <ul class="entry_tags">
+ <li><a href="#tag_LOGICALCAMERA">LOGICALCAMERA</a></li>
+ </ul>
+ </td>
+
+ </tr>
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <p>This capture result matches with <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> on non-logical single
+camera sensor devices.<wbr/> In case of logical cameras that can switch between several
+physical devices in response to <a href="#controls_android.control.zoomRatio">android.<wbr/>control.<wbr/>zoom<wbr/>Ratio</a>,<wbr/> this capture result will
+not behave like <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> and <a href="#controls_android.control.zoomRatio">android.<wbr/>control.<wbr/>zoom<wbr/>Ratio</a>,<wbr/> where the
+combination of both reflects the effective zoom and crop of the logical camera output.<wbr/>
+Instead,<wbr/> this capture result value will describe the zoom and crop of the active physical
+device.<wbr/> Some examples of when the value of this capture result will change include
+switches between different physical lenses,<wbr/> switches between regular and maximum
+resolution pixel mode and going through the device digital or optical range.<wbr/>
+This capture result is similar to <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> with respect to distortion
+correction.<wbr/> When the distortion correction mode is OFF,<wbr/> the coordinate system follows
+<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>,<wbr/> with (0,<wbr/> 0) being the top-left pixel
+of the pre-correction active array.<wbr/> When the distortion correction mode is not OFF,<wbr/>
+the coordinate system follows <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with (0,<wbr/> 0) being
+the top-left pixel of the active array.<wbr/></p>
+<p>For camera devices with the
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR">Camera<wbr/>Metadata#REQUEST_<wbr/>AVAILABLE_<wbr/>CAPABILITIES_<wbr/>ULTRA_<wbr/>HIGH_<wbr/>RESOLUTION_<wbr/>SENSOR</a>
+capability or devices where <a href="https://developer.android.com/reference/CameraCharacteristics.html#getAvailableCaptureRequestKeys">CameraCharacteristics#getAvailableCaptureRequestKeys</a>
+lists <a href="https://developer.android.com/reference/CaptureRequest.html#SENSOR_PIXEL_MODE"><a href="#controls_android.sensor.pixelMode">android.<wbr/>sensor.<wbr/>pixel<wbr/>Mode</a></a>
+,<wbr/> the current active physical device
+<a href="#static_android.sensor.info.activeArraySizeMaximumResolution">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size<wbr/>Maximum<wbr/>Resolution</a> /<wbr/>
+<a href="#static_android.sensor.info.preCorrectionActiveArraySizeMaximumResolution">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size<wbr/>Maximum<wbr/>Resolution</a> must be used as the
+coordinate system for requests where <a href="#controls_android.sensor.pixelMode">android.<wbr/>sensor.<wbr/>pixel<wbr/>Mode</a> is set to
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">Camera<wbr/>Metadata#SENSOR_<wbr/>PIXEL_<wbr/>MODE_<wbr/>MAXIMUM_<wbr/>RESOLUTION</a>.<wbr/></p>
+ </td>
+ </tr>
+
+ <tr class="entries_header">
+ <th class="th_details" colspan="6">HAL Implementation Details</th>
+ </tr>
+ <tr class="entry_cont">
+ <td class="entry_details" colspan="6">
+ <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>
+ </td>
+ </tr>
+
+ <tr class="entry_spacer"><td class="entry_spacer" colspan="7"></td></tr>
+ <!-- end of entry -->
+
<!-- end of kind -->
@@ -38551,7 +39784,8 @@ own requirements.<wbr/></p>
<td class="entry_description">
<p>Whether this camera device can support identical set of stream combinations
involving HEIC image format,<wbr/> compared to the
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#legacy-level-guaranteed-configurations">table of combinations</a> involving JPEG image format required for the device's hardware
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations">table of combinations</a>
+involving JPEG image format required for the device's hardware
level and capabilities.<wbr/></p>
</td>
@@ -38583,7 +39817,8 @@ used to control the orientation and quality of the HEIC image.<wbr/> Configuring
HEIC streams at the same time is not supported.<wbr/></p>
<p>If a camera device supports HEIC format (ISO/<wbr/>IEC 23008-12),<wbr/> not only does it
support the existing mandatory stream
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#legacy-level-guaranteed-configurations">combinations</a> required for the device's hardware level and capabilities,<wbr/> it also
+<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations">combinations</a>
+required for the device's hardware level and capabilities,<wbr/> it also
supports swapping each JPEG stream with HEIC stream in all guaranteed combinations.<wbr/></p>
<p>For every HEIC stream configured by the application,<wbr/> the camera framework sets up 2
internal streams with camera HAL:</p>
@@ -40365,6 +41600,7 @@ output format/<wbr/>size combination for Jpeg/<wbr/>R streams for CaptureRequest
<li><a href="#static_android.logicalMultiCamera.physicalIds">android.logicalMultiCamera.physicalIds</a> (static)</li>
<li><a href="#static_android.logicalMultiCamera.sensorSyncType">android.logicalMultiCamera.sensorSyncType</a> (static)</li>
<li><a href="#dynamic_android.logicalMultiCamera.activePhysicalId">android.logicalMultiCamera.activePhysicalId</a> (dynamic)</li>
+ <li><a href="#dynamic_android.logicalMultiCamera.activePhysicalSensorCropRegion">android.logicalMultiCamera.activePhysicalSensorCropRegion</a> (dynamic)</li>
</ul>
</li> <!-- tag_LOGICALCAMERA -->
<li id="tag_HEIC">HEIC -
diff --git a/camera/docs/metadata_definitions.xml b/camera/docs/metadata_definitions.xml
index 4fcd4c23..34b32538 100644
--- a/camera/docs/metadata_definitions.xml
+++ b/camera/docs/metadata_definitions.xml
@@ -73,6 +73,9 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
<typedef name="imageFormat">
<language name="java">int</language>
</typedef>
+ <typedef name="versionCode">
+ <language name="java">int</language>
+ </typedef>
<typedef name="streamConfigurationMap">
<language name="java">android.hardware.camera2.params.StreamConfigurationMap</language>
</typedef>
@@ -155,6 +158,9 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
<typedef name="colorSpaceProfiles">
<language name="java">android.hardware.camera2.params.ColorSpaceProfiles</language>
</typedef>
+ <typedef name="lensIntrinsicsSample">
+ <language name="java">android.hardware.camera2.params.LensIntrinsicsSample</language>
+ </typedef>
</types>
<namespace name="android">
@@ -674,6 +680,47 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
flash.
</notes>
</value>
+ <value optional="true" hal_version="3.9"
+ aconfig_flag="camera_ae_mode_low_light_boost">ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY
+ <notes>
+ Like 'ON' but applies additional brightness boost in low light scenes.
+
+ When the scene lighting conditions are within the range defined by
+ android.control.lowLightBoostInfoLuminanceRange this mode will apply additional
+ brightness boost.
+
+ This mode will automatically adjust the intensity of low light boost applied
+ according to the scene lighting conditions. A darker scene will receive more boost
+ while a brighter scene will receive less boost.
+
+ This mode can ignore the set target frame rate to allow more light to be captured
+ which can result in choppier motion. The frame rate can extend to lower than the
+ android.control.aeAvailableTargetFpsRanges but will not go below 10 FPS. This mode
+ can also increase the sensor sensitivity gain which can result in increased luma
+ and chroma noise. The sensor sensitivity gain can extend to higher values beyond
+ android.sensor.info.sensitivityRange. This mode may also apply additional
+ processing to recover details in dark and bright areas of the image,and noise
+ reduction at high sensitivity gain settings to manage the trade-off between light
+ sensitivity and capture noise.
+
+ This mode is restricted to two output surfaces. One output surface type can either
+ be SurfaceView or TextureView. Another output surface type can either be MediaCodec
+ or MediaRecorder. This mode cannot be used with a target FPS range higher than 30
+ FPS.
+
+ If the session configuration is not supported, the AE mode reported in the
+ CaptureResult will be 'ON' instead of 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'.
+
+ The application can observe the CapturerResult field
+ android.control.lowLightBoostState to determine when low light boost is 'ACTIVE' or
+ 'INACTIVE'.
+
+ The low light boost is 'ACTIVE' once the scene lighting condition is less than the
+ upper bound lux value defined by android.control.lowLightBoostInfoLuminanceRange.
+ This mode will be 'INACTIVE' once the scene lighting condition is greater than the
+ upper bound lux value defined by android.control.lowLightBoostInfoLuminanceRange.
+ </notes>
+ </value>
</enum>
<description>The desired mode for the camera device's
auto-exposure routine.</description>
@@ -837,7 +884,7 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
To start a CaptureSession with a target FPS range different from the
capture request template's default value, the application
is strongly recommended to call
- {@link SessionConfiguration#setSessionParameters|ACameraDevice_createCaptureSessionWithSessionParameters}
+ {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters|ACameraDevice_createCaptureSessionWithSessionParameters}
with the target fps range before creating the capture session. The aeTargetFpsRange is
typically a session parameter. Specifying it at session creation time helps avoid
session reconfiguration delays in cases like 60fps or high speed recording.
@@ -2113,7 +2160,7 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
Surface types that can be stabilized.
The application is strongly recommended to call
- {@link SessionConfiguration#setSessionParameters|ACameraDevice_createCaptureSessionWithSessionParameters}
+ {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters|ACameraDevice_createCaptureSessionWithSessionParameters}
with the desired video stabilization mode before creating the capture session.
Video stabilization mode is a session parameter on many devices. Specifying
it at session creation time helps avoid reconfiguration delay caused by difference
@@ -3841,6 +3888,61 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
</details>
</entry>
</dynamic>
+ <static>
+ <entry name="lowLightBoostInfoLuminanceRange" type="float" visibility="public"
+ optional="true" container="array" typedef="rangeFloat"
+ aconfig_flag="camera_ae_mode_low_light_boost" hal_version="3.9">
+ <array>
+ <size>2</size>
+ </array>
+ <description>
+ The operating luminance range of low light boost measured in lux (lx).
+ </description>
+ <range>
+ The lower bound indicates the lowest scene luminance value the AE mode
+ 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY' can operate within. Scenes of lower luminance
+ than this may receive less brightening, increased noise, or artifacts.
+
+ The upper bound indicates the luminance threshold at the point when the mode is enabled.
+ For example, 'Range[0.3, 30.0]' defines 0.3 lux being the lowest scene luminance the
+ mode can reliably support. 30.0 lux represents the threshold when this mode is
+ activated. Scenes measured at less than or equal to 30 lux will activate low light
+ boost.
+
+ If this key is defined, then the AE mode 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY' will
+ also be present.
+ </range>
+ </entry>
+ </static>
+ <dynamic>
+ <entry name="lowLightBoostState" type="byte" visibility="public" optional="true" enum="true"
+ aconfig_flag="camera_ae_mode_low_light_boost" hal_version="3.9">
+ <enum>
+ <value>INACTIVE
+ <notes>
+ The AE mode 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY' is enabled but not applied.
+ </notes></value>
+ <value>ACTIVE
+ <notes>
+ The AE mode 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY' is enabled and applied.
+ </notes></value>
+ </enum>
+ <description>
+ Current state of the low light boost AE mode.
+ </description>
+ <details>
+ When low light boost is enabled by setting the AE mode to
+ 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY', it can dynamically apply a low light
+ boost when the light level threshold is exceeded.
+
+ This state indicates when low light boost is 'ACTIVE' and applied. Similarly, it can
+ indicate when it is not being applied by returning 'INACTIVE'.
+
+ This key will be absent from the CaptureResult if AE mode is not set to
+ 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.
+ </details>
+ </entry>
+ </dynamic>
</section>
<section name="demosaic">
<controls>
@@ -4153,6 +4255,102 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
</details>
</entry>
</dynamic>
+ <controls>
+ <entry name="strengthLevel" type="int32" visibility="public" hwlevel="legacy"
+ aconfig_flag="camera_manual_flash_strength_control" hal_version="3.9">
+ <description>Flash strength level to be used when manual flash control is active.
+ </description>
+ <range>`[1-android.flash.info.torchStrengthMaxLevel]` when the android.flash.mode is
+ set to TORCH;
+ `[1-android.flash.info.singleStrengthMaxLevel]` when the android.flash.mode is
+ set to SINGLE
+ </range>
+ <details>Flash strength level to use in capture mode i.e. when the applications control
+ flash with either SINGLE or TORCH mode.
+
+ Use android.flash.info.singleStrengthMaxLevel and
+ android.flash.info.torchStrengthMaxLevel to check whether the device supports
+ flash strength control or not.
+ If the values of android.flash.info.singleStrengthMaxLevel and
+ android.flash.info.torchStrengthMaxLevel are greater than 1,
+ then the device supports manual flash strength control.
+
+ If the android.flash.mode `==` TORCH the value must be &amp;gt;= 1
+ and &amp;lt;= android.flash.info.torchStrengthMaxLevel.
+ If the application doesn't set the key and
+ android.flash.info.torchStrengthMaxLevel &amp;gt; 1,
+ then the flash will be fired at the default level set by HAL in
+ android.flash.info.torchStrengthDefaultLevel.
+ If the android.flash.mode `==` SINGLE, then the value must be &amp;gt;= 1
+ and &amp;lt;= android.flash.info.singleStrengthMaxLevel.
+ If the application does not set this key and
+ android.flash.info.singleStrengthMaxLevel &amp;gt; 1,
+ then the flash will be fired at the default level set by HAL
+ in android.flash.info.singleStrengthDefaultLevel.
+ If android.control.aeMode is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH,
+ ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.
+ </details>
+ </entry>
+ </controls>
+ <static>
+ <entry name="singleStrengthMaxLevel" type="int32" visibility="public" hwlevel="legacy"
+ aconfig_flag="camera_manual_flash_strength_control" hal_version="3.9">
+ <description>Maximum flash brightness level for manual flash control in SINGLE mode.
+ </description>
+ <details>
+ Maximum flash brightness level in camera capture mode and
+ android.flash.mode set to SINGLE.
+ Value will be &amp;gt; 1 if the manual flash strength control feature is supported,
+ otherwise the value will be equal to 1.
+ Note that this level is just a number of supported levels (the granularity of control).
+ There is no actual physical power units tied to this level.
+ </details>
+ </entry>
+ <entry name="singleStrengthDefaultLevel" type="int32" visibility="public" hwlevel="legacy"
+ aconfig_flag="camera_manual_flash_strength_control" hal_version="3.9">
+ <description>Default flash brightness level for manual flash control in SINGLE mode.
+ </description>
+ <details>
+ If flash unit is available this will be greater than or equal to 1 and less
+ or equal to `android.flash.info.singleStrengthMaxLevel`.
+ Note for devices that do not support the manual flash strength control
+ feature, this level will always be equal to 1.
+ </details>
+ </entry>
+ <entry name="torchStrengthMaxLevel" type="int32" visibility="public" hwlevel="legacy"
+ aconfig_flag="camera_manual_flash_strength_control" hal_version="3.9">
+ <description>Maximum flash brightness level for manual flash control in TORCH mode
+ </description>
+ <details>
+ Maximum flash brightness level in camera capture mode and
+ android.flash.mode set to TORCH.
+ Value will be &amp;gt; 1 if the manual flash strength control feature is supported,
+ otherwise the value will be equal to 1.
+
+ Note that this level is just a number of supported levels(the granularity of control).
+ There is no actual physical power units tied to this level.
+ There is no relation between android.flash.info.torchStrengthMaxLevel and
+ android.flash.info.singleStrengthMaxLevel i.e. the ratio of
+ android.flash.info.torchStrengthMaxLevel:android.flash.info.singleStrengthMaxLevel
+ is not guaranteed to be the ratio of actual brightness.
+ </details>
+ </entry>
+ <entry name="torchStrengthDefaultLevel" type="int32" visibility="public" hwlevel="legacy"
+ aconfig_flag="camera_manual_flash_strength_control" hal_version="3.9">
+ <description>Default flash brightness level for manual flash control in TORCH mode
+ </description>
+ <details>
+ If flash unit is available this will be greater than or equal to 1 and less
+ or equal to android.flash.info.torchStrengthMaxLevel.
+ Note for the devices that do not support the manual flash strength control feature,
+ this level will always be equal to 1.
+ </details>
+ </entry>
+ </static>
+ <dynamic>
+ <clone entry="android.flash.strengthLevel" kind="controls">
+ </clone>
+ </dynamic>
</section>
<section name="hotPixel">
<controls>
@@ -6320,10 +6518,10 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
Combinations of logical and physical streams, or physical streams from different
physical cameras are not guaranteed. However, if the camera device supports
- {@link CameraDevice#isSessionConfigurationSupported|ACameraDevice_isSessionConfigurationSupported},
+ {@link CameraManager#isSessionConfigurationWithParametersSupported|ACameraDevice_isSessionConfigurationSupported},
application must be able to query whether a stream combination involving physical
streams is supported by calling
- {@link CameraDevice#isSessionConfigurationSupported|ACameraDevice_isSessionConfigurationSupported}.
+ {@link CameraManager#isSessionConfigurationWithParametersSupported|ACameraDevice_isSessionConfigurationSupported}.
Camera application shouldn't assume that there are at most 1 rear camera and 1 front
camera in the system. For an application that switches between front and back cameras,
@@ -6596,8 +6794,7 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
* Profile {@link android.hardware.camera2.params.DynamicRangeProfiles#HLG10}
* All mandatory stream combinations for this specific capability as per
- documentation
- {@link android.hardware.camera2.CameraDevice#10-bit-output-additional-guaranteed-configurations}
+ [documentation](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#10-bit-output-additional-guaranteed-configurations)
* In case the device is not able to capture some combination of supported
standard 8-bit and/or 10-bit dynamic range profiles within the same capture request,
then those constraints must be listed in
@@ -6635,8 +6832,8 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
{@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES}
lists all of the supported stream use cases.
- Refer to
- {@link android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations}
+ Refer to the
+ [guideline](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations)
for the mandatory stream combinations involving stream use cases, which can also be
queried via {@link android.hardware.camera2.params.MandatoryStreamCombination}.
</notes>
@@ -8136,7 +8333,7 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
31.
Refer to android.request.availableCapabilities and
- {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations}
+ [the table](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations)
for additional mandatory stream configurations on a per-capability basis.
*1: For JPEG format, the sizes may be restricted by below conditions:
@@ -8449,15 +8646,14 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
{@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
and {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}.
This is an app-readable conversion of the mandatory stream combination
- {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations
- tables}.
+ [tables](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations).
</description>
<details>
The array of
{@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
generated according to the documented
- {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations
- guideline} based on specific device level and capabilities.
+ [guideline](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations).
+ based on specific device level and capabilities.
Clients can use the array as a quick reference to find an appropriate camera stream
combination.
As per documentation, the stream combinations with given PREVIEW, RECORD and
@@ -8484,15 +8680,14 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
<description>
An array of mandatory concurrent stream combinations.
This is an app-readable conversion of the concurrent mandatory stream combination
- {@link android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations
- tables}.
+ [tables](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#concurrent-stream-guaranteed-configurations).
</description>
<details>
The array of
{@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
generated according to the documented
- {@link android.hardware.camera2.CameraDevice#concurrent-stream-guaranteed-configurations
- guideline} for each device which has its Id present in the set returned by
+ [guideline](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#concurrent-stream-guaranteed-configurations)
+ for each device which has its Id present in the set returned by
{@link android.hardware.camera2.CameraManager#getConcurrentCameraIds}.
Clients can use the array as a quick reference to find an appropriate camera stream
combination.
@@ -8672,7 +8867,7 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
When the key is present, only a PRIVATE/YUV output of the specified size is guaranteed
to be supported by the camera HAL in the secure camera mode. Any other format or
resolutions might not be supported. Use
- {@link CameraDevice#isSessionConfigurationSupported|ACameraDevice_isSessionConfigurationSupported}
+ {@link CameraManager#isSessionConfigurationWithParametersSupported|ACameraDevice_isSessionConfigurationSupported}
API to query if a secure session configuration is supported if the device supports this
API.
@@ -8752,7 +8947,7 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
If a camera device supports multi-resolution output streams for a particular format, for
each of its mandatory stream combinations, the camera device will support using a
MultiResolutionImageReader for the MAXIMUM stream of supported formats. Refer to
- {@link android.hardware.camera2.CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs}
+ [the table](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs)
for additional details.
To use multi-resolution input streams, the supported formats can be queried by {@link
@@ -8766,7 +8961,7 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
{@code YUV} output, or multi-resolution {@code PRIVATE} input and multi-resolution
{@code PRIVATE} output, {@code JPEG} and {@code YUV} are guaranteed to be supported
multi-resolution output stream formats. Refer to
- {@link android.hardware.camera2.CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs}}
+ [the table](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-additional-guaranteed-combinations-with-multiresolutionoutputs)
for details about the additional mandatory stream combinations in this case.
</details>
<hal_details>
@@ -8905,15 +9100,14 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
{@link android.hardware.camera2.CaptureRequest} has android.sensor.pixelMode set
to {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION}.
This is an app-readable conversion of the maximum resolution mandatory stream combination
- {@link android.hardware.camera2.CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors
- tables}.
+ [tables](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors).
</description>
<details>
The array of
{@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
generated according to the documented
- {@link android.hardware.camera2.CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors
- guideline} for each device which has the
+ [guideline](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#additional-guaranteed-combinations-for-ultra-high-resolution-sensors)
+ for each device which has the
{@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR}
capability.
Clients can use the array as a quick reference to find an appropriate camera stream
@@ -8938,15 +9132,14 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
10-bit output capability
{@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
This is an app-readable conversion of the 10 bit output mandatory stream combination
- {@link android.hardware.camera2.CameraDevice#10-bit-output-additional-guaranteed-configurations
- tables}.
+ [tables](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#10-bit-output-additional-guaranteed-configurations).
</description>
<details>
The array of
{@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
generated according to the documented
- {@link android.hardware.camera2.CameraDevice#10-bit-output-additional-guaranteed-configurations
- guideline} for each device which has the
+ [guideline](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#10-bit-output-additional-guaranteed-configurations)
+ for each device which has the
{@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
capability.
Clients can use the array as a quick reference to find an appropriate camera stream
@@ -8971,15 +9164,14 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
{@code PREVIEW_STABILIZATION} in android.control.availableVideoStabilizationModes.
This is an app-readable conversion of the preview stabilization mandatory stream
combination
- {@link android.hardware.camera2.CameraDevice#preview-stabilization-guaranteed-stream-configurations
- tables}.
+ [tables](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#preview-stabilization-guaranteed-stream-configurations).
</description>
<details>
The array of
{@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
generated according to the documented
- {@link android.hardware.camera2.CameraDevice#preview-stabilization-guaranteed-stream-configurations
- guideline} for each device which supports {@code PREVIEW_STABILIZATION}
+ [guideline](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#preview-stabilization-guaranteed-stream-configurations)
+ for each device which supports {@code PREVIEW_STABILIZATION}
Clients can use the array as a quick reference to find an appropriate camera stream
combination.
The mandatory stream combination array will be {@code null} in case the device does not
@@ -9211,9 +9403,8 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
The guaranteed stream combinations related to stream use case for a camera device with
{@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}
capability is documented in the camera device
- {@link android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations
- guideline}. The application is strongly recommended to use one of the guaranteed stream
- combinations.
+ [guideline](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations).
+ The application is strongly recommended to use one of the guaranteed stream combinations.
If the application creates a session with a stream combination not in the guaranteed
list, or with mixed DEFAULT and non-DEFAULT use cases within the same session,
the camera device may ignore some stream use cases due to hardware constraints
@@ -9237,15 +9428,15 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
<description>
An array of mandatory stream combinations with stream use cases.
This is an app-readable conversion of the mandatory stream combination
- {@link android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations
- tables} with each stream's use case being set.
+ [tables](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations)
+ with each stream's use case being set.
</description>
<details>
The array of
{@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
generated according to the documented
- {@link android.hardware.camera2.CameraDevice#stream-use-case-capability-additional-guaranteed-configurations
- guideline} for a camera device with
+ [guildeline](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations)
+ for a camera device with
{@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}
capability.
The mandatory stream combination array will be {@code null} in case the device doesn't
@@ -9330,8 +9521,8 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
<tag id="V1" />
</entry>
<entry name="frameDuration" type="int64" visibility="public" hwlevel="full">
- <description>Duration from start of frame exposure to
- start of next frame exposure.</description>
+ <description>Duration from start of frame readout to
+ start of next frame readout.</description>
<units>Nanoseconds</units>
<range>See android.sensor.info.maxFrameDuration, {@link
android.hardware.camera2.params.StreamConfigurationMap|ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS}.
@@ -9406,6 +9597,11 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
This control is only effective if android.control.aeMode or android.control.mode is set to
OFF; otherwise the auto-exposure algorithm will override this value.
+
+ *Note:* Prior to Android 13, this field was described as measuring the duration from
+ start of frame exposure to start of next frame exposure, which doesn't reflect the
+ definition from sensor manufacturer. A mobile sensor defines the frame duration as
+ intervals between sensor readouts.
</details>
<hal_details>
For more details about stalling, see
@@ -12041,6 +12237,59 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
is needed.
</details>
</entry>
+ <entry name="lensIntrinsicsSamples" type="float" visibility="java_public" synthetic="true"
+ container="array" typedef="lensIntrinsicsSample" aconfig_flag="concert_mode"
+ hal_version="3.9">
+ <array>
+ <size>n</size>
+ </array>
+ <description>
+ An array of intra-frame lens intrinsic samples.
+ </description>
+ <details>
+ Contains an array of intra-frame android.lens.intrinsicCalibration updates. This must
+ not be confused or compared to android.statistics.oisSamples. Although OIS could be the
+ main driver, all relevant factors such as focus distance and optical zoom must also
+ be included. Do note that OIS samples must not be applied on top of the lens intrinsic
+ samples.
+ Support for this capture result can be queried via
+ {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys}.
+ If available, clients can expect multiple samples per capture result. The specific
+ amount will depend on current frame duration and sampling rate. Generally a sampling rate
+ greater than or equal to 200Hz is considered sufficient for high quality results.
+ </details>
+ </entry>
+ <entry name="lensIntrinsicTimestamps" type="int64" visibility="ndk_public" container="array"
+ aconfig_flag="concert_mode" hal_version="3.9">
+ <array>
+ <size>n</size>
+ </array>
+ <description>
+ An array of timestamps of lens intrinsics samples, in nanoseconds.
+ </description>
+ <units>nanoseconds</units>
+ <details>
+ The array contains the timestamps of lens intrinsics samples. The timestamps are in the
+ same timebase as and comparable to android.sensor.timestamp.
+ </details>
+ </entry>
+ <entry name="lensIntrinsicSamples" type="float" visibility="ndk_public"
+ container="array" aconfig_flag="concert_mode" hal_version="3.9">
+ <array>
+ <size>5</size>
+ <size>n</size>
+ </array>
+ <description>
+ An array of intra-frame lens intrinsics.
+ </description>
+ <units>
+ Pixels in the android.sensor.info.preCorrectionActiveArraySize coordinate system.
+ </units>
+ <details>
+ The data layout and contents of individual array entries matches with
+ android.lens.intrinsicCalibration.
+ </details>
+ </entry>
</dynamic>
</section>
<section name="tonemap">
@@ -12464,9 +12713,9 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
This camera device does not have enough capabilities to qualify as a `FULL` device or
better.
- Only the stream configurations listed in the `LEGACY` and `LIMITED` tables in the
- {@link android.hardware.camera2.CameraDevice#limited-level-additional-guaranteed-configurations|ACameraDevice_createCaptureSession}
- documentation are guaranteed to be supported.
+ Only the stream configurations listed in the `LEGACY` and `LIMITED`
+ [tables](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#limited-level-additional-guaranteed-configurations)
+ in the documentation are guaranteed to be supported.
All `LIMITED` devices support the `BACKWARDS_COMPATIBLE` capability, indicating basic
support for color image capture. The only exception is that the device may
@@ -12491,9 +12740,9 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
<notes>
This camera device is capable of supporting advanced imaging applications.
- The stream configurations listed in the `FULL`, `LEGACY` and `LIMITED` tables in the
- {@link android.hardware.camera2.CameraDevice#full-level-additional-guaranteed-configurations|ACameraDevice_createCaptureSession}
- documentation are guaranteed to be supported.
+ The stream configurations listed in the `FULL`, `LEGACY` and `LIMITED`
+ [tables](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#full-level-additional-guaranteed-configurations)
+ in the documentation are guaranteed to be supported.
A `FULL` device will support below capabilities:
@@ -12517,9 +12766,9 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
<notes>
This camera device is running in backward compatibility mode.
- Only the stream configurations listed in the `LEGACY` table in the
- {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations|ACameraDevice_createCaptureSession}
- documentation are supported.
+ Only the stream configurations listed in the `LEGACY`
+ [table](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations)
+ in the documentation are supported.
A `LEGACY` device does not support per-frame control, manual sensor control, manual
post-processing, arbitrary cropping regions, and has relaxed performance constraints.
@@ -12544,9 +12793,9 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
FULL-level capabilities.
The stream configurations listed in the `LEVEL_3`, `RAW`, `FULL`, `LEGACY` and
- `LIMITED` tables in the
- {@link android.hardware.camera2.CameraDevice#level-3-additional-guaranteed-configurations|ACameraDevice_createCaptureSession}
- documentation are guaranteed to be supported.
+ `LIMITED`
+ [tables](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#level-3-additional-guaranteed-configurations)
+ in the documentation are guaranteed to be supported.
The following additional capabilities are guaranteed to be supported:
@@ -12692,6 +12941,15 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
HIDL ICameraDevice version 3.5.
</notes>
</value>
+ <value hal_version="3.9" aconfig_flag="session_hal_buf_manager">
+ SESSION_CONFIGURABLE
+ <notes>
+ This camera device supports the buffer management APIs provided by AIDL ICameraDevice
+ version 1. It also supports the ICameraDeviceSession.configureStreamsV2 call to
+ inform the camera framework whether HAL buffer manager must be used for the
+ particular session configured.
+ </notes>
+ </value>
</enum>
<description>
The version of buffer management API this camera device supports and opts into.
@@ -12732,6 +12990,90 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
supported device state bitwise combination.
</details>
</entry>
+ <entry name="sessionConfigurationQueryVersion" type="int32"
+ visibility="fwk_java_public" enum="true" typedef="versionCode"
+ hwlevel="legacy" aconfig_flag="feature_combination_query">
+ <enum>
+ <value id="34">UPSIDE_DOWN_CAKE</value>
+ <value id="35">VANILLA_ICE_CREAM</value>
+ </enum>
+ <description>The version of the session configuration query
+ {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported}
+ API
+ </description>
+ <details>The possible values in this key correspond to the values defined in
+ android.os.Build.VERSION_CODES. Each version defines a set of feature combinations the
+ camera device must reliably report whether they are supported via
+ {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported}
+ API. And the version is always less or equal to android.os.Build.VERSION.SDK_INT.
+
+ If set to UPSIDE_DOWN_CAKE, this camera device doesn't support
+ {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported}.
+ Calling the method for this camera ID throws an UnsupportedOperationException.
+
+ If set to VANILLA_ICE_CREAM, the application can call
+ {@link android.hardware.camera2.CameraManager#isSessionConfigurationWithParametersSupported}
+ to check if the combinations of below features are supported.
+
+ * A subset of LIMITED-level device stream combinations.
+
+ Target 1 | Size | Target 2 | Size | Sample use case(s)
+ :----------:|:-------------:|:-----------:|:-----------:|:-------------------:
+ PRIV | MAXIMUM | | | Simple preview, GPU video processing, or no-preview video recording.
+ PRIV | PREVIEW | | |
+ PRIV | S1440P | | |
+ PRIV | S1080P | | |
+ PRIV | S720P | | |
+ YUV | MAXIMUM | | | In-application video/image processing.
+ YUV | PREVIEW | | |
+ YUV | S1440P | | |
+ YUV | S1080P | | |
+ YUV | S720P | | |
+ PRIV | PREVIEW | JPEG | MAXIMUM | Standard still imaging.
+ PRIV | S1440P | JPEG | MAXIMUM |
+ PRIV | S1080P | JPEG | MAXIMUM |
+ PRIV | S720P | JPEG | MAXIMUM |
+ PRIV | S1440P | JPEG | S1440P |
+ PRIV | S1080P | JPEG | S1080P |
+ PRIV | S720P | JPEG | S1080P |
+ YUV | PREVIEW | JPEG | MAXIMUM | In-app processing plus still capture.
+ YUV | S1440P | JPEG | MAXIMUM |
+ YUV | S1080P | JPEG | MAXIMUM |
+ YUV | S720P | JPEG | MAXIMUM |
+ YUV | S1440P | JPEG | S1440P |
+ YUV | S1080P | JPEG | S1080P |
+ YUV | S720P | JPEG | S1080P |
+ PRIV | PREVIEW | PRIV | PREVIEW | Standard recording.
+ PRIV | S1440P | PRIV | S1440P |
+ PRIV | S1080P | PRIV | S1080P |
+ PRIV | S720P | PRIV | S720P |
+ PRIV | PREVIEW | YUV | PREVIEW | Preview plus in-app processing.
+ PRIV | S1440P | YUV | S1440P |
+ PRIV | S1080P | YUV | S1080P |
+ PRIV | S720P | YUV | S720P |
+
+ - {@code MAXIMUM} size refers to the camera device's maximum output resolution for
+ that format from {@code StreamConfigurationMap#getOutputSizes}. {@code PREVIEW} size
+ refers to the best size match to the device's screen resolution, or to 1080p
+ (@code 1920x1080}, whichever is smaller. Both sizes are guaranteed to be supported.
+
+ - {@code S1440P} refers to {@code 1920x1440 (4:3)} and {@code 2560x1440 (16:9)}.
+ {@code S1080P} refers to {@code 1440x1080 (4:3)} and {@code 1920x1080 (16:9)}.
+ And {@code S720P} refers to {@code 960x720 (4:3)} and {@code 1280x720 (16:9)}.
+
+ - If a combination contains a S1440P, S1080P, or S720P stream,
+ both 4:3 and 16:9 aspect ratio sizes can be queried. For example, for the
+ stream combination of {PRIV, S1440P, JPEG, MAXIMUM}, and if MAXIMUM ==
+ 4032 x 3024, the application will be able to query both
+ {PRIV, 1920 x 1440, JPEG, 4032 x 3024} and {PRIV, 2560 x 1440, JPEG, 4032 x 2268}
+ without an exception being thrown.
+
+ * VIDEO_STABILIZATION_MODES: {OFF, PREVIEW}
+ * AE_TARGET_FPS_RANGE: {{*, 30}, {*, 60}}
+ * DYNAMIC_RANGE_PROFILE: {STANDARD, HLG10}
+
+ </details>
+ </entry>
</static>
</section>
<section name="blackLevel">
@@ -13487,6 +13829,25 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
The number of physical camera IDs must be no less than 2.
</details>
+ <hal_details>
+ Each physical camera id should uniquely identify a camera lens in the system.
+ So if each camera lens only backs one logical camera, all camera IDs in the system,
+ physical IDs or non-physical IDs, should be unique.
+
+ In rare cases, one camera lens backs two different logical cameras, the
+ physicalIds of both logical cameras should contain a physical camera ID
+ identifying that same camera lens. For example, if the mobile device has 3 rear facing
+ cameras and no front facing cameras, and the 3 rear facing lenses may be modelled as
+ 2 logical cameras:
+
+ - "device@1.0/internal/10": physicalIds: "camera0", "camera42"
+ - "device@1.0/internal/11": physicalIds: "camera1", "camera42"
+
+ In this case, the two logical cameras are conflicting devices because they are backed
+ by a common lens.
+
+ Physical camera IDs can be an arbitrary string not containing '\0'.
+ </hal_details>
<tag id="LOGICALCAMERA" />
</entry>
<entry name="sensorSyncType" type="byte" visibility="public"
@@ -13556,6 +13917,60 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
</hal_details>
<tag id="LOGICALCAMERA" />
</entry>
+ <entry name="activePhysicalSensorCropRegion" type="int32" visibility="public"
+ container="array" typedef="rectangle" aconfig_flag="concert_mode" hal_version="3.9">
+ <array>
+ <size>4</size>
+ </array>
+ <description>The current region of the active physical sensor that will be read out for this
+ capture.</description>
+ <units>Pixel coordinates relative to
+ android.sensor.info.activeArraySize or
+ android.sensor.info.preCorrectionActiveArraySize of the currently
+ android.logicalMultiCamera.activePhysicalId depending on distortion correction capability
+ and mode</units>
+ <details>
+ This capture result matches with android.scaler.cropRegion on non-logical single
+ camera sensor devices. In case of logical cameras that can switch between several
+ physical devices in response to android.control.zoomRatio, this capture result will
+ not behave like android.scaler.cropRegion and android.control.zoomRatio, where the
+ combination of both reflects the effective zoom and crop of the logical camera output.
+ Instead, this capture result value will describe the zoom and crop of the active physical
+ device. Some examples of when the value of this capture result will change include
+ switches between different physical lenses, switches between regular and maximum
+ resolution pixel mode and going through the device digital or optical range.
+ This capture result is similar to android.scaler.cropRegion with respect to distortion
+ correction. When the distortion correction mode is OFF, the coordinate system follows
+ android.sensor.info.preCorrectionActiveArraySize, with (0, 0) being the top-left pixel
+ of the pre-correction active array. When the distortion correction mode is not OFF,
+ the coordinate system follows android.sensor.info.activeArraySize, with (0, 0) being
+ the top-left pixel of the active array.
+
+ For camera devices with the
+ {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR}
+ capability or devices where {@link CameraCharacteristics#getAvailableCaptureRequestKeys}
+ lists {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode}
+ , the current active physical device
+ android.sensor.info.activeArraySizeMaximumResolution /
+ android.sensor.info.preCorrectionActiveArraySizeMaximumResolution must be used as the
+ coordinate system for requests where android.sensor.pixelMode is set to
+ {@link android.hardware.camera2.CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION}.
+ </details>
+ <ndk_details>
+ The data representation is int[4], which maps to (left, top, width, height).
+ </ndk_details>
+ <hal_details>
+ The output streams must maintain square pixels at all
+ times, no matter what the relative aspect ratios of the
+ crop region and the stream are. Negative values for
+ corner are allowed for raw output if full pixel array is
+ larger than active pixel array. Width and height may be
+ rounded to nearest larger supportable width, especially
+ for raw output, where only a few fixed scales may be
+ possible.
+ </hal_details>
+ <tag id="LOGICALCAMERA" />
+ </entry>
</dynamic>
</section>
<section name="distortionCorrection">
@@ -13653,8 +14068,8 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
</enum>
<description>Whether this camera device can support identical set of stream combinations
involving HEIC image format, compared to the
- {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations
- table of combinations} involving JPEG image format required for the device's hardware
+ [table of combinations](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations)
+ involving JPEG image format required for the device's hardware
level and capabilities.
</description>
<details>
@@ -13665,8 +14080,8 @@ xsi:schemaLocation="http://schemas.android.com/service/camera/metadata/ metadata
If a camera device supports HEIC format (ISO/IEC 23008-12), not only does it
support the existing mandatory stream
- {@link android.hardware.camera2.CameraDevice#legacy-level-guaranteed-configurations
- combinations} required for the device's hardware level and capabilities, it also
+ [combinations](https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations)
+ required for the device's hardware level and capabilities, it also
supports swapping each JPEG stream with HEIC stream in all guaranteed combinations.
For every HEIC stream configured by the application, the camera framework sets up 2
diff --git a/camera/docs/metadata_definitions.xsd b/camera/docs/metadata_definitions.xsd
index 2a167262..d66e5271 100644
--- a/camera/docs/metadata_definitions.xsd
+++ b/camera/docs/metadata_definitions.xsd
@@ -253,6 +253,7 @@
</restriction>
</simpleType>
</attribute>
+ <attribute name="aconfig_flag" type="string" />
</complexType>
<complexType name="EnumType">
@@ -327,6 +328,7 @@
</attribute>
<attribute name="id" type="string" />
<attribute name="hal_version" type="decimal" default="3.2" />
+ <attribute name="aconfig_flag" type="string" />
</complexType>
<complexType name="CloneType">
diff --git a/camera/docs/metadata_helpers.py b/camera/docs/metadata_helpers.py
index f3d52a67..37b3d59c 100644
--- a/camera/docs/metadata_helpers.py
+++ b/camera/docs/metadata_helpers.py
@@ -189,6 +189,7 @@ def protobuf_type(entry):
"deviceStateSensorOrientationMap" : "DeviceStateSensorOrientationMap",
"dynamicRangeProfiles" : "DynamicRangeProfiles",
"colorSpaceProfiles" : "ColorSpaceProfiles",
+ "versionCode" : "int32",
}
if typeName not in typename_to_protobuftype:
@@ -768,7 +769,7 @@ def generate_extra_javadoc_detail(entry):
if entry.enum and not (entry.typedef and entry.typedef.languages.get('java')):
text += '\n\n<b>Possible values:</b>\n<ul>\n'
for value in entry.enum.values:
- if not value.hidden:
+ if not value.hidden and (value.aconfig_flag == entry.aconfig_flag):
text += ' <li>{@link #%s %s}</li>\n' % ( jenum_value(entry, value ), value.name )
text += '</ul>\n'
if entry.range:
@@ -1622,4 +1623,4 @@ def aidl_enum_values(entry):
]
return [
val for val in entry.enum.values if '%s_%s'%(csym(entry.name), val.name) not in ignoreList
- ] \ No newline at end of file
+ ]
diff --git a/camera/docs/metadata_model.py b/camera/docs/metadata_model.py
index 4428c90e..db11f6b7 100644
--- a/camera/docs/metadata_model.py
+++ b/camera/docs/metadata_model.py
@@ -985,9 +985,11 @@ class EnumValue(Node):
parent: An edge to the parent, always an Enum instance.
hal_major_version: The major HIDL HAL version this value was first added in
hal_minor_version: The minor HIDL HAL version this value was first added in
+ aconfig_flag: The aconfig flag name that determines if this enum value is actually enabled
"""
def __init__(self, name, parent,
- id=None, deprecated=False, optional=False, visibility=None, notes=None, sdk_notes=None, ndk_notes=None, hal_version='3.2'):
+ id=None, deprecated=False, optional=False, visibility=None, notes=None,
+ sdk_notes=None, ndk_notes=None, hal_version='3.2', aconfig_flag=None):
self._name = name # str, e.g. 'ON' or 'OFF'
self._id = id # int, e.g. '0'
self._deprecated = deprecated # bool
@@ -1008,6 +1010,11 @@ class EnumValue(Node):
self._hal_major_version = int(hal_version.partition('.')[0])
self._hal_minor_version = int(hal_version.partition('.')[2])
+ self._aconfig_flag = aconfig_flag
+ if self._aconfig_flag is None:
+ if parent is not None and parent.parent is not None:
+ self._aconfig_flag = parent.parent.aconfig_flag
+
@property
def id(self):
return self._id
@@ -1066,6 +1073,10 @@ class EnumValue(Node):
def hal_minor_version(self):
return self._hal_minor_version
+ @property
+ def aconfig_flag(self):
+ return self._aconfig_flag
+
def _get_children(self):
return None
@@ -1080,12 +1091,14 @@ class Enum(Node):
non-empty id property.
"""
def __init__(self, parent, values, ids={}, deprecateds=[],
- optionals=[], visibilities={}, notes={}, sdk_notes={}, ndk_notes={}, hal_versions={}):
+ optionals=[], visibilities={}, notes={}, sdk_notes={}, ndk_notes={},
+ hal_versions={}, aconfig_flags={}):
self._parent = parent
self._name = None
self._values = \
[ EnumValue(val, self, ids.get(val), val in deprecateds, val in optionals, visibilities.get(val), \
- notes.get(val), sdk_notes.get(val), ndk_notes.get(val), hal_versions.get(val)) \
+ notes.get(val), sdk_notes.get(val), ndk_notes.get(val), hal_versions.get(val), \
+ aconfig_flags.get(val)) \
for val in values ]
@property
@@ -1135,6 +1148,7 @@ class Entry(Node):
hwlevels will also include this entry. None means that the
entry is optional on any hardware level.
permission_needed: Flags whether the tag needs extra camera permission.
+ aconfig_flag: The aconfig flag name that determines if the entry is actually enabled
deprecated: Marks an entry as @Deprecated in the Java layer; if within an
unreleased version this needs to be removed altogether. If applied
to an entry from an older release, then this means the entry
@@ -1187,6 +1201,7 @@ class Entry(Node):
enum_notes: A dictionary of value->notes strings.
enum_ids: A dictionary of value->id strings.
enum_hal_versions: A dictionary of value->hal version strings
+ enum_aconfig_flags: A dictionary of value->aconfig flag name strings
Args (if the 'deprecated' attribute is true):
deprecation_description: A string explaining the deprecation, to be added
@@ -1282,6 +1297,10 @@ class Entry(Node):
def permission_needed(self):
return self._permission_needed or "false"
+ @property
+ def aconfig_flag(self):
+ return self._aconfig_flag
+
# TODO: optional should just return hwlevel is None
@property
def optional(self):
@@ -1401,6 +1420,8 @@ class Entry(Node):
self._hal_major_version = int(hal_version.partition('.')[0])
self._hal_minor_version = int(hal_version.partition('.')[2])
+ self._aconfig_flag = kwargs.get('aconfig_flag')
+
# access these via the 'enum' prop
enum_values = kwargs.get('enum_values')
enum_deprecateds = kwargs.get('enum_deprecateds')
@@ -1411,6 +1432,7 @@ class Entry(Node):
enum_ndk_notes = kwargs.get('enum_ndk_notes') # { value => ndk_notes }
enum_ids = kwargs.get('enum_ids') # { value => notes }
enum_hal_versions = kwargs.get('enum_hal_versions') # { value => hal_versions }
+ enum_aconfig_flags = kwargs.get('enum_aconfig_flags') # { value => aconfig flags }
self._tuple_values = kwargs.get('tuple_values')
@@ -1430,7 +1452,8 @@ class Entry(Node):
if kwargs.get('enum', False):
self._enum = Enum(self, enum_values, enum_ids, enum_deprecateds, enum_optionals,
- enum_visibilities, enum_notes, enum_sdk_notes, enum_ndk_notes, enum_hal_versions)
+ enum_visibilities, enum_notes, enum_sdk_notes, enum_ndk_notes,
+ enum_hal_versions, enum_aconfig_flags)
else:
self._enum = None
@@ -1651,7 +1674,8 @@ class MergedEntry(Entry):
'typedef',
'hal_major_version',
'hal_minor_version',
- 'permission_needed'
+ 'permission_needed',
+ 'aconfig_flag'
]
for p in props_common:
diff --git a/camera/docs/metadata_parser_xml.py b/camera/docs/metadata_parser_xml.py
index 5db2443a..f8feeecc 100755
--- a/camera/docs/metadata_parser_xml.py
+++ b/camera/docs/metadata_parser_xml.py
@@ -187,6 +187,9 @@ class MetadataParserXml:
#
d['permission_needed'] = entry.get('permission_needed')
+ # Aconfig flag gating this entry ?
+ d['aconfig_flag'] = entry.get('aconfig_flag')
+
#
# Hardware Level (one of limited, legacy, full)
#
@@ -225,6 +228,7 @@ class MetadataParserXml:
enum_ndk_notes = {}
enum_ids = {}
enum_hal_versions = {}
+ enum_aconfig_flags = {}
for value in entry.enum.find_all('value'):
value_body = self._strings_no_nl(value)
@@ -258,6 +262,9 @@ class MetadataParserXml:
if value.attrs.get('hal_version') is not None:
enum_hal_versions[value_body] = value['hal_version']
+ if value.attrs.get('aconfig_flag') is not None:
+ enum_aconfig_flags[value_body] = value['aconfig_flag']
+
d['enum_values'] = enum_values
d['enum_deprecateds'] = enum_deprecateds
d['enum_optionals'] = enum_optionals
@@ -267,6 +274,7 @@ class MetadataParserXml:
d['enum_ndk_notes'] = enum_ndk_notes
d['enum_ids'] = enum_ids
d['enum_hal_versions'] = enum_hal_versions
+ d['enum_aconfig_flags'] = enum_aconfig_flags
d['enum'] = True
#
diff --git a/camera/docs/metadata_template.mako b/camera/docs/metadata_template.mako
index a6730650..f8c47145 100644
--- a/camera/docs/metadata_template.mako
+++ b/camera/docs/metadata_template.mako
@@ -128,6 +128,10 @@
permission_needed="true"
% endif
+ % if prop.aconfig_flag:
+ aconfig_flag="${prop.aconfig_flag}"
+ % endif
+
% if (prop.hal_major_version, prop.hal_minor_version) != (3,2):
hal_version="${prop.hal_major_version}.${prop.hal_minor_version}"
% endif
@@ -165,6 +169,9 @@
% if not (value.hal_major_version == prop.hal_major_version and value.hal_minor_version == prop.hal_minor_version):
hal_version=${"%d.%d" % (value.hal_major_version, value.hal_minor_version)}
% endif
+ % if not (value.aconfig_flag == prop.aconfig_flag):
+ aconfig_flag="${value.aconfig_flag}"
+ % endif
>${value.name}
% if value.notes is not None:
<notes>${value.notes}</notes>
diff --git a/camera/include/system/camera_metadata_tags.h b/camera/include/system/camera_metadata_tags.h
index edf5fe6a..e3425264 100644
--- a/camera/include/system/camera_metadata_tags.h
+++ b/camera/include/system/camera_metadata_tags.h
@@ -200,6 +200,9 @@ typedef enum camera_metadata_tag {
ANDROID_CONTROL_AUTOFRAMING, // enum | public | HIDL v3.9
ANDROID_CONTROL_AUTOFRAMING_AVAILABLE, // enum | public | HIDL v3.9
ANDROID_CONTROL_AUTOFRAMING_STATE, // enum | public | HIDL v3.9
+ ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE,
+ // float[] | public | HIDL v3.9
+ ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE, // enum | public | HIDL v3.9
ANDROID_CONTROL_END,
ANDROID_DEMOSAIC_MODE = // enum | system | HIDL v3.2
@@ -219,6 +222,11 @@ typedef enum camera_metadata_tag {
ANDROID_FLASH_COLOR_TEMPERATURE, // byte | system | HIDL v3.2
ANDROID_FLASH_MAX_ENERGY, // byte | system | HIDL v3.2
ANDROID_FLASH_STATE, // enum | public | HIDL v3.2
+ ANDROID_FLASH_STRENGTH_LEVEL, // int32 | public | HIDL v3.9
+ ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL, // int32 | public | HIDL v3.9
+ ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL, // int32 | public | HIDL v3.9
+ ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL, // int32 | public | HIDL v3.9
+ ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL, // int32 | public | HIDL v3.9
ANDROID_FLASH_END,
ANDROID_FLASH_INFO_AVAILABLE = // enum | public | HIDL v3.2
@@ -448,6 +456,8 @@ typedef enum camera_metadata_tag {
ANDROID_STATISTICS_OIS_TIMESTAMPS, // int64[] | ndk_public | HIDL v3.3
ANDROID_STATISTICS_OIS_X_SHIFTS, // float[] | ndk_public | HIDL v3.3
ANDROID_STATISTICS_OIS_Y_SHIFTS, // float[] | ndk_public | HIDL v3.3
+ ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS, // int64[] | ndk_public | HIDL v3.9
+ ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES, // float[] | ndk_public | HIDL v3.9
ANDROID_STATISTICS_END,
ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES =
@@ -486,6 +496,7 @@ typedef enum camera_metadata_tag {
ANDROID_INFO_VERSION, // byte | public | HIDL v3.3
ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, // enum | system | HIDL v3.4
ANDROID_INFO_DEVICE_STATE_ORIENTATIONS, // int64[] | ndk_public | HIDL v3.7
+ ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION, // enum | fwk_java_public
ANDROID_INFO_END,
ANDROID_BLACK_LEVEL_LOCK = // enum | public | HIDL v3.2
@@ -535,6 +546,8 @@ typedef enum camera_metadata_tag {
ANDROID_LOGICAL_MULTI_CAMERA_START,
ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE, // enum | public | HIDL v3.3
ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID, // byte | public | HIDL v3.4
+ ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION,
+ // int32[] | public | HIDL v3.9
ANDROID_LOGICAL_MULTI_CAMERA_END,
ANDROID_DISTORTION_CORRECTION_MODE = // enum | public | HIDL v3.3
@@ -630,6 +643,7 @@ typedef enum camera_metadata_enum_android_control_ae_mode {
ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH , // HIDL v3.2
ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE , // HIDL v3.2
ANDROID_CONTROL_AE_MODE_ON_EXTERNAL_FLASH , // HIDL v3.3
+ ANDROID_CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY , // HIDL v3.9
} camera_metadata_enum_android_control_ae_mode_t;
// ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER
@@ -848,6 +862,12 @@ typedef enum camera_metadata_enum_android_control_autoframing_state {
ANDROID_CONTROL_AUTOFRAMING_STATE_CONVERGED , // HIDL v3.9
} camera_metadata_enum_android_control_autoframing_state_t;
+// ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE
+typedef enum camera_metadata_enum_android_control_low_light_boost_state {
+ ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE , // HIDL v3.9
+ ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_ACTIVE , // HIDL v3.9
+} camera_metadata_enum_android_control_low_light_boost_state_t;
+
// ANDROID_DEMOSAIC_MODE
typedef enum camera_metadata_enum_android_demosaic_mode {
@@ -1295,8 +1315,18 @@ typedef enum camera_metadata_enum_android_info_supported_hardware_level {
// ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION
typedef enum camera_metadata_enum_android_info_supported_buffer_management_version {
ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5, // HIDL v3.4
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE
+ , // HIDL v3.9
} camera_metadata_enum_android_info_supported_buffer_management_version_t;
+// ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION
+typedef enum camera_metadata_enum_android_info_session_configuration_query_version {
+ ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION_UPSIDE_DOWN_CAKE
+ = 34,
+ ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION_VANILLA_ICE_CREAM
+ = 35,
+} camera_metadata_enum_android_info_session_configuration_query_version_t;
+
// ANDROID_BLACK_LEVEL_LOCK
typedef enum camera_metadata_enum_android_black_level_lock {
diff --git a/camera/src/camera_metadata_asserts.cpp b/camera/src/camera_metadata_asserts.cpp
index 4e3748f0..d1fd162b 100644
--- a/camera/src/camera_metadata_asserts.cpp
+++ b/camera/src/camera_metadata_asserts.cpp
@@ -50,6 +50,7 @@
#include <aidl/android/hardware/camera/metadata/ControlAutoframing.h>
#include <aidl/android/hardware/camera/metadata/ControlAutoframingAvailable.h>
#include <aidl/android/hardware/camera/metadata/ControlAutoframingState.h>
+#include <aidl/android/hardware/camera/metadata/ControlLowLightBoostState.h>
#include <aidl/android/hardware/camera/metadata/DemosaicMode.h>
#include <aidl/android/hardware/camera/metadata/EdgeMode.h>
#include <aidl/android/hardware/camera/metadata/FlashMode.h>
@@ -380,6 +381,10 @@ static_assert(static_cast<int>(ANDROID_CONTROL_AUTOFRAMING_AVAILABLE)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_CONTROL_AUTOFRAMING_AVAILABLE));
static_assert(static_cast<int>(ANDROID_CONTROL_AUTOFRAMING_STATE)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_CONTROL_AUTOFRAMING_STATE));
+static_assert(static_cast<int>(ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE));
+static_assert(static_cast<int>(ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE));
static_assert(static_cast<int>(ANDROID_DEMOSAIC_MODE)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_DEMOSAIC_MODE));
static_assert(static_cast<int>(ANDROID_EDGE_MODE)
@@ -400,6 +405,16 @@ static_assert(static_cast<int>(ANDROID_FLASH_MAX_ENERGY)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_FLASH_MAX_ENERGY));
static_assert(static_cast<int>(ANDROID_FLASH_STATE)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_FLASH_STATE));
+static_assert(static_cast<int>(ANDROID_FLASH_STRENGTH_LEVEL)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_FLASH_STRENGTH_LEVEL));
+static_assert(static_cast<int>(ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL));
+static_assert(static_cast<int>(ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL));
+static_assert(static_cast<int>(ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL));
+static_assert(static_cast<int>(ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL));
static_assert(static_cast<int>(ANDROID_FLASH_INFO_AVAILABLE)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_FLASH_INFO_AVAILABLE));
static_assert(static_cast<int>(ANDROID_FLASH_INFO_CHARGE_DURATION)
@@ -740,6 +755,10 @@ static_assert(static_cast<int>(ANDROID_STATISTICS_OIS_X_SHIFTS)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_STATISTICS_OIS_X_SHIFTS));
static_assert(static_cast<int>(ANDROID_STATISTICS_OIS_Y_SHIFTS)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_STATISTICS_OIS_Y_SHIFTS));
+static_assert(static_cast<int>(ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS));
+static_assert(static_cast<int>(ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES));
static_assert(static_cast<int>(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES));
static_assert(static_cast<int>(ANDROID_STATISTICS_INFO_HISTOGRAM_BUCKET_COUNT)
@@ -832,6 +851,8 @@ static_assert(static_cast<int>(ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE));
static_assert(static_cast<int>(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID));
+static_assert(static_cast<int>(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION)
+ == static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION));
static_assert(static_cast<int>(ANDROID_DISTORTION_CORRECTION_MODE)
== static_cast<int>(::aidl::android::hardware::camera::metadata::CameraMetadataTag::ANDROID_DISTORTION_CORRECTION_MODE));
static_assert(static_cast<int>(ANDROID_DISTORTION_CORRECTION_AVAILABLE_MODES)
@@ -909,6 +930,8 @@ static_assert(static_cast<int32_t>(ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE)
== static_cast<int32_t>(::aidl::android::hardware::camera::metadata::ControlAeMode::ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE));
static_assert(static_cast<int32_t>(ANDROID_CONTROL_AE_MODE_ON_EXTERNAL_FLASH)
== static_cast<int32_t>(::aidl::android::hardware::camera::metadata::ControlAeMode::ANDROID_CONTROL_AE_MODE_ON_EXTERNAL_FLASH));
+static_assert(static_cast<int32_t>(ANDROID_CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY)
+ == static_cast<int32_t>(::aidl::android::hardware::camera::metadata::ControlAeMode::ANDROID_CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY));
static_assert(static_cast<int32_t>(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE)
== static_cast<int32_t>(::aidl::android::hardware::camera::metadata::ControlAePrecaptureTrigger::ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE));
@@ -1152,6 +1175,11 @@ static_assert(static_cast<int32_t>(ANDROID_CONTROL_AUTOFRAMING_STATE_FRAMING)
static_assert(static_cast<int32_t>(ANDROID_CONTROL_AUTOFRAMING_STATE_CONVERGED)
== static_cast<int32_t>(::aidl::android::hardware::camera::metadata::ControlAutoframingState::ANDROID_CONTROL_AUTOFRAMING_STATE_CONVERGED));
+static_assert(static_cast<int32_t>(ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE)
+ == static_cast<int32_t>(::aidl::android::hardware::camera::metadata::ControlLowLightBoostState::ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE));
+static_assert(static_cast<int32_t>(ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_ACTIVE)
+ == static_cast<int32_t>(::aidl::android::hardware::camera::metadata::ControlLowLightBoostState::ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_ACTIVE));
+
static_assert(static_cast<int32_t>(ANDROID_DEMOSAIC_MODE_FAST)
== static_cast<int32_t>(::aidl::android::hardware::camera::metadata::DemosaicMode::ANDROID_DEMOSAIC_MODE_FAST));
static_assert(static_cast<int32_t>(ANDROID_DEMOSAIC_MODE_HIGH_QUALITY)
@@ -1599,6 +1627,8 @@ static_assert(static_cast<int32_t>(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNA
static_assert(static_cast<int32_t>(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5)
== static_cast<int32_t>(::aidl::android::hardware::camera::metadata::InfoSupportedBufferManagementVersion::ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_AIDL_DEVICE));
+static_assert(static_cast<int32_t>(ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE)
+ == static_cast<int32_t>(::aidl::android::hardware::camera::metadata::InfoSupportedBufferManagementVersion::ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE));
static_assert(static_cast<int32_t>(ANDROID_BLACK_LEVEL_LOCK_OFF)
== static_cast<int32_t>(::aidl::android::hardware::camera::metadata::BlackLevelLock::ANDROID_BLACK_LEVEL_LOCK_OFF));
diff --git a/camera/src/camera_metadata_tag_info.c b/camera/src/camera_metadata_tag_info.c
index 1dac402a..0b93365a 100644
--- a/camera/src/camera_metadata_tag_info.c
+++ b/camera/src/camera_metadata_tag_info.c
@@ -279,6 +279,11 @@ static tag_info_t android_control[ANDROID_CONTROL_END -
{ "autoframingAvailable", TYPE_BYTE },
[ ANDROID_CONTROL_AUTOFRAMING_STATE - ANDROID_CONTROL_START ] =
{ "autoframingState", TYPE_BYTE },
+ [ ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE - ANDROID_CONTROL_START ] =
+ { "lowLightBoostInfoLuminanceRange",
+ TYPE_FLOAT },
+ [ ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE - ANDROID_CONTROL_START ] =
+ { "lowLightBoostState", TYPE_BYTE },
};
static tag_info_t android_demosaic[ANDROID_DEMOSAIC_END -
@@ -311,6 +316,16 @@ static tag_info_t android_flash[ANDROID_FLASH_END -
{ "maxEnergy", TYPE_BYTE },
[ ANDROID_FLASH_STATE - ANDROID_FLASH_START ] =
{ "state", TYPE_BYTE },
+ [ ANDROID_FLASH_STRENGTH_LEVEL - ANDROID_FLASH_START ] =
+ { "strengthLevel", TYPE_INT32 },
+ [ ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL - ANDROID_FLASH_START ] =
+ { "singleStrengthMaxLevel", TYPE_INT32 },
+ [ ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL - ANDROID_FLASH_START ] =
+ { "singleStrengthDefaultLevel", TYPE_INT32 },
+ [ ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL - ANDROID_FLASH_START ] =
+ { "torchStrengthMaxLevel", TYPE_INT32 },
+ [ ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL - ANDROID_FLASH_START ] =
+ { "torchStrengthDefaultLevel", TYPE_INT32 },
};
static tag_info_t android_flash_info[ANDROID_FLASH_INFO_END -
@@ -736,6 +751,10 @@ static tag_info_t android_statistics[ANDROID_STATISTICS_END -
{ "oisXShifts", TYPE_FLOAT },
[ ANDROID_STATISTICS_OIS_Y_SHIFTS - ANDROID_STATISTICS_START ] =
{ "oisYShifts", TYPE_FLOAT },
+ [ ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS - ANDROID_STATISTICS_START ] =
+ { "lensIntrinsicTimestamps", TYPE_INT64 },
+ [ ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES - ANDROID_STATISTICS_START ] =
+ { "lensIntrinsicSamples", TYPE_FLOAT },
};
static tag_info_t android_statistics_info[ANDROID_STATISTICS_INFO_END -
@@ -799,6 +818,9 @@ static tag_info_t android_info[ANDROID_INFO_END -
TYPE_BYTE },
[ ANDROID_INFO_DEVICE_STATE_ORIENTATIONS - ANDROID_INFO_START ] =
{ "deviceStateOrientations", TYPE_INT64 },
+ [ ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION - ANDROID_INFO_START ] =
+ { "sessionConfigurationQueryVersion",
+ TYPE_INT32 },
};
static tag_info_t android_black_level[ANDROID_BLACK_LEVEL_END -
@@ -877,6 +899,9 @@ static tag_info_t android_logical_multi_camera[ANDROID_LOGICAL_MULTI_CAMERA_END
{ "sensorSyncType", TYPE_BYTE },
[ ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID - ANDROID_LOGICAL_MULTI_CAMERA_START ] =
{ "activePhysicalId", TYPE_BYTE },
+ [ ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION - ANDROID_LOGICAL_MULTI_CAMERA_START ] =
+ { "activePhysicalSensorCropRegion",
+ TYPE_INT32 },
};
static tag_info_t android_distortion_correction[ANDROID_DISTORTION_CORRECTION_END -
@@ -1139,6 +1164,10 @@ int camera_metadata_enum_snprint(uint32_t tag,
msg = "ON_EXTERNAL_FLASH";
ret = 0;
break;
+ case ANDROID_CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY:
+ msg = "ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY";
+ ret = 0;
+ break;
default:
msg = "error: enum value out of range";
}
@@ -1870,6 +1899,24 @@ int camera_metadata_enum_snprint(uint32_t tag,
}
break;
}
+ case ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE: {
+ break;
+ }
+ case ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE: {
+ switch (value) {
+ case ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE:
+ msg = "INACTIVE";
+ ret = 0;
+ break;
+ case ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_ACTIVE:
+ msg = "ACTIVE";
+ ret = 0;
+ break;
+ default:
+ msg = "error: enum value out of range";
+ }
+ break;
+ }
case ANDROID_DEMOSAIC_MODE: {
switch (value) {
@@ -1975,6 +2022,21 @@ int camera_metadata_enum_snprint(uint32_t tag,
}
break;
}
+ case ANDROID_FLASH_STRENGTH_LEVEL: {
+ break;
+ }
+ case ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL: {
+ break;
+ }
+ case ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL: {
+ break;
+ }
+ case ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL: {
+ break;
+ }
+ case ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL: {
+ break;
+ }
case ANDROID_FLASH_INFO_AVAILABLE: {
switch (value) {
@@ -3368,6 +3430,12 @@ int camera_metadata_enum_snprint(uint32_t tag,
case ANDROID_STATISTICS_OIS_Y_SHIFTS: {
break;
}
+ case ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS: {
+ break;
+ }
+ case ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES: {
+ break;
+ }
case ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES: {
break;
@@ -3521,6 +3589,10 @@ int camera_metadata_enum_snprint(uint32_t tag,
msg = "HIDL_DEVICE_3_5";
ret = 0;
break;
+ case ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE:
+ msg = "SESSION_CONFIGURABLE";
+ ret = 0;
+ break;
default:
msg = "error: enum value out of range";
}
@@ -3529,6 +3601,21 @@ int camera_metadata_enum_snprint(uint32_t tag,
case ANDROID_INFO_DEVICE_STATE_ORIENTATIONS: {
break;
}
+ case ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION: {
+ switch (value) {
+ case ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION_UPSIDE_DOWN_CAKE:
+ msg = "UPSIDE_DOWN_CAKE";
+ ret = 0;
+ break;
+ case ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION_VANILLA_ICE_CREAM:
+ msg = "VANILLA_ICE_CREAM";
+ ret = 0;
+ break;
+ default:
+ msg = "error: enum value out of range";
+ }
+ break;
+ }
case ANDROID_BLACK_LEVEL_LOCK: {
switch (value) {
@@ -3711,6 +3798,9 @@ int camera_metadata_enum_snprint(uint32_t tag,
case ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID: {
break;
}
+ case ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION: {
+ break;
+ }
case ANDROID_DISTORTION_CORRECTION_MODE: {
switch (value) {
@@ -4121,6 +4211,12 @@ int camera_metadata_enum_value(uint32_t tag,
ret = 0;
break;
}
+ enumName = "ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY";
+ if (strncmp(name, enumName, size) == 0) {
+ *value = ANDROID_CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY;
+ ret = 0;
+ break;
+ }
break;
}
case ANDROID_CONTROL_AE_REGIONS: {
@@ -4981,6 +5077,24 @@ int camera_metadata_enum_value(uint32_t tag,
}
break;
}
+ case ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE: {
+ break;
+ }
+ case ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE: {
+ enumName = "INACTIVE";
+ if (strncmp(name, enumName, size) == 0) {
+ *value = ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE;
+ ret = 0;
+ break;
+ }
+ enumName = "ACTIVE";
+ if (strncmp(name, enumName, size) == 0) {
+ *value = ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE_ACTIVE;
+ ret = 0;
+ break;
+ }
+ break;
+ }
case ANDROID_DEMOSAIC_MODE: {
enumName = "FAST";
@@ -5098,6 +5212,21 @@ int camera_metadata_enum_value(uint32_t tag,
}
break;
}
+ case ANDROID_FLASH_STRENGTH_LEVEL: {
+ break;
+ }
+ case ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL: {
+ break;
+ }
+ case ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL: {
+ break;
+ }
+ case ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL: {
+ break;
+ }
+ case ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL: {
+ break;
+ }
case ANDROID_FLASH_INFO_AVAILABLE: {
enumName = "FALSE";
@@ -6683,6 +6812,12 @@ int camera_metadata_enum_value(uint32_t tag,
case ANDROID_STATISTICS_OIS_Y_SHIFTS: {
break;
}
+ case ANDROID_STATISTICS_LENS_INTRINSIC_TIMESTAMPS: {
+ break;
+ }
+ case ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES: {
+ break;
+ }
case ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES: {
break;
@@ -6847,11 +6982,32 @@ int camera_metadata_enum_value(uint32_t tag,
ret = 0;
break;
}
+ enumName = "SESSION_CONFIGURABLE";
+ if (strncmp(name, enumName, size) == 0) {
+ *value = ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_SESSION_CONFIGURABLE;
+ ret = 0;
+ break;
+ }
break;
}
case ANDROID_INFO_DEVICE_STATE_ORIENTATIONS: {
break;
}
+ case ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION: {
+ enumName = "UPSIDE_DOWN_CAKE";
+ if (strncmp(name, enumName, size) == 0) {
+ *value = ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION_UPSIDE_DOWN_CAKE;
+ ret = 0;
+ break;
+ }
+ enumName = "VANILLA_ICE_CREAM";
+ if (strncmp(name, enumName, size) == 0) {
+ *value = ANDROID_INFO_SESSION_CONFIGURATION_QUERY_VERSION_VANILLA_ICE_CREAM;
+ ret = 0;
+ break;
+ }
+ break;
+ }
case ANDROID_BLACK_LEVEL_LOCK: {
enumName = "OFF";
@@ -7034,6 +7190,9 @@ int camera_metadata_enum_value(uint32_t tag,
case ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID: {
break;
}
+ case ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION: {
+ break;
+ }
case ANDROID_DISTORTION_CORRECTION_MODE: {
enumName = "OFF";
@@ -7342,4 +7501,4 @@ int camera_metadata_enum_value(uint32_t tag,
}
-#define CAMERA_METADATA_ENUM_STRING_MAX_SIZE 29
+#define CAMERA_METADATA_ENUM_STRING_MAX_SIZE 39