diff options
19 files changed, 639 insertions, 374 deletions
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 2684f048f8..2ae61b9603 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -612,7 +612,8 @@ void ServiceManager::binderDied(const wp<IBinder>& who) { } void ServiceManager::tryStartService(const std::string& name) { - ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service", + ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service. (if it's not " + "configured to be a lazy service, it may be stuck starting or still starting).", name.c_str()); std::thread([=] { diff --git a/data/etc/android.software.opengles.deqp.level-2023-03-01.xml b/data/etc/android.software.opengles.deqp.level-2023-03-01.xml new file mode 100644 index 0000000000..d0b594c73d --- /dev/null +++ b/data/etc/android.software.opengles.deqp.level-2023-03-01.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature indicating that the device passes OpenGL ES + dEQP tests associated with date 2023-03-01 (0x07E70301). --> +<permissions> + <feature name="android.software.opengles.deqp.level" version="132580097" /> +</permissions> diff --git a/data/etc/android.software.vulkan.deqp.level-2023-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2023-03-01.xml new file mode 100644 index 0000000000..6ae248ac3c --- /dev/null +++ b/data/etc/android.software.vulkan.deqp.level-2023-03-01.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- This is the standard feature indicating that the device passes Vulkan dEQP + tests associated with date 2023-03-01 (0x07E70301). --> +<permissions> + <feature name="android.software.vulkan.deqp.level" version="132580097" /> +</permissions> diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs index 21271d2484..c5c7719df2 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs +++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs @@ -22,7 +22,7 @@ extern crate libfuzzer_sys; mod read_utils; -use crate::read_utils::get_read_funcs; +use crate::read_utils::READ_FUNCS; use binder::binder_impl::{ Binder, BorrowedParcel, IBinderInternal, Parcel, Stability, TransactionCode, }; @@ -34,18 +34,18 @@ use binder_random_parcel_rs::create_random_parcel; use libfuzzer_sys::arbitrary::Arbitrary; #[derive(Arbitrary, Debug)] -enum ReadOperations { +enum ReadOperation { SetDataPosition { pos: i32 }, GetDataSize, ReadParcelableHolder { is_vintf: bool }, - ReadBasicTypes { indexes: Vec<usize> }, + ReadBasicTypes { instructions: Vec<usize> }, } #[derive(Arbitrary, Debug)] -enum Operations<'a> { +enum Operation<'a> { Transact { code: u32, flag: u32, data: &'a [u8] }, Append { start: i32, len: i32, data1: &'a [u8], data2: &'a [u8], append_all: bool }, - Read { indexes: Vec<ReadOperations>, data: &'a [u8] }, + Read { read_operations: Vec<ReadOperation>, data: &'a [u8] }, } /// Interface to fuzz transact with random parcel @@ -102,13 +102,12 @@ fn do_append_fuzz(start: i32, len: i32, data1: &[u8], data2: &[u8], append_all: }; } -fn do_read_fuzz(read_operations: Vec<ReadOperations>, data: &[u8]) { - let read_funcs = get_read_funcs(); +fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) { let parcel = create_random_parcel(data); for operation in read_operations { match operation { - ReadOperations::SetDataPosition { pos } => { + ReadOperation::SetDataPosition { pos } => { unsafe { // Safety: Safe if pos is less than current size of the parcel. // It relies on C++ code for bound checks @@ -119,12 +118,12 @@ fn do_read_fuzz(read_operations: Vec<ReadOperations>, data: &[u8]) { } } - ReadOperations::GetDataSize => { + ReadOperation::GetDataSize => { let data_size = parcel.get_data_size(); println!("data size from parcel: {:?}", data_size); } - ReadOperations::ReadParcelableHolder { is_vintf } => { + ReadOperation::ReadParcelableHolder { is_vintf } => { let stability = if is_vintf { Stability::Vintf } else { Stability::Local }; let mut holder: ParcelableHolder = ParcelableHolder::new(stability); match holder.read_from_parcel(parcel.borrowed_ref()) { @@ -135,30 +134,28 @@ fn do_read_fuzz(read_operations: Vec<ReadOperations>, data: &[u8]) { } } - ReadOperations::ReadBasicTypes { indexes } => { - for index in indexes.iter() { - let read_index = index % read_funcs.len(); - read_funcs[read_index](parcel.borrowed_ref()); + ReadOperation::ReadBasicTypes { instructions } => { + for instruction in instructions.iter() { + let read_index = instruction % READ_FUNCS.len(); + READ_FUNCS[read_index](parcel.borrowed_ref()); } } } } } -fuzz_target!(|operations: Vec<Operations>| { - for operation in operations { - match operation { - Operations::Transact { code, flag, data } => { - do_transact(code, data, flag); - } +fuzz_target!(|operation: Operation| { + match operation { + Operation::Transact { code, flag, data } => { + do_transact(code, data, flag); + } - Operations::Append { start, len, data1, data2, append_all } => { - do_append_fuzz(start, len, data1, data2, append_all); - } + Operation::Append { start, len, data1, data2, append_all } => { + do_append_fuzz(start, len, data1, data2, append_all); + } - Operations::Read { indexes, data } => { - do_read_fuzz(indexes, data); - } + Operation::Read { read_operations, data } => { + do_read_fuzz(read_operations, data); } } }); diff --git a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs index 9b06013332..d2bfde1022 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs +++ b/libs/binder/rust/tests/parcel_fuzzer/read_utils.rs @@ -22,7 +22,7 @@ use binderReadParcelIface::aidl::SingleDataParcelable::SingleDataParcelable; macro_rules! read_parcel_interface { ($data_type:ty) => { - |parcel| { + |parcel: &BorrowedParcel<'_>| { let _res = parcel.read::<$data_type>(); } }; @@ -57,81 +57,77 @@ impl binder::Parcelable for SomeParcelable { binder::impl_deserialize_for_parcelable!(SomeParcelable); -pub fn get_read_funcs() -> Vec<Box<dyn Fn(&BorrowedParcel<'_>)>> { - let read_funcs: Vec<Box<dyn Fn(&BorrowedParcel<'_>)>> = vec![ - //read basic types - Box::new(read_parcel_interface!(bool)), - Box::new(read_parcel_interface!(i8)), - Box::new(read_parcel_interface!(i32)), - Box::new(read_parcel_interface!(i64)), - Box::new(read_parcel_interface!(f32)), - Box::new(read_parcel_interface!(f64)), - Box::new(read_parcel_interface!(u16)), - Box::new(read_parcel_interface!(u32)), - Box::new(read_parcel_interface!(u64)), - Box::new(read_parcel_interface!(String)), - //read vec of basic types - Box::new(read_parcel_interface!(Vec<i8>)), - Box::new(read_parcel_interface!(Vec<i32>)), - Box::new(read_parcel_interface!(Vec<i64>)), - Box::new(read_parcel_interface!(Vec<f32>)), - Box::new(read_parcel_interface!(Vec<f64>)), - Box::new(read_parcel_interface!(Vec<u16>)), - Box::new(read_parcel_interface!(Vec<u32>)), - Box::new(read_parcel_interface!(Vec<u64>)), - Box::new(read_parcel_interface!(Vec<String>)), - Box::new(read_parcel_interface!(Option<Vec<i8>>)), - Box::new(read_parcel_interface!(Option<Vec<i32>>)), - Box::new(read_parcel_interface!(Option<Vec<i64>>)), - Box::new(read_parcel_interface!(Option<Vec<f32>>)), - Box::new(read_parcel_interface!(Option<Vec<f64>>)), - Box::new(read_parcel_interface!(Option<Vec<u16>>)), - Box::new(read_parcel_interface!(Option<Vec<u32>>)), - Box::new(read_parcel_interface!(Option<Vec<u64>>)), - Box::new(read_parcel_interface!(Option<Vec<String>>)), - Box::new(read_parcel_interface!(ParcelFileDescriptor)), - Box::new(read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>)), - Box::new(read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>)), - Box::new(read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>)), - Box::new(read_parcel_interface!(SpIBinder)), - Box::new(read_parcel_interface!(Vec<Option<SpIBinder>>)), - Box::new(read_parcel_interface!(Option<Vec<SpIBinder>>)), - Box::new(read_parcel_interface!(Option<Vec<Option<SpIBinder>>>)), - Box::new(read_parcel_interface!(SomeParcelable)), - Box::new(read_parcel_interface!(Vec<Option<SomeParcelable>>)), - Box::new(read_parcel_interface!(Option<Vec<SomeParcelable>>)), - Box::new(read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>)), - // Fuzz read_from_parcel for AIDL generated parcelables - Box::new(|parcel| { - let mut empty_parcelable: EmptyParcelable = EmptyParcelable::default(); - match empty_parcelable.read_from_parcel(parcel) { - Ok(result) => result, - Err(e) => { - println!("EmptyParcelable: error occurred while reading from a parcel: {:?}", e) - } +pub const READ_FUNCS: &[fn(&BorrowedParcel<'_>)] = &[ + //read basic types + read_parcel_interface!(bool), + read_parcel_interface!(i8), + read_parcel_interface!(i32), + read_parcel_interface!(i64), + read_parcel_interface!(f32), + read_parcel_interface!(f64), + read_parcel_interface!(u16), + read_parcel_interface!(u32), + read_parcel_interface!(u64), + read_parcel_interface!(String), + //read vec of basic types + read_parcel_interface!(Vec<i8>), + read_parcel_interface!(Vec<i32>), + read_parcel_interface!(Vec<i64>), + read_parcel_interface!(Vec<f32>), + read_parcel_interface!(Vec<f64>), + read_parcel_interface!(Vec<u16>), + read_parcel_interface!(Vec<u32>), + read_parcel_interface!(Vec<u64>), + read_parcel_interface!(Vec<String>), + read_parcel_interface!(Option<Vec<i8>>), + read_parcel_interface!(Option<Vec<i32>>), + read_parcel_interface!(Option<Vec<i64>>), + read_parcel_interface!(Option<Vec<f32>>), + read_parcel_interface!(Option<Vec<f64>>), + read_parcel_interface!(Option<Vec<u16>>), + read_parcel_interface!(Option<Vec<u32>>), + read_parcel_interface!(Option<Vec<u64>>), + read_parcel_interface!(Option<Vec<String>>), + read_parcel_interface!(ParcelFileDescriptor), + read_parcel_interface!(Vec<Option<ParcelFileDescriptor>>), + read_parcel_interface!(Option<Vec<ParcelFileDescriptor>>), + read_parcel_interface!(Option<Vec<Option<ParcelFileDescriptor>>>), + read_parcel_interface!(SpIBinder), + read_parcel_interface!(Vec<Option<SpIBinder>>), + read_parcel_interface!(Option<Vec<SpIBinder>>), + read_parcel_interface!(Option<Vec<Option<SpIBinder>>>), + read_parcel_interface!(SomeParcelable), + read_parcel_interface!(Vec<Option<SomeParcelable>>), + read_parcel_interface!(Option<Vec<SomeParcelable>>), + read_parcel_interface!(Option<Vec<Option<SomeParcelable>>>), + // Fuzz read_from_parcel for AIDL generated parcelables + |parcel| { + let mut empty_parcelable: EmptyParcelable = EmptyParcelable::default(); + match empty_parcelable.read_from_parcel(parcel) { + Ok(result) => result, + Err(e) => { + println!("EmptyParcelable: error occurred while reading from a parcel: {:?}", e) } - }), - Box::new(|parcel| { - let mut single_parcelable: SingleDataParcelable = SingleDataParcelable::default(); - match single_parcelable.read_from_parcel(parcel) { - Ok(result) => result, - Err(e) => println!( - "SingleDataParcelable: error occurred while reading from a parcel: {:?}", - e - ), - } - }), - Box::new(|parcel| { - let mut generic_parcelable: GenericDataParcelable = GenericDataParcelable::default(); - match generic_parcelable.read_from_parcel(parcel) { - Ok(result) => result, - Err(e) => println!( - "GenericDataParcelable: error occurred while reading from a parcel: {:?}", - e - ), - } - }), - ]; - - read_funcs -} + } + }, + |parcel| { + let mut single_parcelable: SingleDataParcelable = SingleDataParcelable::default(); + match single_parcelable.read_from_parcel(parcel) { + Ok(result) => result, + Err(e) => println!( + "SingleDataParcelable: error occurred while reading from a parcel: {:?}", + e + ), + } + }, + |parcel| { + let mut generic_parcelable: GenericDataParcelable = GenericDataParcelable::default(); + match generic_parcelable.read_from_parcel(parcel) { + Ok(result) => result, + Err(e) => println!( + "GenericDataParcelable: error occurred while reading from a parcel: {:?}", + e + ), + } + }, +]; diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h index 8e36250e60..b2ca481aa7 100644 --- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h @@ -176,11 +176,13 @@ private: * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format * @param uncompressed_p010_image uncompressed HDR image in P010 color format * @param dest recovery map; caller responsible for memory of data + * @param hdr_ratio HDR ratio will be updated in this method * @return NO_ERROR if calculation succeeds, error code if error occurs. */ status_t generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr dest); + jr_uncompressed_ptr dest, + float &hdr_ratio); /* * This method is called in the decoding pipeline. It will take the uncompressed (decoded) @@ -213,11 +215,13 @@ private: * * @param compressed_jpeg_image compressed 8-bit JPEG image * @param compress_recovery_map compressed recover map + * @param hdr_ratio HDR ratio * @param dest compressed JPEGR image * @return NO_ERROR if calculation succeeds, error code if error occurs. */ status_t appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image, jr_compressed_ptr compressed_recovery_map, + float hdr_ratio, jr_compressed_ptr dest); /* diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp index d46025c441..bd16a68b0d 100644 --- a/libs/jpegrecoverymap/recoverymap.cpp +++ b/libs/jpegrecoverymap/recoverymap.cpp @@ -20,11 +20,11 @@ // TODO: handle PQ encode/decode (currently only HLG) #include <jpegrecoverymap/recoverymap.h> - #include <jpegrecoverymap/jpegencoder.h> #include <jpegrecoverymap/jpegdecoder.h> #include <jpegrecoverymap/recoverymapmath.h> +#include <image_io/jpeg/jpeg_marker.h> #include <image_io/xml/xml_writer.h> #include <memory> @@ -60,6 +60,25 @@ string Name(const string &prefix, const string &suffix) { return ss.str(); } +/* + * Helper function used for writing data to destination. + * + * @param destination destination of the data to be written. + * @param source source of data being written. + * @param length length of the data to be written. + * @param position cursor in desitination where the data is to be written. + * @return status of succeed or error code. + */ +status_t Write(jr_compressed_ptr destination, const void* source, size_t length, int &position) { + if (position + length > destination->length) { + return ERROR_JPEGR_BUFFER_TOO_SMALL; + } + + memcpy((uint8_t*)destination->data + sizeof(uint8_t) * position, source, length); + position += length; + return NO_ERROR; +} + status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jr_uncompressed_ptr uncompressed_yuv_420_image, jr_compressed_ptr dest, @@ -81,7 +100,9 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, } jpegr_uncompressed_struct map; - JPEGR_CHECK(generateRecoveryMap(uncompressed_yuv_420_image, uncompressed_p010_image, &map)); + float hdr_ratio = 0.0f; + JPEGR_CHECK(generateRecoveryMap( + uncompressed_yuv_420_image, uncompressed_p010_image, &map, hdr_ratio)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); @@ -102,7 +123,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpeg.data = jpeg_encoder.getCompressedImagePtr(); jpeg.length = jpeg_encoder.getCompressedImageSize(); - JPEGR_CHECK(appendRecoveryMap(&jpeg, &compressed_map, dest)); + JPEGR_CHECK(appendRecoveryMap(&jpeg, &compressed_map, hdr_ratio, dest)); return NO_ERROR; } @@ -124,7 +145,9 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, } jpegr_uncompressed_struct map; - JPEGR_CHECK(generateRecoveryMap(uncompressed_yuv_420_image, uncompressed_p010_image, &map)); + float hdr_ratio = 0.0f; + JPEGR_CHECK(generateRecoveryMap( + uncompressed_yuv_420_image, uncompressed_p010_image, &map, hdr_ratio)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); @@ -134,7 +157,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, compressed_map.data = compressed_map_data.get(); JPEGR_CHECK(compressRecoveryMap(&map, &compressed_map)); - JPEGR_CHECK(appendRecoveryMap(compressed_jpeg_image, &compressed_map, dest)); + JPEGR_CHECK(appendRecoveryMap(compressed_jpeg_image, &compressed_map, hdr_ratio, dest)); return NO_ERROR; } @@ -163,7 +186,9 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, } jpegr_uncompressed_struct map; - JPEGR_CHECK(generateRecoveryMap(&uncompressed_yuv_420_image, uncompressed_p010_image, &map)); + float hdr_ratio = 0.0f; + JPEGR_CHECK(generateRecoveryMap( + &uncompressed_yuv_420_image, uncompressed_p010_image, &map, hdr_ratio)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); @@ -173,7 +198,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, compressed_map.data = compressed_map_data.get(); JPEGR_CHECK(compressRecoveryMap(&map, &compressed_map)); - JPEGR_CHECK(appendRecoveryMap(compressed_jpeg_image, &compressed_map, dest)); + JPEGR_CHECK(appendRecoveryMap(compressed_jpeg_image, &compressed_map, hdr_ratio, dest)); return NO_ERROR; } @@ -252,7 +277,8 @@ status_t RecoveryMap::compressRecoveryMap(jr_uncompressed_ptr uncompressed_recov status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr dest) { + jr_uncompressed_ptr dest, + float &hdr_ratio) { if (uncompressed_yuv_420_image == nullptr || uncompressed_p010_image == nullptr || dest == nullptr) { @@ -287,7 +313,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 } float y_hdr_max_nits = hlgInvOetf(yp_hdr_max); - float hdr_ratio = y_hdr_max_nits / kSdrWhiteNits; + hdr_ratio = y_hdr_max_nits / kSdrWhiteNits; for (size_t y = 0; y < map_height; ++y) { for (size_t x = 0; x < map_width; ++x) { @@ -364,6 +390,7 @@ status_t RecoveryMap::extractRecoveryMap(jr_compressed_ptr compressed_jpegr_imag status_t RecoveryMap::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image, jr_compressed_ptr compressed_recovery_map, + float hdr_ratio, jr_compressed_ptr dest) { if (compressed_jpeg_image == nullptr || compressed_recovery_map == nullptr @@ -371,7 +398,39 @@ status_t RecoveryMap::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image, return ERROR_JPEGR_INVALID_NULL_PTR; } - // TBD + string xmp = generateXmp(compressed_recovery_map->length, hdr_ratio); + string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; + + // 2 bytes: APP1 sign (ff e1) + // 29 bytes: length of name space "http://ns.adobe.com/xap/1.0/\0" + // x bytes: length of xmp packet + int length = 2 + nameSpace.size() + xmp.size(); + uint8_t lengthH = ((length >> 8) & 0xff); + uint8_t lengthL = (length & 0xff); + + int pos = 0; + + // JPEG/R structure: + // SOI (ff d8) + // APP1 (ff e1) + // 2 bytes of length (2 + 29 + length of xmp packet) + // name space ("http://ns.adobe.com/xap/1.0/\0") + // xmp + // primary image (without the first two bytes, the SOI sign) + // secondary image (the recovery map) + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kSOI, 1, pos)); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP1, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); + JPEGR_CHECK(Write(dest, (void*)nameSpace.c_str(), nameSpace.size(), pos)); + JPEGR_CHECK(Write(dest, (void*)xmp.c_str(), xmp.size(), pos)); + JPEGR_CHECK(Write(dest, + (uint8_t*)compressed_jpeg_image->data + 2, compressed_jpeg_image->length - 2, pos)); + JPEGR_CHECK(Write(dest, compressed_recovery_map->data, compressed_recovery_map->length, pos)); + dest->length = pos; + return NO_ERROR; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 9a6ebaaed2..a47f40ccbb 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2104,7 +2104,7 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked( const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE); if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; - if (switchedDevice && tempTouchState.down && !down && !isHoverAction) { + if (switchedDevice && tempTouchState.isDown() && !down && !isHoverAction) { ALOGI("Dropping event because a pointer for a different device is already down " "in display %" PRId32, displayId); @@ -2113,7 +2113,6 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked( return touchedWindows; // wrong device } tempTouchState.reset(); - tempTouchState.down = down; tempTouchState.deviceId = entry.deviceId; tempTouchState.source = entry.source; tempTouchState.displayId = displayId; @@ -2234,7 +2233,7 @@ std::vector<TouchedWindow> InputDispatcher::findTouchedWindowTargetsLocked( /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ // If the pointer is not currently down, then ignore the event. - if (!tempTouchState.down) { + if (!tempTouchState.isDown()) { if (DEBUG_FOCUS) { ALOGD("Dropping event because the pointer is not down or we previously " "dropped the pointer down event in display %" PRId32, @@ -2445,7 +2444,7 @@ Failed: if (isHoverAction) { // Started hovering, therefore no longer down. - if (oldState && oldState->down) { + if (oldState && oldState->isDown()) { if (DEBUG_FOCUS) { ALOGD("Conflicting pointer actions: Hover received while pointer was " "down."); @@ -2465,7 +2464,7 @@ Failed: tempTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { // First pointer went down. - if (oldState && oldState->down) { + if (oldState && oldState->isDown()) { if (DEBUG_FOCUS) { ALOGD("Conflicting pointer actions: Down received while already down."); } @@ -5326,9 +5325,8 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += StringPrintf(INDENT "TouchStatesByDisplay:\n"); for (const std::pair<int32_t, TouchState>& pair : mTouchStatesByDisplay) { const TouchState& state = pair.second; - dump += StringPrintf(INDENT2 "%d: down=%s, deviceId=%d, source=0x%08x\n", - state.displayId, toString(state.down), state.deviceId, - state.source); + dump += StringPrintf(INDENT2 "%d: deviceId=%d, source=0x%08x\n", state.displayId, + state.deviceId, state.source); if (!state.windows.empty()) { dump += INDENT3 "Windows:\n"; for (size_t i = 0; i < state.windows.size(); i++) { @@ -5688,7 +5686,7 @@ status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) { } auto [statePtr, windowPtr] = findTouchStateAndWindowLocked(token); - if (statePtr == nullptr || windowPtr == nullptr || !statePtr->down) { + if (statePtr == nullptr || windowPtr == nullptr || windowPtr->pointerIds.isEmpty()) { ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams." " Ignoring."); return BAD_VALUE; diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index a3f45cfce3..f5b7cb88d9 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -138,4 +138,9 @@ sp<WindowInfoHandle> TouchState::getWallpaperWindow() const { return nullptr; } +bool TouchState::isDown() const { + return std::any_of(windows.begin(), windows.end(), + [](const TouchedWindow& window) { return !window.pointerIds.isEmpty(); }); +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index f6e9fb69f8..ceeeb1eb3d 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -28,8 +28,6 @@ class WindowInfoHandle; namespace inputdispatcher { struct TouchState { - bool down = false; - // id of the device that is currently down, others are rejected int32_t deviceId = -1; // source of the device that is current down, others are rejected @@ -59,6 +57,8 @@ struct TouchState { sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const; bool isSlippery() const; sp<android::gui::WindowInfoHandle> getWallpaperWindow() const; + // Whether any of the windows are currently being touched + bool isDown() const; }; } // namespace inputdispatcher diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index a53fcd763d..24168a12a6 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -55,6 +55,7 @@ filegroup { "mapper/accumulator/CursorButtonAccumulator.cpp", "mapper/accumulator/CursorScrollAccumulator.cpp", "mapper/accumulator/HidUsageAccumulator.cpp", + "mapper/accumulator/MultiTouchMotionAccumulator.cpp", "mapper/accumulator/SingleTouchMotionAccumulator.cpp", "mapper/accumulator/TouchButtonAccumulator.cpp", ], diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index acba4f6513..8e757a5bf7 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -28,163 +28,6 @@ namespace android { // Maximum number of slots supported when using the slot-based Multitouch Protocol B. static constexpr size_t MAX_SLOTS = 32; -// --- MultiTouchMotionAccumulator --- - -MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() - : mCurrentSlot(-1), - mUsingSlotsProtocol(false), - mHaveStylus(false) {} - -void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, - bool usingSlotsProtocol) { - mUsingSlotsProtocol = usingSlotsProtocol; - mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); - mSlots = std::vector<Slot>(slotCount); - - mCurrentSlot = -1; - if (mUsingSlotsProtocol) { - // Query the driver for the current slot index and use it as the initial slot - // before we start reading events from the device. It is possible that the - // current slot index will not be the same as it was when the first event was - // written into the evdev buffer, which means the input mapper could start - // out of sync with the initial state of the events in the evdev buffer. - // In the extremely unlikely case that this happens, the data from - // two slots will be confused until the next ABS_MT_SLOT event is received. - // This can cause the touch point to "jump", but at least there will be - // no stuck touches. - int32_t initialSlot; - if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot); - status == OK) { - mCurrentSlot = initialSlot; - } else { - ALOGD("Could not retrieve current multi-touch slot index. status=%d", status); - } - } -} - -void MultiTouchMotionAccumulator::resetSlots() { - for (Slot& slot : mSlots) { - slot.clear(); - } - mCurrentSlot = -1; -} - -void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { - bool newSlot = false; - if (mUsingSlotsProtocol) { - if (rawEvent->code == ABS_MT_SLOT) { - mCurrentSlot = rawEvent->value; - newSlot = true; - } - } else if (mCurrentSlot < 0) { - mCurrentSlot = 0; - } - - if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) { - if (DEBUG_POINTERS) { - if (newSlot) { - ALOGW("MultiTouch device emitted invalid slot index %d but it " - "should be between 0 and %zd; ignoring this slot.", - mCurrentSlot, mSlots.size() - 1); - } - } - } else { - Slot& slot = mSlots[mCurrentSlot]; - // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of - // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while - // updating the slot. - if (!mUsingSlotsProtocol) { - slot.mInUse = true; - } - - switch (rawEvent->code) { - case ABS_MT_POSITION_X: - slot.mAbsMTPositionX = rawEvent->value; - warnIfNotInUse(*rawEvent, slot); - break; - case ABS_MT_POSITION_Y: - slot.mAbsMTPositionY = rawEvent->value; - warnIfNotInUse(*rawEvent, slot); - break; - case ABS_MT_TOUCH_MAJOR: - slot.mAbsMTTouchMajor = rawEvent->value; - break; - case ABS_MT_TOUCH_MINOR: - slot.mAbsMTTouchMinor = rawEvent->value; - slot.mHaveAbsMTTouchMinor = true; - break; - case ABS_MT_WIDTH_MAJOR: - slot.mAbsMTWidthMajor = rawEvent->value; - break; - case ABS_MT_WIDTH_MINOR: - slot.mAbsMTWidthMinor = rawEvent->value; - slot.mHaveAbsMTWidthMinor = true; - break; - case ABS_MT_ORIENTATION: - slot.mAbsMTOrientation = rawEvent->value; - break; - case ABS_MT_TRACKING_ID: - if (mUsingSlotsProtocol && rawEvent->value < 0) { - // The slot is no longer in use but it retains its previous contents, - // which may be reused for subsequent touches. - slot.mInUse = false; - } else { - slot.mInUse = true; - slot.mAbsMTTrackingId = rawEvent->value; - } - break; - case ABS_MT_PRESSURE: - slot.mAbsMTPressure = rawEvent->value; - break; - case ABS_MT_DISTANCE: - slot.mAbsMTDistance = rawEvent->value; - break; - case ABS_MT_TOOL_TYPE: - slot.mAbsMTToolType = rawEvent->value; - slot.mHaveAbsMTToolType = true; - break; - } - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { - // MultiTouch Sync: The driver has returned all data for *one* of the pointers. - mCurrentSlot += 1; - } -} - -void MultiTouchMotionAccumulator::finishSync() { - if (!mUsingSlotsProtocol) { - resetSlots(); - } -} - -bool MultiTouchMotionAccumulator::hasStylus() const { - return mHaveStylus; -} - -void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) { - if (!slot.mInUse) { - ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i", - event.code, event.value, mCurrentSlot, slot.mAbsMTTrackingId); - } -} - -// --- MultiTouchMotionAccumulator::Slot --- - -int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { - if (mHaveAbsMTToolType) { - switch (mAbsMTToolType) { - case MT_TOOL_FINGER: - return AMOTION_EVENT_TOOL_TYPE_FINGER; - case MT_TOOL_PEN: - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - case MT_TOOL_PALM: - return AMOTION_EVENT_TOOL_TYPE_PALM; - } - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - // --- MultiTouchInputMapper --- MultiTouchInputMapper::MultiTouchInputMapper(InputDeviceContext& deviceContext) diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h index 047e62de62..ddf9e80a6c 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h @@ -17,77 +17,10 @@ #pragma once #include "TouchInputMapper.h" +#include "accumulator/MultiTouchMotionAccumulator.h" namespace android { -/* Keeps track of the state of multi-touch protocol. */ -class MultiTouchMotionAccumulator { -public: - class Slot { - public: - inline bool isInUse() const { return mInUse; } - inline int32_t getX() const { return mAbsMTPositionX; } - inline int32_t getY() const { return mAbsMTPositionY; } - inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } - inline int32_t getTouchMinor() const { - return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; - } - inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } - inline int32_t getToolMinor() const { - return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; - } - inline int32_t getOrientation() const { return mAbsMTOrientation; } - inline int32_t getTrackingId() const { return mAbsMTTrackingId; } - inline int32_t getPressure() const { return mAbsMTPressure; } - inline int32_t getDistance() const { return mAbsMTDistance; } - inline int32_t getToolType() const; - - private: - friend class MultiTouchMotionAccumulator; - - bool mInUse = false; - bool mHaveAbsMTTouchMinor = false; - bool mHaveAbsMTWidthMinor = false; - bool mHaveAbsMTToolType = false; - - int32_t mAbsMTPositionX = 0; - int32_t mAbsMTPositionY = 0; - int32_t mAbsMTTouchMajor = 0; - int32_t mAbsMTTouchMinor = 0; - int32_t mAbsMTWidthMajor = 0; - int32_t mAbsMTWidthMinor = 0; - int32_t mAbsMTOrientation = 0; - int32_t mAbsMTTrackingId = -1; - int32_t mAbsMTPressure = 0; - int32_t mAbsMTDistance = 0; - int32_t mAbsMTToolType = 0; - - void clear() { *this = Slot(); } - }; - - MultiTouchMotionAccumulator(); - - void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); - void process(const RawEvent* rawEvent); - void finishSync(); - bool hasStylus() const; - - inline size_t getSlotCount() const { return mSlots.size(); } - inline const Slot& getSlot(size_t index) const { - LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); - return mSlots[index]; - } - -private: - int32_t mCurrentSlot; - std::vector<Slot> mSlots; - bool mUsingSlotsProtocol; - bool mHaveStylus; - - void resetSlots(); - void warnIfNotInUse(const RawEvent& event, const Slot& slot); -}; - class MultiTouchInputMapper : public TouchInputMapper { public: explicit MultiTouchInputMapper(InputDeviceContext& deviceContext); diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp new file mode 100644 index 0000000000..b0cef676fb --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// clang-format off +#include "../Macros.h" +// clang-format on +#include "MultiTouchMotionAccumulator.h" + +namespace android { + +// --- MultiTouchMotionAccumulator --- + +MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() + : mCurrentSlot(-1), mUsingSlotsProtocol(false), mHaveStylus(false) {} + +void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, + bool usingSlotsProtocol) { + mUsingSlotsProtocol = usingSlotsProtocol; + mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); + mSlots = std::vector<Slot>(slotCount); + + mCurrentSlot = -1; + if (mUsingSlotsProtocol) { + // Query the driver for the current slot index and use it as the initial slot before we + // start reading events from the device. It is possible that the current slot index will + // not be the same as it was when the first event was written into the evdev buffer, which + // means the input mapper could start out of sync with the initial state of the events in + // the evdev buffer. In the extremely unlikely case that this happens, the data from two + // slots will be confused until the next ABS_MT_SLOT event is received. This can cause the + // touch point to "jump", but at least there will be no stuck touches. + int32_t initialSlot; + if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot); + status == OK) { + mCurrentSlot = initialSlot; + } else { + ALOGD("Could not retrieve current multi-touch slot index. status=%d", status); + } + } +} + +void MultiTouchMotionAccumulator::resetSlots() { + for (Slot& slot : mSlots) { + slot.clear(); + } + mCurrentSlot = -1; +} + +void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_ABS) { + bool newSlot = false; + if (mUsingSlotsProtocol) { + if (rawEvent->code == ABS_MT_SLOT) { + mCurrentSlot = rawEvent->value; + newSlot = true; + } + } else if (mCurrentSlot < 0) { + mCurrentSlot = 0; + } + + if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) { + if (newSlot) { + ALOGW_IF(DEBUG_POINTERS, + "MultiTouch device emitted invalid slot index %d but it " + "should be between 0 and %zd; ignoring this slot.", + mCurrentSlot, mSlots.size() - 1); + } + } else { + Slot& slot = mSlots[mCurrentSlot]; + // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of + // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while + // updating the slot. + if (!mUsingSlotsProtocol) { + slot.mInUse = true; + } + + switch (rawEvent->code) { + case ABS_MT_POSITION_X: + slot.mAbsMtPositionX = rawEvent->value; + warnIfNotInUse(*rawEvent, slot); + break; + case ABS_MT_POSITION_Y: + slot.mAbsMtPositionY = rawEvent->value; + warnIfNotInUse(*rawEvent, slot); + break; + case ABS_MT_TOUCH_MAJOR: + slot.mAbsMtTouchMajor = rawEvent->value; + break; + case ABS_MT_TOUCH_MINOR: + slot.mAbsMtTouchMinor = rawEvent->value; + slot.mHaveAbsMtTouchMinor = true; + break; + case ABS_MT_WIDTH_MAJOR: + slot.mAbsMtWidthMajor = rawEvent->value; + break; + case ABS_MT_WIDTH_MINOR: + slot.mAbsMtWidthMinor = rawEvent->value; + slot.mHaveAbsMtWidthMinor = true; + break; + case ABS_MT_ORIENTATION: + slot.mAbsMtOrientation = rawEvent->value; + break; + case ABS_MT_TRACKING_ID: + if (mUsingSlotsProtocol && rawEvent->value < 0) { + // The slot is no longer in use but it retains its previous contents, + // which may be reused for subsequent touches. + slot.mInUse = false; + } else { + slot.mInUse = true; + slot.mAbsMtTrackingId = rawEvent->value; + } + break; + case ABS_MT_PRESSURE: + slot.mAbsMtPressure = rawEvent->value; + break; + case ABS_MT_DISTANCE: + slot.mAbsMtDistance = rawEvent->value; + break; + case ABS_MT_TOOL_TYPE: + slot.mAbsMtToolType = rawEvent->value; + slot.mHaveAbsMtToolType = true; + break; + } + } + } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { + // MultiTouch Sync: The driver has returned all data for *one* of the pointers. + mCurrentSlot += 1; + } +} + +void MultiTouchMotionAccumulator::finishSync() { + if (!mUsingSlotsProtocol) { + resetSlots(); + } +} + +bool MultiTouchMotionAccumulator::hasStylus() const { + return mHaveStylus; +} + +void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) { + if (!slot.mInUse) { + ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i", + event.code, event.value, mCurrentSlot, slot.mAbsMtTrackingId); + } +} + +// --- MultiTouchMotionAccumulator::Slot --- + +int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { + if (mHaveAbsMtToolType) { + switch (mAbsMtToolType) { + case MT_TOOL_FINGER: + return AMOTION_EVENT_TOOL_TYPE_FINGER; + case MT_TOOL_PEN: + return AMOTION_EVENT_TOOL_TYPE_STYLUS; + case MT_TOOL_PALM: + return AMOTION_EVENT_TOOL_TYPE_PALM; + } + } + return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h new file mode 100644 index 0000000000..625a00fdd4 --- /dev/null +++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 <linux/input-event-codes.h> +#include <stdint.h> +#include <vector> + +#include "EventHub.h" +#include "InputDevice.h" + +namespace android { + +/* Keeps track of the state of multi-touch protocol. */ +class MultiTouchMotionAccumulator { +public: + class Slot { + public: + inline bool isInUse() const { return mInUse; } + inline int32_t getX() const { return mAbsMtPositionX; } + inline int32_t getY() const { return mAbsMtPositionY; } + inline int32_t getTouchMajor() const { return mAbsMtTouchMajor; } + inline int32_t getTouchMinor() const { + return mHaveAbsMtTouchMinor ? mAbsMtTouchMinor : mAbsMtTouchMajor; + } + inline int32_t getToolMajor() const { return mAbsMtWidthMajor; } + inline int32_t getToolMinor() const { + return mHaveAbsMtWidthMinor ? mAbsMtWidthMinor : mAbsMtWidthMajor; + } + inline int32_t getOrientation() const { return mAbsMtOrientation; } + inline int32_t getTrackingId() const { return mAbsMtTrackingId; } + inline int32_t getPressure() const { return mAbsMtPressure; } + inline int32_t getDistance() const { return mAbsMtDistance; } + int32_t getToolType() const; + + private: + friend class MultiTouchMotionAccumulator; + + bool mInUse = false; + bool mHaveAbsMtTouchMinor = false; + bool mHaveAbsMtWidthMinor = false; + bool mHaveAbsMtToolType = false; + + int32_t mAbsMtPositionX = 0; + int32_t mAbsMtPositionY = 0; + int32_t mAbsMtTouchMajor = 0; + int32_t mAbsMtTouchMinor = 0; + int32_t mAbsMtWidthMajor = 0; + int32_t mAbsMtWidthMinor = 0; + int32_t mAbsMtOrientation = 0; + int32_t mAbsMtTrackingId = -1; + int32_t mAbsMtPressure = 0; + int32_t mAbsMtDistance = 0; + int32_t mAbsMtToolType = 0; + + void clear() { *this = Slot(); } + }; + + MultiTouchMotionAccumulator(); + + void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); + void process(const RawEvent* rawEvent); + void finishSync(); + bool hasStylus() const; + + inline size_t getSlotCount() const { return mSlots.size(); } + inline const Slot& getSlot(size_t index) const { + LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); + return mSlots[index]; + } + +private: + int32_t mCurrentSlot; + std::vector<Slot> mSlots; + bool mUsingSlotsProtocol; + bool mHaveStylus; + + void resetSlots(); + void warnIfNotInUse(const RawEvent& event, const Slot& slot); +}; + +} // namespace android diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index ecc42ba5c2..e4e22df5de 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2373,7 +2373,7 @@ TEST_F(InputReaderIntegrationTest, TestInvalidDevice) { // An invalid input device that is only used for this test. class InvalidUinputDevice : public UinputDevice { public: - InvalidUinputDevice() : UinputDevice("Invalid Device") {} + InvalidUinputDevice() : UinputDevice("Invalid Device", 99 /*productId*/) {} private: void configureDevice(int fd, uinput_user_dev* device) override {} @@ -2825,6 +2825,96 @@ TEST_F(TouchIntegrationTest, StylusButtonsGenerateKeyEvents) { WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY)))); } +TEST_F(TouchIntegrationTest, StylusButtonsSurroundingTouchGesture) { + const Point centerPoint = mDevice->getCenterPoint(); + + // Press the stylus button. + mDevice->sendKey(BTN_STYLUS, 1); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled( + AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_KEYBOARD), + WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY)))); + + // Start and finish a stylus gesture. + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); + mDevice->sendToolType(MT_TOOL_PEN); + mDevice->sendDown(centerPoint); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)))); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)))); + + mDevice->sendTrackingId(INVALID_TRACKING_ID); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0)))); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0)))); + + // Release the stylus button. + mDevice->sendKey(BTN_STYLUS, 0); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled( + AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_KEYBOARD), + WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY)))); +} + +TEST_F(TouchIntegrationTest, StylusButtonsWithinTouchGesture) { + const Point centerPoint = mDevice->getCenterPoint(); + + // Start a stylus gesture. + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); + mDevice->sendToolType(MT_TOOL_PEN); + mDevice->sendDown(centerPoint); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0)))); + + // Press and release a stylus button. Each change in button state also generates a MOVE event. + mDevice->sendKey(BTN_STYLUS, 1); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled( + AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_KEYBOARD), + WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY)))); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)))); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)))); + + mDevice->sendKey(BTN_STYLUS, 0); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled( + AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_KEYBOARD), + WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY)))); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0)))); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0)))); + + // Finish the stylus gesture. + mDevice->sendTrackingId(INVALID_TRACKING_ID); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0)))); +} + // --- InputDeviceTest --- class InputDeviceTest : public testing::Test { protected: diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp index c4830dc815..bc695b8bd8 100644 --- a/services/inputflinger/tests/UinputDevice.cpp +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -24,7 +24,8 @@ namespace android { // --- UinputDevice --- -UinputDevice::UinputDevice(const char* name) : mName(name) {} +UinputDevice::UinputDevice(const char* name, int16_t productId) + : mName(name), mProductId(productId) {} UinputDevice::~UinputDevice() { if (ioctl(mDeviceFd, UI_DEV_DESTROY)) { @@ -43,7 +44,7 @@ void UinputDevice::init() { strlcpy(device.name, mName, UINPUT_MAX_NAME_SIZE); device.id.bustype = BUS_USB; device.id.vendor = 0x01; - device.id.product = 0x01; + device.id.product = mProductId; device.id.version = 1; ASSERT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device)); @@ -76,8 +77,8 @@ void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) { // --- UinputKeyboard --- -UinputKeyboard::UinputKeyboard(const char* name, std::initializer_list<int> keys) - : UinputDevice(name), mKeys(keys.begin(), keys.end()) {} +UinputKeyboard::UinputKeyboard(const char* name, int16_t productId, std::initializer_list<int> keys) + : UinputDevice(name, productId), mKeys(keys.begin(), keys.end()) {} void UinputKeyboard::configureDevice(int fd, uinput_user_dev* device) { // enable key press/release event @@ -121,23 +122,26 @@ void UinputKeyboard::pressAndReleaseKey(int key) { // --- UinputHomeKey --- -UinputHomeKey::UinputHomeKey() : UinputKeyboard("Test Uinput Home Key", {KEY_HOME}) {} +UinputHomeKey::UinputHomeKey() : UinputKeyboard(DEVICE_NAME, PRODUCT_ID, {KEY_HOME}) {} void UinputHomeKey::pressAndReleaseHomeKey() { pressAndReleaseKey(KEY_HOME); } -// --- UinputSteamController +// --- UinputSteamController --- + UinputSteamController::UinputSteamController() - : UinputKeyboard("Test Uinput Steam Controller", {BTN_GEAR_DOWN, BTN_GEAR_UP}) {} + : UinputKeyboard(DEVICE_NAME, PRODUCT_ID, {BTN_GEAR_DOWN, BTN_GEAR_UP}) {} + +// --- UinputExternalStylus --- -// --- UinputExternalStylus UinputExternalStylus::UinputExternalStylus() - : UinputKeyboard("Test Uinput External Stylus", {BTN_STYLUS, BTN_STYLUS2, BTN_STYLUS3}) {} + : UinputKeyboard(DEVICE_NAME, PRODUCT_ID, {BTN_STYLUS, BTN_STYLUS2, BTN_STYLUS3}) {} // --- UinputTouchScreen --- -UinputTouchScreen::UinputTouchScreen(const Rect* size) - : UinputDevice(UinputTouchScreen::DEVICE_NAME), mSize(*size) {} + +UinputTouchScreen::UinputTouchScreen(const Rect& size) + : UinputDevice(DEVICE_NAME, PRODUCT_ID), mSize(size) {} void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) { // Setup the touch screen device diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index 53dcfd0a68..d661bd36d3 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -32,7 +32,7 @@ namespace android { template <class D, class... Ts> std::unique_ptr<D> createUinputDevice(Ts... args) { // Using `new` to access non-public constructors. - std::unique_ptr<D> dev(new D(&args...)); + std::unique_ptr<D> dev(new D(args...)); EXPECT_NO_FATAL_FAILURE(dev->init()); return dev; } @@ -51,8 +51,9 @@ public: protected: const char* mName; + const int16_t mProductId; - UinputDevice(const char* name); + explicit UinputDevice(const char* name, int16_t productId); // Signals which types of events this device supports before it is created. // This must be overridden by subclasses. @@ -71,7 +72,8 @@ private: class UinputKeyboard : public UinputDevice { public: - static constexpr const char* KEYBOARD_NAME = "Test Keyboard Device"; + static constexpr const char* KEYBOARD_NAME = "Test Uinput Keyboard Device"; + static constexpr int16_t PRODUCT_ID = 42; // Injects key press and sync. void pressKey(int key); @@ -84,7 +86,8 @@ public: friend std::unique_ptr<D> createUinputDevice(Ts... args); protected: - UinputKeyboard(const char* name, std::initializer_list<int> keys = {}); + explicit UinputKeyboard(const char* name, int16_t productId = PRODUCT_ID, + std::initializer_list<int> keys = {}); private: void configureDevice(int fd, uinput_user_dev* device) override; @@ -97,6 +100,9 @@ private: // A keyboard device that has a single HOME key. class UinputHomeKey : public UinputKeyboard { public: + static constexpr const char* DEVICE_NAME = "Test Uinput Home Key"; + static constexpr int16_t PRODUCT_ID = 43; + // Injects 4 events: key press, sync, key release, and sync. void pressAndReleaseHomeKey(); @@ -104,34 +110,47 @@ public: friend std::unique_ptr<D> createUinputDevice(Ts... args); private: - UinputHomeKey(); + explicit UinputHomeKey(); }; +// --- UinputSteamController --- + // A joystick device that sends a BTN_GEAR_DOWN / BTN_WHEEL key. class UinputSteamController : public UinputKeyboard { public: + static constexpr const char* DEVICE_NAME = "Test Uinput Steam Controller"; + static constexpr int16_t PRODUCT_ID = 44; + template <class D, class... Ts> friend std::unique_ptr<D> createUinputDevice(Ts... args); private: - UinputSteamController(); + explicit UinputSteamController(); }; +// --- UinputExternalStylus --- + // A stylus that reports button presses. class UinputExternalStylus : public UinputKeyboard { public: + static constexpr const char* DEVICE_NAME = "Test Uinput External Stylus"; + static constexpr int16_t PRODUCT_ID = 45; + template <class D, class... Ts> friend std::unique_ptr<D> createUinputDevice(Ts... args); private: - UinputExternalStylus(); + explicit UinputExternalStylus(); }; // --- UinputTouchScreen --- -// A touch screen device with specific size. + +// A multi-touch touchscreen device with specific size that also supports styluses. class UinputTouchScreen : public UinputDevice { public: - static constexpr const char* DEVICE_NAME = "Test Touch Screen"; + static constexpr const char* DEVICE_NAME = "Test Uinput Touch Screen"; + static constexpr int16_t PRODUCT_ID = 46; + static const int32_t RAW_TOUCH_MIN = 0; static const int32_t RAW_TOUCH_MAX = 31; static const int32_t RAW_ID_MIN = 0; @@ -157,7 +176,7 @@ public: const Point getCenterPoint(); protected: - UinputTouchScreen(const Rect* size); + explicit UinputTouchScreen(const Rect& size); private: void configureDevice(int fd, uinput_user_dev* device) override; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h index 5f749dfbcc..f4ded216cb 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h @@ -42,6 +42,7 @@ public: MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t), (override)); MOCK_METHOD(Status, reportActualWorkDuration, (const ::std::vector<WorkDuration>&), (override)); MOCK_METHOD(Status, sendHint, (SessionHint), (override)); + MOCK_METHOD(Status, setThreads, (const ::std::vector<int32_t>&), (override)); }; } // namespace android::Hwc2::mock |