1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef __VTS_HAL_HIDL_TARGET_CALLBACK_BASE_H 18 #define __VTS_HAL_HIDL_TARGET_CALLBACK_BASE_H 19 20 #include <chrono> 21 #include <condition_variable> 22 #include <iostream> 23 #include <mutex> 24 #include <queue> 25 #include <unordered_map> 26 #include <utility> 27 28 using namespace ::std; 29 using namespace ::std::chrono; 30 31 constexpr char kVtsHalHidlTargetCallbackDefaultName[] = 32 "VtsHalHidlTargetCallbackDefaultName"; 33 constexpr milliseconds DEFAULT_CALLBACK_WAIT_TIMEOUT_INITIAL = minutes(1); 34 35 namespace testing { 36 37 /* 38 * VTS target side test template for callback. 39 * 40 * Providing wait and notify for callback functionality. 41 * 42 * A typical usage looks like this: 43 * 44 * class CallbackArgs { 45 * ArgType1 arg1; 46 * ArgType2 arg2; 47 * } 48 * 49 * class MyCallback 50 * : public ::testing::VtsHalHidlTargetCallbackBase<>, 51 * public CallbackInterface { 52 * public: 53 * CallbackApi1(ArgType1 arg1) { 54 * CallbackArgs data; 55 * data.arg1 = arg1; 56 * NotifyFromCallback("CallbackApi1", data); 57 * } 58 * 59 * CallbackApi2(ArgType2 arg2) { 60 * CallbackArgs data; 61 * data.arg1 = arg1; 62 * NotifyFromCallback("CallbackApi2", data); 63 * } 64 * } 65 * 66 * Test(MyTest) { 67 * CallApi1(); 68 * CallApi2(); 69 * auto result = cb_.WaitForCallback("CallbackApi1"); 70 * // cb_ as an instance of MyCallback, result is an instance of 71 * // ::testing::VtsHalHidlTargetCallbackBase::WaitForCallbackResult 72 * EXPECT_TRUE(result.no_timeout); // Check wait did not time out 73 * EXPECT_TRUE(result.args); // Check CallbackArgs is received (not 74 * nullptr). This is optional. 75 * // Here check value of args using the pointer result.args; 76 * result = cb_.WaitForCallback("CallbackApi2"); 77 * EXPECT_TRUE(result.no_timeout); 78 * // Here check value of args using the pointer result.args; 79 * 80 * // Additionally. a test can wait for one of multiple callbacks. 81 * // In this case, wait will return when any of the callbacks in the provided 82 * // name list is called. 83 * result = cb_.WaitForCallbackAny(<vector_of_string>) 84 * // When vector_of_string is not provided, all callback functions will 85 * // be monitored. The name of callback function that was invoked 86 * // is stored in result.name 87 * } 88 * 89 * Note type of CallbackArgsTemplateClass is same across the class, which means 90 * all WaitForCallback method will return the same data type. 91 */ 92 template <class CallbackArgsTemplateClass> 93 class VtsHalHidlTargetCallbackBase { 94 public: 95 struct WaitForCallbackResult { WaitForCallbackResultWaitForCallbackResult96 WaitForCallbackResult() 97 : no_timeout(false), 98 args(shared_ptr<CallbackArgsTemplateClass>(nullptr)), 99 name("") {} 100 101 // Whether the wait timed out 102 bool no_timeout; 103 // Arguments data from callback functions. Defaults to nullptr. 104 shared_ptr<CallbackArgsTemplateClass> args; 105 // Name of the callback. Defaults to empty string. 106 string name; 107 }; 108 VtsHalHidlTargetCallbackBase()109 VtsHalHidlTargetCallbackBase() 110 : cb_default_wait_timeout_(DEFAULT_CALLBACK_WAIT_TIMEOUT_INITIAL) {} 111 ~VtsHalHidlTargetCallbackBase()112 virtual ~VtsHalHidlTargetCallbackBase() { 113 for (auto it : cb_lock_map_) { 114 delete it.second; 115 } 116 } 117 118 /* 119 * Wait for a callback function in a test. 120 * Returns a WaitForCallbackResult object containing wait results. 121 * If callback_function_name is not provided, a default name will be used. 122 * Timeout defaults to -1 milliseconds. Negative timeout means use to 123 * use the time out set for the callback or default callback wait time out. 124 */ 125 WaitForCallbackResult WaitForCallback( 126 const string& callback_function_name = 127 kVtsHalHidlTargetCallbackDefaultName, 128 milliseconds timeout = milliseconds(-1)) { 129 return GetCallbackLock(callback_function_name)->WaitForCallback(timeout); 130 } 131 132 /* 133 * Wait for any of the callback functions specified. 134 * Returns a WaitForCallbackResult object containing wait results. 135 * If callback_function_names is not provided, all callback functions will 136 * be monitored, and the list of callback functions will be updated 137 * dynamically during run time. 138 * If timeout_any is not provided, the shortest timeout from the function 139 * list will be used. 140 */ 141 WaitForCallbackResult WaitForCallbackAny( 142 const vector<string>& callback_function_names = vector<string>(), 143 milliseconds timeout_any = milliseconds(-1)) { 144 unique_lock<mutex> lock(cb_wait_any_mtx_); 145 146 auto start_time = steady_clock::now(); 147 148 WaitForCallbackResult res = PeekCallbackLocks(callback_function_names); 149 while (!res.no_timeout) { 150 auto expiration = 151 GetWaitAnyTimeout(callback_function_names, start_time, timeout_any); 152 auto status = cb_wait_any_cv_.wait_until(lock, expiration); 153 if (status == cv_status::timeout) { 154 cerr << "Timed out waiting for callback functions." << endl; 155 break; 156 } 157 res = PeekCallbackLocks(callback_function_names); 158 } 159 return res; 160 } 161 162 /* 163 * Notify a waiting test when a callback is invoked. 164 * If callback_function_name is not provided, a default name will be used. 165 */ 166 void NotifyFromCallback(const string& callback_function_name = 167 kVtsHalHidlTargetCallbackDefaultName) { 168 unique_lock<mutex> lock(cb_wait_any_mtx_); 169 GetCallbackLock(callback_function_name)->NotifyFromCallback(); 170 cb_wait_any_cv_.notify_one(); 171 } 172 173 /* 174 * Notify a waiting test with data when a callback is invoked. 175 */ NotifyFromCallback(const CallbackArgsTemplateClass & data)176 void NotifyFromCallback(const CallbackArgsTemplateClass& data) { 177 NotifyFromCallback(kVtsHalHidlTargetCallbackDefaultName, data); 178 } 179 180 /* 181 * Notify a waiting test with data when a callback is invoked. 182 * If callback_function_name is not provided, a default name will be used. 183 */ NotifyFromCallback(const string & callback_function_name,const CallbackArgsTemplateClass & data)184 void NotifyFromCallback(const string& callback_function_name, 185 const CallbackArgsTemplateClass& data) { 186 unique_lock<mutex> lock(cb_wait_any_mtx_); 187 GetCallbackLock(callback_function_name)->NotifyFromCallback(data); 188 cb_wait_any_cv_.notify_one(); 189 } 190 191 /* 192 * Clear lock and data for a callback function. 193 * This function is optional. 194 */ 195 void ClearForCallback(const string& callback_function_name = 196 kVtsHalHidlTargetCallbackDefaultName) { 197 GetCallbackLock(callback_function_name, true); 198 } 199 200 /* 201 * Get wait timeout for a specific callback function. 202 * If callback_function_name is not provided, a default name will be used. 203 */ 204 milliseconds GetWaitTimeout(const string& callback_function_name = 205 kVtsHalHidlTargetCallbackDefaultName) { 206 return GetCallbackLock(callback_function_name)->GetWaitTimeout(); 207 } 208 209 /* 210 * Set wait timeout for a specific callback function. 211 * To set a default timeout (not for the default function name), 212 * use SetWaitTimeoutDefault. default function name callback timeout will 213 * also be set by SetWaitTimeoutDefault. 214 */ SetWaitTimeout(const string & callback_function_name,milliseconds timeout)215 void SetWaitTimeout(const string& callback_function_name, 216 milliseconds timeout) { 217 GetCallbackLock(callback_function_name)->SetWaitTimeout(timeout); 218 } 219 220 /* 221 * Get default wait timeout for a callback function. 222 * The default timeout is valid for all callback function names that 223 * have not been specified a timeout value, including default function name. 224 */ GetWaitTimeoutDefault()225 milliseconds GetWaitTimeoutDefault() { return cb_default_wait_timeout_; } 226 227 /* 228 * Set default wait timeout for a callback function. 229 * The default timeout is valid for all callback function names that 230 * have not been specified a timeout value, including default function name. 231 */ SetWaitTimeoutDefault(milliseconds timeout)232 void SetWaitTimeoutDefault(milliseconds timeout) { 233 cb_default_wait_timeout_ = timeout; 234 } 235 236 private: 237 /* 238 * A utility class to store semaphore and data for a callback name. 239 */ 240 class CallbackLock { 241 public: CallbackLock(VtsHalHidlTargetCallbackBase & parent,const string & name)242 CallbackLock(VtsHalHidlTargetCallbackBase& parent, const string& name) 243 : wait_count_(0), 244 parent_(parent), 245 timeout_(milliseconds(-1)), 246 name_(name) {} 247 248 /* 249 * Wait for represented callback function. 250 * Timeout defaults to -1 milliseconds. Negative timeout means use to 251 * use the time out set for the callback or default callback wait time out. 252 */ 253 WaitForCallbackResult WaitForCallback( 254 milliseconds timeout = milliseconds(-1), 255 bool no_wait_blocking = false) { 256 return Wait(timeout, no_wait_blocking); 257 } 258 259 /* 260 * Wait for represented callback function. 261 * Timeout defaults to -1 milliseconds. Negative timeout means use to 262 * use the time out set for the callback or default callback wait time out. 263 */ WaitForCallback(bool no_wait_blocking)264 WaitForCallbackResult WaitForCallback(bool no_wait_blocking) { 265 return Wait(milliseconds(-1), no_wait_blocking); 266 } 267 268 /* Notify from represented callback function. */ NotifyFromCallback()269 void NotifyFromCallback() { 270 unique_lock<mutex> lock(wait_mtx_); 271 Notify(); 272 } 273 274 /* Notify from represented callback function with data. */ NotifyFromCallback(const CallbackArgsTemplateClass & data)275 void NotifyFromCallback(const CallbackArgsTemplateClass& data) { 276 unique_lock<mutex> wait_lock(wait_mtx_); 277 arg_data_.push(make_shared<CallbackArgsTemplateClass>(data)); 278 Notify(); 279 } 280 281 /* Set wait timeout for represented callback function. */ SetWaitTimeout(milliseconds timeout)282 void SetWaitTimeout(milliseconds timeout) { timeout_ = timeout; } 283 284 /* Get wait timeout for represented callback function. */ GetWaitTimeout()285 milliseconds GetWaitTimeout() { 286 if (timeout_ < milliseconds(0)) { 287 return parent_.GetWaitTimeoutDefault(); 288 } 289 return timeout_; 290 } 291 292 private: 293 /* 294 * Wait for represented callback function in a test. 295 * Returns a WaitForCallbackResult object containing wait results. 296 * Timeout defaults to -1 milliseconds. Negative timeout means use to 297 * use the time out set for the callback or default callback wait time out. 298 */ Wait(milliseconds timeout,bool no_wait_blocking)299 WaitForCallbackResult Wait(milliseconds timeout, bool no_wait_blocking) { 300 unique_lock<mutex> lock(wait_mtx_); 301 WaitForCallbackResult res; 302 res.name = name_; 303 if (!no_wait_blocking) { 304 if (timeout < milliseconds(0)) { 305 timeout = GetWaitTimeout(); 306 } 307 auto expiration = steady_clock::now() + timeout; 308 while (wait_count_ == 0) { 309 auto status = wait_cv_.wait_until(lock, expiration); 310 if (status == cv_status::timeout) { 311 cerr << "Timed out waiting for callback" << endl; 312 return res; 313 } 314 } 315 } else if (!wait_count_) { 316 return res; 317 } 318 319 wait_count_--; 320 res.no_timeout = true; 321 if (!arg_data_.empty()) { 322 res.args = arg_data_.front(); 323 arg_data_.pop(); 324 } 325 return res; 326 } 327 328 /* Notify from represented callback function. */ Notify()329 void Notify() { 330 wait_count_++; 331 wait_cv_.notify_one(); 332 } 333 334 // Mutex for protecting operations on wait count and conditional variable 335 mutex wait_mtx_; 336 // Conditional variable for callback wait and notify 337 condition_variable wait_cv_; 338 // Count for callback conditional variable 339 unsigned int wait_count_; 340 // A queue of callback arg data 341 queue<shared_ptr<CallbackArgsTemplateClass>> arg_data_; 342 // Pointer to parent class 343 VtsHalHidlTargetCallbackBase& parent_; 344 // Wait time out 345 milliseconds timeout_; 346 // Name of the represented callback function 347 string name_; 348 }; 349 350 /* 351 * Get CallbackLock object using callback function name. 352 * If callback_function_name is not provided, a default name will be used. 353 * If callback_function_name does not exists in map yet, a new CallbackLock 354 * object will be created. 355 * If auto_clear is true, the old CallbackLock will be deleted. 356 */ 357 CallbackLock* GetCallbackLock(const string& callback_function_name, 358 bool auto_clear = false) { 359 unique_lock<mutex> lock(cb_lock_map_mtx_); 360 auto found = cb_lock_map_.find(callback_function_name); 361 if (found == cb_lock_map_.end()) { 362 CallbackLock* result = new CallbackLock(*this, callback_function_name); 363 cb_lock_map_.insert({callback_function_name, result}); 364 return result; 365 } else { 366 if (auto_clear) { 367 delete (found->second); 368 found->second = new CallbackLock(*this, callback_function_name); 369 } 370 return found->second; 371 } 372 } 373 374 /* 375 * Get wait timeout for a list of function names. 376 * If timeout_any is not negative, start_time + timeout_any will be returned. 377 * Otherwise, the shortest timeout from the list will be returned. 378 */ GetWaitAnyTimeout(const vector<string> & callback_function_names,steady_clock::time_point start_time,milliseconds timeout_any)379 steady_clock::time_point GetWaitAnyTimeout( 380 const vector<string>& callback_function_names, 381 steady_clock::time_point start_time, milliseconds timeout_any) { 382 if (timeout_any >= milliseconds(0)) { 383 return start_time + timeout_any; 384 } 385 386 auto locks = GetWaitAnyCallbackLocks(callback_function_names); 387 388 auto timeout_min = steady_clock::duration::max(); 389 for (auto lock : locks) { 390 auto timeout = lock->GetWaitTimeout(); 391 if (timeout < timeout_min) { 392 timeout_min = timeout; 393 } 394 } 395 396 return start_time + timeout_min; 397 } 398 399 /* 400 * Get a list of CallbackLock pointers from provided function name list. 401 */ GetWaitAnyCallbackLocks(const vector<string> & callback_function_names)402 vector<CallbackLock*> GetWaitAnyCallbackLocks( 403 const vector<string>& callback_function_names) { 404 vector<CallbackLock*> res; 405 if (callback_function_names.empty()) { 406 for (auto const& it : cb_lock_map_) { 407 res.push_back(it.second); 408 } 409 } else { 410 for (auto const& name : callback_function_names) { 411 res.push_back(GetCallbackLock(name)); 412 } 413 } 414 return res; 415 } 416 417 /* 418 * Peek into the list of callback locks to check whether any of the 419 * callback functions has been called. 420 */ PeekCallbackLocks(const vector<string> & callback_function_names)421 WaitForCallbackResult PeekCallbackLocks( 422 const vector<string>& callback_function_names) { 423 auto locks = GetWaitAnyCallbackLocks(callback_function_names); 424 for (auto lock : locks) { 425 auto test = lock->WaitForCallback(true); 426 if (test.no_timeout) { 427 return test; 428 } 429 } 430 WaitForCallbackResult res; 431 return res; 432 } 433 434 // A map of function name and CallbackLock object pointers 435 unordered_map<string, CallbackLock*> cb_lock_map_; 436 // Mutex for protecting operations on lock map 437 mutex cb_lock_map_mtx_; 438 // Mutex for protecting waiting any callback 439 mutex cb_wait_any_mtx_; 440 // Default wait timeout 441 milliseconds cb_default_wait_timeout_; 442 // Conditional variable for any callback notify 443 condition_variable cb_wait_any_cv_; 444 }; 445 446 } // namespace testing 447 448 #endif // __VTS_HAL_HIDL_TARGET_CALLBACK_BASE_H 449