diff options
-rw-r--r-- | cmds/dumpstate/DumpstateService.cpp | 42 | ||||
-rw-r--r-- | cmds/dumpstate/DumpstateService.h | 7 | ||||
-rw-r--r-- | cmds/dumpstate/binder/android/os/IDumpstate.aidl | 23 | ||||
-rw-r--r-- | cmds/dumpstate/binder/android/os/IDumpstateListener.aidl | 7 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.cpp | 71 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.h | 17 | ||||
-rw-r--r-- | cmds/dumpstate/tests/dumpstate_smoke_test.cpp | 2 | ||||
-rw-r--r-- | cmds/dumpstate/tests/dumpstate_test.cpp | 16 | ||||
-rw-r--r-- | libs/binder/RpcState.cpp | 4 | ||||
-rw-r--r-- | libs/binder/trusty/RpcServerTrusty.cpp | 10 | ||||
-rw-r--r-- | libs/binder/trusty/include_mock/lib/tipc/tipc.h | 8 | ||||
-rw-r--r-- | libs/jpegrecoverymap/Android.bp | 2 | ||||
-rw-r--r-- | libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h | 1 | ||||
-rw-r--r-- | libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h | 7 | ||||
-rw-r--r-- | libs/jpegrecoverymap/recoverymap.cpp | 60 | ||||
-rw-r--r-- | libs/jpegrecoverymap/tests/Android.bp | 8 | ||||
-rw-r--r-- | services/surfaceflinger/TransactionCallbackInvoker.cpp | 7 |
17 files changed, 228 insertions, 64 deletions
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index 42e9e0f1a7..a7bc018ff6 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -58,6 +58,13 @@ static binder::Status exception(uint32_t code, const std::string& msg, exit(0); } +[[noreturn]] static void* dumpstate_thread_retrieve(void* data) { + std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data)); + ds_info->ds->Retrieve(ds_info->calling_uid, ds_info->calling_package); + MYLOGD("Finished retrieving a bugreport. Exiting.\n"); + exit(0); +} + [[noreturn]] static void signalErrorAndExit(sp<IDumpstateListener> listener, int error_code) { listener->onError(error_code); exit(0); @@ -192,6 +199,41 @@ binder::Status DumpstateService::cancelBugreport(int32_t calling_uid, return binder::Status::ok(); } +binder::Status DumpstateService::retrieveBugreport( + int32_t calling_uid, const std::string& calling_package, + android::base::unique_fd bugreport_fd, + const std::string& bugreport_file, + const sp<IDumpstateListener>& listener) { + + ds_ = &(Dumpstate::GetInstance()); + DumpstateInfo* ds_info = new DumpstateInfo(); + ds_info->ds = ds_; + ds_info->calling_uid = calling_uid; + ds_info->calling_package = calling_package; + ds_->listener_ = listener; + std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>(); + // Use a /dev/null FD when initializing options since none is provided. + android::base::unique_fd devnull_fd( + TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC))); + + options->Initialize(Dumpstate::BugreportMode::BUGREPORT_DEFAULT, + 0, bugreport_fd, devnull_fd, false); + + if (bugreport_fd.get() == -1) { + MYLOGE("Invalid filedescriptor"); + signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); + } + ds_->SetOptions(std::move(options)); + ds_->path_ = bugreport_file; + pthread_t thread; + status_t err = pthread_create(&thread, nullptr, dumpstate_thread_retrieve, ds_info); + if (err != 0) { + MYLOGE("Could not create a thread"); + signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR); + } + return binder::Status::ok(); +} + status_t DumpstateService::dump(int fd, const Vector<String16>&) { std::lock_guard<std::mutex> lock(lock_); if (ds_ == nullptr) { diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h index 997999c805..dd7331932c 100644 --- a/cmds/dumpstate/DumpstateService.h +++ b/cmds/dumpstate/DumpstateService.h @@ -46,6 +46,13 @@ class DumpstateService : public BinderService<DumpstateService>, public BnDumpst int bugreport_flags, const sp<IDumpstateListener>& listener, bool is_screenshot_requested) override; + binder::Status retrieveBugreport(int32_t calling_uid, + const std::string& calling_package, + android::base::unique_fd bugreport_fd, + const std::string& bugreport_file, + const sp<IDumpstateListener>& listener) + override; + binder::Status cancelBugreport(int32_t calling_uid, const std::string& calling_package) override; diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl index d4323af3cf..0dc8f5ad64 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl @@ -50,7 +50,10 @@ interface IDumpstate { const int BUGREPORT_MODE_DEFAULT = 6; // Use pre-dumped data. - const int BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA = 1; + const int BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA = 0x1; + + // Defer user consent. + const int BUGREPORT_FLAG_DEFER_CONSENT = 0x2; /** * Speculatively pre-dumps UI data for a bugreport request that might come later. @@ -100,4 +103,22 @@ interface IDumpstate { * @param callingPackage package of the original application that requested the cancellation. */ void cancelBugreport(int callingUid, @utf8InCpp String callingPackage); + + /** + * Retrieves a previously generated bugreport. + * + * <p>The caller must have previously generated a bugreport using + * {@link #startBugreport} with the {@link BUGREPORT_FLAG_DEFER_CONSENT} + * flag set. + * + * @param callingUid UID of the original application that requested the report. + * @param callingPackage package of the original application that requested the report. + * @param bugreportFd the file to which the zipped bugreport should be written + * @param bugreportFile the path of the bugreport file + * @param listener callback for updates; optional + */ + void retrieveBugreport(int callingUid, @utf8InCpp String callingPackage, + FileDescriptor bugreportFd, + @utf8InCpp String bugreportFile, + IDumpstateListener listener); } diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl index 50c1624dc2..e8891d3236 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl @@ -50,6 +50,9 @@ interface IDumpstateListener { /* There is currently a bugreport running. The caller should try again later. */ const int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; + /* There is no bugreport to retrieve for the given caller. */ + const int BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE = 6; + /** * Called on an error condition with one of the error codes listed above. */ @@ -57,8 +60,10 @@ interface IDumpstateListener { /** * Called when taking bugreport finishes successfully. + * + * @param bugreportFile The location of the bugreport file */ - oneway void onFinished(); + oneway void onFinished(@utf8InCpp String bugreportFile); /** * Called when screenshot is taken. diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index c06a714b6a..ecafcfc170 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2825,6 +2825,7 @@ void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& screenshot_fd_in, bool is_screenshot_requested) { this->use_predumped_ui_data = bugreport_flags & BugreportFlag::BUGREPORT_USE_PREDUMPED_UI_DATA; + this->is_consent_deferred = bugreport_flags & BugreportFlag::BUGREPORT_FLAG_DEFER_CONSENT; // Duplicate the fds because the passed in fds don't outlive the binder transaction. bugreport_fd.reset(fcntl(bugreport_fd_in.get(), F_DUPFD_CLOEXEC, 0)); screenshot_fd.reset(fcntl(screenshot_fd_in.get(), F_DUPFD_CLOEXEC, 0)); @@ -2907,10 +2908,64 @@ void Dumpstate::Initialize() { Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) { Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package); - if (listener_ != nullptr) { + HandleRunStatus(status); + return status; +} + +Dumpstate::RunStatus Dumpstate::Retrieve(int32_t calling_uid, const std::string& calling_package) { + Dumpstate::RunStatus status = RetrieveInternal(calling_uid, calling_package); + HandleRunStatus(status); + return status; +} + +Dumpstate::RunStatus Dumpstate::RetrieveInternal(int32_t calling_uid, + const std::string& calling_package) { + consent_callback_ = new ConsentCallback(); + const String16 incidentcompanion("incidentcompanion"); + sp<android::IBinder> ics( + defaultServiceManager()->checkService(incidentcompanion)); + android::String16 package(calling_package.c_str()); + if (ics != nullptr) { + MYLOGD("Checking user consent via incidentcompanion service\n"); + android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport( + calling_uid, package, String16(), String16(), + 0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get()); + } else { + MYLOGD( + "Unable to check user consent; incidentcompanion service unavailable\n"); + return RunStatus::USER_CONSENT_TIMED_OUT; + } + UserConsentResult consent_result = consent_callback_->getResult(); + int timeout_ms = 30 * 1000; + while (consent_result == UserConsentResult::UNAVAILABLE && + consent_callback_->getElapsedTimeMs() < timeout_ms) { + sleep(1); + consent_result = consent_callback_->getResult(); + } + if (consent_result == UserConsentResult::DENIED) { + return RunStatus::USER_CONSENT_DENIED; + } + if (consent_result == UserConsentResult::UNAVAILABLE) { + MYLOGD("Canceling user consent request via incidentcompanion service\n"); + android::interface_cast<android::os::IIncidentCompanion>(ics)->cancelAuthorization( + consent_callback_.get()); + return RunStatus::USER_CONSENT_TIMED_OUT; + } + + bool copy_succeeded = + android::os::CopyFileToFd(path_, options_->bugreport_fd.get()); + if (copy_succeeded) { + android::os::UnlinkAndLogOnError(path_); + } + return copy_succeeded ? Dumpstate::RunStatus::OK + : Dumpstate::RunStatus::ERROR; +} + +void Dumpstate::HandleRunStatus(Dumpstate::RunStatus status) { + if (listener_ != nullptr) { switch (status) { case Dumpstate::RunStatus::OK: - listener_->onFinished(); + listener_->onFinished(path_.c_str()); break; case Dumpstate::RunStatus::HELP: break; @@ -2928,9 +2983,7 @@ Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& call break; } } - return status; } - void Dumpstate::Cancel() { CleanupTmpFiles(); android::os::UnlinkAndLogOnError(log_path_); @@ -3181,7 +3234,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, // Share the final file with the caller if the user has consented or Shell is the caller. Dumpstate::RunStatus status = Dumpstate::RunStatus::OK; - if (CalledByApi()) { + if (CalledByApi() && !options_->is_consent_deferred) { status = CopyBugreportIfUserConsented(calling_uid); if (status != Dumpstate::RunStatus::OK && status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) { @@ -3335,9 +3388,11 @@ void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) { } void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) { - if (multiuser_get_app_id(calling_uid) == AID_SHELL || !CalledByApi()) { - // No need to get consent for shell triggered dumpstates, or not through - // bugreporting API (i.e. no fd to copy back). + if (multiuser_get_app_id(calling_uid) == AID_SHELL || + !CalledByApi() || options_->is_consent_deferred) { + // No need to get consent for shell triggered dumpstates, or not + // through bugreporting API (i.e. no fd to copy back), or when consent + // is deferred. return; } consent_callback_ = new ConsentCallback(); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 9f894b5079..8a31c314d9 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -207,7 +207,9 @@ class Dumpstate { // The flags used to customize bugreport requests. enum BugreportFlag { BUGREPORT_USE_PREDUMPED_UI_DATA = - android::os::IDumpstate::BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA + android::os::IDumpstate::BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA, + BUGREPORT_FLAG_DEFER_CONSENT = + android::os::IDumpstate::BUGREPORT_FLAG_DEFER_CONSENT }; static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS; @@ -353,6 +355,15 @@ class Dumpstate { */ RunStatus Run(int32_t calling_uid, const std::string& calling_package); + /* + * Entry point for retrieving a previous-generated bugreport. + * + * Initialize() dumpstate before calling this method. + */ + RunStatus Retrieve(int32_t calling_uid, const std::string& calling_package); + + + RunStatus ParseCommandlineAndRun(int argc, char* argv[]); /* Deletes in-progress files */ @@ -396,6 +407,7 @@ class Dumpstate { bool progress_updates_to_socket = false; bool do_screenshot = false; bool is_screenshot_copied = false; + bool is_consent_deferred = false; bool is_remote_mode = false; bool show_header_only = false; bool telephony_only = false; @@ -548,6 +560,7 @@ class Dumpstate { private: RunStatus RunInternal(int32_t calling_uid, const std::string& calling_package); + RunStatus RetrieveInternal(int32_t calling_uid, const std::string& calling_package); RunStatus DumpstateDefaultAfterCritical(); RunStatus dumpstate(); @@ -572,6 +585,8 @@ class Dumpstate { RunStatus HandleUserConsentDenied(); + void HandleRunStatus(RunStatus status); + // Copies bugreport artifacts over to the caller's directories provided there is user consent or // called by Shell. RunStatus CopyBugreportIfUserConsented(int32_t calling_uid); diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp index b091c8e297..ccf64fe54e 100644 --- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp @@ -160,7 +160,7 @@ class DumpstateListener : public BnDumpstateListener { return binder::Status::ok(); } - binder::Status onFinished() override { + binder::Status onFinished([[maybe_unused]] const std::string& bugreport_file) override { std::lock_guard<std::mutex> lock(lock_); is_finished_ = true; dprintf(out_fd_, "\rFinished"); diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 1ffcafa544..87f92544c0 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -71,7 +71,7 @@ class DumpstateListenerMock : public IDumpstateListener { public: MOCK_METHOD1(onProgress, binder::Status(int32_t progress)); MOCK_METHOD1(onError, binder::Status(int32_t error_code)); - MOCK_METHOD0(onFinished, binder::Status()); + MOCK_METHOD1(onFinished, binder::Status(const std::string& bugreport_file)); MOCK_METHOD1(onScreenshotTaken, binder::Status(bool success)); MOCK_METHOD0(onUiIntensiveBugreportDumpsFinished, binder::Status()); @@ -486,6 +486,20 @@ TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) { EXPECT_TRUE(options_.ValidateOptions()); } +TEST_F(DumpOptionsTest, InitializeBugreportFlags) { + int flags = Dumpstate::BugreportFlag::BUGREPORT_USE_PREDUMPED_UI_DATA | + Dumpstate::BugreportFlag::BUGREPORT_FLAG_DEFER_CONSENT; + options_.Initialize( + Dumpstate::BugreportMode::BUGREPORT_FULL, flags, fd, fd, true); + EXPECT_TRUE(options_.is_consent_deferred); + EXPECT_TRUE(options_.use_predumped_ui_data); + + options_.Initialize( + Dumpstate::BugreportMode::BUGREPORT_FULL, 0, fd, fd, true); + EXPECT_FALSE(options_.is_consent_deferred); + EXPECT_FALSE(options_.use_predumped_ui_data); +} + class DumpstateTest : public DumpstateBaseTest { public: void SetUp() { diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index b27f1028d4..1ea13f9a1c 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -1036,8 +1036,8 @@ processTransactInternalTailCall: return DEAD_OBJECT; } - if (it->second.asyncTodo.size() == 0) return OK; - if (it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) { + if (it->second.asyncTodo.size() != 0 && + it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) { LOG_RPC_DETAIL("Found next async transaction %" PRIu64 " on %" PRIu64, it->second.asyncNumber, addr); diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp index 18ce316d67..109da7509a 100644 --- a/libs/binder/trusty/RpcServerTrusty.cpp +++ b/libs/binder/trusty/RpcServerTrusty.cpp @@ -117,7 +117,15 @@ int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const u *ctx_p = channelContext; }; - base::unique_fd clientFd(chan); + // We need to duplicate the channel handle here because the tipc library + // owns the original handle and closes is automatically on channel cleanup. + // We use dup() because Trusty does not have fcntl(). + // NOLINTNEXTLINE(android-cloexec-dup) + handle_t chanDup = dup(chan); + if (chanDup < 0) { + return chanDup; + } + base::unique_fd clientFd(chanDup); android::RpcTransportFd transportFd(std::move(clientFd)); std::array<uint8_t, RpcServer::kRpcAddressSize> addr; diff --git a/libs/binder/trusty/include_mock/lib/tipc/tipc.h b/libs/binder/trusty/include_mock/lib/tipc/tipc.h index f295be4980..ead9f9cdaf 100644 --- a/libs/binder/trusty/include_mock/lib/tipc/tipc.h +++ b/libs/binder/trusty/include_mock/lib/tipc/tipc.h @@ -15,7 +15,9 @@ */ #pragma once -__BEGIN_DECLS +#if defined(__cplusplus) +extern "C" { +#endif struct tipc_hset; @@ -26,4 +28,6 @@ int tipc_run_event_loop(struct tipc_hset*) { return 0; } -__END_DECLS +#if defined(__cplusplus) +} +#endif diff --git a/libs/jpegrecoverymap/Android.bp b/libs/jpegrecoverymap/Android.bp index 01318dc80a..2c4b3bff77 100644 --- a/libs/jpegrecoverymap/Android.bp +++ b/libs/jpegrecoverymap/Android.bp @@ -41,6 +41,8 @@ cc_library { "libjpegdecoder", "liblog", ], + + static_libs: ["libskia"], } cc_library { diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h index 696be1beb7..1a4b679a73 100644 --- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h @@ -34,6 +34,7 @@ typedef enum { JPEGR_TF_LINEAR = 0, JPEGR_TF_HLG = 1, JPEGR_TF_PQ = 2, + JPEGR_TF_SRGB = 3, } jpegr_transfer_function; struct jpegr_info_struct { diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h index c36a363a3c..8696851155 100644 --- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h @@ -28,13 +28,6 @@ namespace android::recoverymap { struct jpegr_metadata; -// If the EXIF package doesn't exist in the input JPEG, we'll create one with one entry -// where the length is represented by this value. -const size_t PSEUDO_EXIF_PACKAGE_LENGTH = 28; -// If the EXIF package exists in the input JPEG, we'll add an "JR" entry where the length is -// represented by this value. -const size_t EXIF_J_R_ENTRY_LENGTH = 12; - /* * Helper function used for writing data to destination. * diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp index 30aa846bf8..e06bd24cfa 100644 --- a/libs/jpegrecoverymap/recoverymap.cpp +++ b/libs/jpegrecoverymap/recoverymap.cpp @@ -26,7 +26,10 @@ #include <image_io/jpeg/jpeg_info_builder.h> #include <image_io/base/data_segment_data_source.h> #include <utils/Log.h> +#include "SkColorSpace.h" +#include "SkICC.h" +#include <map> #include <memory> #include <sstream> #include <string> @@ -93,30 +96,19 @@ int GetCPUCoreCount() { return cpuCoreCount; } -/* - * Helper function copies the JPEG image from without EXIF. - * - * @param dest destination of the data to be written. - * @param source source of data being written. - * @param exif_pos position of the EXIF package, which is aligned with jpegdecoder.getEXIFPos(). - * (4 bypes offset to FF sign, the byte after FF E1 XX XX <this byte>). - * @param exif_size exif size without the initial 4 bytes, aligned with jpegdecoder.getEXIFSize(). - */ -void copyJpegWithoutExif(jr_compressed_ptr dest, - jr_compressed_ptr source, - size_t exif_pos, - size_t exif_size) { - memcpy(dest, source, sizeof(jpegr_compressed_struct)); - - const size_t exif_offset = 4; //exif_pos has 4 bypes offset to the FF sign - dest->length = source->length - exif_size - exif_offset; - dest->data = malloc(dest->length); - - memcpy(dest->data, source->data, exif_pos - exif_offset); - memcpy((uint8_t*)dest->data + exif_pos - exif_offset, - (uint8_t*)source->data + exif_pos + exif_size, - source->length - exif_pos - exif_size); -} +static const map<recoverymap::jpegr_color_gamut, skcms_Matrix3x3> jrGamut_to_skGamut { + {JPEGR_COLORGAMUT_BT709, SkNamedGamut::kSRGB}, + {JPEGR_COLORGAMUT_P3, SkNamedGamut::kDisplayP3}, + {JPEGR_COLORGAMUT_BT2100, SkNamedGamut::kRec2020}, +}; + +static const map< + recoverymap::jpegr_transfer_function, skcms_TransferFunction> jrTransFunc_to_skTransFunc { + {JPEGR_TF_SRGB, SkNamedTransferFn::kSRGB}, + {JPEGR_TF_LINEAR, SkNamedTransferFn::kLinear}, + {JPEGR_TF_HLG, SkNamedTransferFn::kHLG}, + {JPEGR_TF_PQ, SkNamedTransferFn::kPQ}, +}; /* Encode API-0 */ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, @@ -164,11 +156,15 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, compressed_map.data = compressed_map_data.get(); JPEGR_CHECK(compressRecoveryMap(&map, &compressed_map)); + sk_sp<SkData> icc = SkWriteICCProfile( + jrTransFunc_to_skTransFunc.at(JPEGR_TF_SRGB), + jrGamut_to_skGamut.at(uncompressed_yuv_420_image.colorGamut)); + JpegEncoder jpeg_encoder; - // TODO: determine ICC data based on color gamut information if (!jpeg_encoder.compressImage(uncompressed_yuv_420_image.data, uncompressed_yuv_420_image.width, - uncompressed_yuv_420_image.height, quality, nullptr, 0)) { + uncompressed_yuv_420_image.height, quality, + icc.get()->data(), icc.get()->size())) { return ERROR_JPEGR_ENCODE_ERROR; } jpegr_compressed_struct jpeg; @@ -228,11 +224,15 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, compressed_map.data = compressed_map_data.get(); JPEGR_CHECK(compressRecoveryMap(&map, &compressed_map)); + sk_sp<SkData> icc = SkWriteICCProfile( + jrTransFunc_to_skTransFunc.at(JPEGR_TF_SRGB), + jrGamut_to_skGamut.at(uncompressed_yuv_420_image->colorGamut)); + JpegEncoder jpeg_encoder; - // TODO: determine ICC data based on color gamut information if (!jpeg_encoder.compressImage(uncompressed_yuv_420_image->data, uncompressed_yuv_420_image->width, - uncompressed_yuv_420_image->height, quality, nullptr, 0)) { + uncompressed_yuv_420_image->height, quality, + icc.get()->data(), icc.get()->size())) { return ERROR_JPEGR_ENCODE_ERROR; } jpegr_compressed_struct jpeg; @@ -574,7 +574,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 #endif hdr_white_nits = kPqMaxNits; break; - case JPEGR_TF_UNSPECIFIED: + default: // Should be impossible to hit after input validation. return ERROR_JPEGR_INVALID_TRANS_FUNC; } @@ -750,7 +750,7 @@ status_t RecoveryMap::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_ hdrOetf = pqOetf; #endif break; - case JPEGR_TF_UNSPECIFIED: + default: // Should be impossible to hit after input validation. hdrOetf = identityConversion; } diff --git a/libs/jpegrecoverymap/tests/Android.bp b/libs/jpegrecoverymap/tests/Android.bp index 39445f81ab..cad273e437 100644 --- a/libs/jpegrecoverymap/tests/Android.bp +++ b/libs/jpegrecoverymap/tests/Android.bp @@ -30,15 +30,13 @@ cc_test { ], shared_libs: [ "libjpeg", + "libjpegrecoverymap", "libimage_io", "liblog", ], static_libs: [ "libgmock", "libgtest", - "libjpegdecoder", - "libjpegencoder", - "libjpegrecoverymap", ], } @@ -50,10 +48,10 @@ cc_test { ], shared_libs: [ "libjpeg", + "libjpegencoder", "liblog", ], static_libs: [ - "libjpegencoder", "libgtest", ], } @@ -66,10 +64,10 @@ cc_test { ], shared_libs: [ "libjpeg", + "libjpegdecoder", "liblog", ], static_libs: [ - "libjpegdecoder", "libgtest", ], } diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index e5de7591ef..3da98d4247 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -137,7 +137,6 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& sp<Fence> currentFence = future.get().value_or(Fence::NO_FENCE); if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) { prevFence = std::move(currentFence); - handle->previousReleaseFence = prevFence; } else if (prevFence != nullptr) { // If both fences are signaled or both are unsignaled, we need to merge // them to get an accurate timestamp. @@ -147,8 +146,7 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& snprintf(fenceName, 32, "%.28s", handle->name.c_str()); sp<Fence> mergedFence = Fence::merge(fenceName, prevFence, currentFence); if (mergedFence->isValid()) { - handle->previousReleaseFence = std::move(mergedFence); - prevFence = handle->previousReleaseFence; + prevFence = std::move(mergedFence); } } else if (currentFence->getStatus() == Fence::Status::Unsignaled) { // If one fence has signaled and the other hasn't, the unsignaled @@ -158,10 +156,11 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& // by this point, they will have both signaled and only the timestamp // will be slightly off; any dependencies after this point will // already have been met. - handle->previousReleaseFence = std::move(currentFence); + prevFence = std::move(currentFence); } } } + handle->previousReleaseFence = prevFence; handle->previousReleaseFences.clear(); FrameEventHistoryStats eventStats(handle->frameNumber, |