diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp index 8bee9c95277c3..36444102fb070 100644 --- a/core/jni/android_hardware_location_ContextHubService.cpp +++ b/core/jni/android_hardware_location_ContextHubService.cpp @@ -26,6 +26,10 @@ #include #include #include + +// TOOD: On master, alphabetize these and move into this +// grouping. +#include #include #include @@ -51,6 +55,10 @@ static constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE; static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1; static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2; +// Monotonically increasing clock we use to determine if we can cancel +// a transaction. +using std::chrono::steady_clock; + namespace android { namespace { @@ -107,6 +115,17 @@ struct app_instance_info_s { struct hub_app_info appInfo; // returned from the HAL }; + +// If a transaction takes longer than this, we'll allow it to be +// canceled by a new transaction. Note we do _not_ automatically +// cancel a transaction after this much time. We can have a +// legal transaction which takes longer than this amount of time, +// as long as no other new transactions are attempted after this +// time has expired. +// TODO(b/31105001): Establish a clean timing approach for all +// of our HAL interactions. +constexpr auto kMinTransactionCancelTime = std::chrono::seconds(29); + /* * TODO(ashutoshj): From original code review: * @@ -148,6 +167,7 @@ struct txnManager_s { std::mutex m; // mutex for manager hub_messages_e txnIdentifier; // What are we doing void *txnData; // Details + steady_clock::time_point firstTimeTxnCanBeCanceled; }; struct contextHubServiceDb_s { @@ -177,25 +197,40 @@ static int addTxn(hub_messages_e txnIdentifier, void *txnData) { std::lock_guardlock(mgr->m); mgr->txnPending = true; + mgr->firstTimeTxnCanBeCanceled = steady_clock::now() + + kMinTransactionCancelTime; mgr->txnData = txnData; mgr->txnIdentifier = txnIdentifier; return 0; } -static int closeTxn() { +// Only call this if you hold the db.txnManager.m lock. +static void closeTxnUnlocked() { txnManager_s *mgr = &db.txnManager; - std::lock_guardlock(mgr->m); mgr->txnPending = false; free(mgr->txnData); mgr->txnData = nullptr; +} +static int closeTxn() { + std::lock_guardlock(db.txnManager.m); + closeTxnUnlocked(); return 0; } +// If a transaction has been pending for longer than +// kMinTransactionCancelTime, this call will "cancel" that +// transaction and return that there are none pending. static bool isTxnPending() { txnManager_s *mgr = &db.txnManager; std::lock_guardlock(mgr->m); + if (mgr->txnPending) { + if (steady_clock::now() >= mgr->firstTimeTxnCanBeCanceled) { + ALOGW("Transaction canceled"); + closeTxnUnlocked(); + } + } return mgr->txnPending; }