-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Presently, the core of the Wifi test logic is obscured by the boilerplate required to create a callback. This CL provides some utilities to simplify the creation of a HIDL result callback, and migrates existing Wifi code to use the new utilities. Along the way: add a .clang-format file, so that I don't misformat code with 2-space indents (the Google default). Bug: 34817351 Test: vts-tradefed run commandAndExit vts --module=HalWifiHidlTargetTest Change-Id: Id2c728f96c3369c74adc8dfce7228b0a15a0781e
- Loading branch information
Showing
5 changed files
with
272 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
BasedOnStyle: Google | ||
IndentWidth: 4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* | ||
* Copyright (C) 2017 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 <functional> | ||
#include <tuple> | ||
#include <type_traits> | ||
#include <utility> | ||
|
||
#include <gtest/gtest.h> | ||
|
||
namespace { | ||
namespace detail { | ||
template <typename> | ||
struct functionArgSaver; | ||
|
||
// Provides a std::function that takes one argument, and a buffer | ||
// wherein the function will store its argument. The buffer has | ||
// the same type as the argument, but with const and reference | ||
// modifiers removed. | ||
template <typename ArgT> | ||
struct functionArgSaver<std::function<void(ArgT)>> final { | ||
using StorageT = typename std::remove_const< | ||
typename std::remove_reference<ArgT>::type>::type; | ||
|
||
std::function<void(ArgT)> saveArgs = [this](ArgT arg) { | ||
this->saved_values = arg; | ||
}; | ||
|
||
StorageT saved_values; | ||
}; | ||
|
||
// Provides a std::function that takes two arguments, and a buffer | ||
// wherein the function will store its arguments. The buffer is a | ||
// std::pair, whose elements have the same types as the arguments | ||
// (but with const and reference modifiers removed). | ||
template <typename Arg1T, typename Arg2T> | ||
struct functionArgSaver<std::function<void(Arg1T, Arg2T)>> final { | ||
using StorageT = | ||
std::pair<typename std::remove_const< | ||
typename std::remove_reference<Arg1T>::type>::type, | ||
typename std::remove_const< | ||
typename std::remove_reference<Arg2T>::type>::type>; | ||
|
||
std::function<void(Arg1T, Arg2T)> saveArgs = [this](Arg1T arg1, | ||
Arg2T arg2) { | ||
this->saved_values = {arg1, arg2}; | ||
}; | ||
|
||
StorageT saved_values; | ||
}; | ||
|
||
// Provides a std::function that takes three or more arguments, and a | ||
// buffer wherein the function will store its arguments. The buffer is a | ||
// std::tuple whose elements have the same types as the arguments (but | ||
// with const and reference modifiers removed). | ||
template <typename... ArgT> | ||
struct functionArgSaver<std::function<void(ArgT...)>> final { | ||
using StorageT = std::tuple<typename std::remove_const< | ||
typename std::remove_reference<ArgT>::type>::type...>; | ||
|
||
std::function<void(ArgT...)> saveArgs = [this](ArgT... arg) { | ||
this->saved_values = {arg...}; | ||
}; | ||
|
||
StorageT saved_values; | ||
}; | ||
|
||
// Invokes |method| on |object|, providing |method| a CallbackT as the | ||
// final argument. Returns a copy of the parameters that |method| provided | ||
// to CallbackT. (The parameters are returned by value.) | ||
template <typename CallbackT, typename MethodT, typename ObjectT, | ||
typename... ArgT> | ||
typename functionArgSaver<CallbackT>::StorageT invokeMethod( | ||
MethodT method, ObjectT object, ArgT&&... methodArg) { | ||
functionArgSaver<CallbackT> result_buffer; | ||
const auto& res = ((*object).*method)(std::forward<ArgT>(methodArg)..., | ||
result_buffer.saveArgs); | ||
EXPECT_TRUE(res.isOk()); | ||
return result_buffer.saved_values; | ||
} | ||
} // namespace detail | ||
} // namespace | ||
|
||
// Invokes |method| on |strong_pointer|, passing provided arguments through to | ||
// |method|. | ||
// | ||
// Returns either: | ||
// - A copy of the result callback parameter (for callbacks with a single | ||
// parameter), OR | ||
// - A pair containing a copy of the result callback parameters (for callbacks | ||
// with two parameters), OR | ||
// - A tuple containing a copy of the result callback paramters (for callbacks | ||
// with three or more parameters). | ||
// | ||
// Example usage: | ||
// EXPECT_EQ(WifiStatusCode::SUCCESS, | ||
// HIDL_INVOKE(strong_pointer, methodReturningWifiStatus).code); | ||
// EXPECT_EQ(WifiStatusCode::SUCCESS, | ||
// HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndOneMore) | ||
// .first.code); | ||
// EXPECT_EQ(WifiStatusCode::SUCCESS, std::get<0>( | ||
// HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndTwoMore)) | ||
// .code); | ||
#define HIDL_INVOKE(strong_pointer, method, ...) \ | ||
(detail::invokeMethod< \ | ||
std::remove_reference<decltype(*strong_pointer)>::type::method##_cb>( \ | ||
&std::remove_reference<decltype(*strong_pointer)>::type::method, \ | ||
strong_pointer, ##__VA_ARGS__)) |
114 changes: 114 additions & 0 deletions
114
wifi/1.0/vts/functional/wifi_hidl_call_util_selftest.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/* | ||
* Copyright (C) 2017 The Android Open Source Project | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include <functional> | ||
#include <type_traits> | ||
|
||
#include <hidl/Status.h> | ||
#include <utils/RefBase.h> | ||
#include <utils/StrongPointer.h> | ||
|
||
#include "wifi_hidl_call_util.h" | ||
|
||
namespace { | ||
/* | ||
* Example of a user-defined data-type. | ||
* | ||
* Used to verify that, within the internals of HIDL_INVOKE, | ||
* reference parameters are stored by copy. | ||
*/ | ||
class Dummy {}; | ||
|
||
/* | ||
* Example of what a HIDL-generated proxy might look like. | ||
*/ | ||
class IExample : public ::android::RefBase { | ||
public: | ||
// The callback type, for a method called startWithCallbackCopy, which | ||
// has a callback that takes an |int|. Both the name, and the value, | ||
// must match what would appear in HIDL-generated code. | ||
using startWithCallbackCopy_cb = std::function<void(int)>; | ||
|
||
// The callback type, for a method called startWithCallbackReference, which | ||
// has a callback that takes an |int|. Both the name, and the value, | ||
// must match what would appear in HIDL-generated code. | ||
using startWithCallbackReference_cb = std::function<void(int)>; | ||
|
||
// Constants which allow tests to verify that the proxy methods can | ||
// correctly return a value. We use different values for by-copy and | ||
// by-reference, to double-check that a call was dispatched properly. | ||
static constexpr int kByCopyResult = 42; | ||
static constexpr int kByReferenceResult = 420; | ||
|
||
// Example of what a no-arg method would look like, if the callback | ||
// is passed by-value. | ||
::android::hardware::Return<void> startWithCallbackCopy( | ||
startWithCallbackCopy_cb _hidl_cb) { | ||
_hidl_cb(kByCopyResult); | ||
return ::android::hardware::Void(); | ||
} | ||
// Example of what a no-arg method would look like, if the callback | ||
// is passed by const-reference. | ||
::android::hardware::Return<void> startWithCallbackReference( | ||
const startWithCallbackReference_cb& _hidl_cb) { | ||
_hidl_cb(kByReferenceResult); | ||
return ::android::hardware::Void(); | ||
} | ||
}; | ||
|
||
constexpr int IExample::kByCopyResult; | ||
constexpr int IExample::kByReferenceResult; | ||
} // namespace | ||
|
||
static_assert(std::is_same<int, detail::functionArgSaver< | ||
std::function<void(int)>>::StorageT>::value, | ||
"Single-arg result should be stored directly."); | ||
|
||
static_assert( | ||
std::is_same<std::pair<int, long>, detail::functionArgSaver<std::function< | ||
void(int, long)>>::StorageT>::value, | ||
"Two-arg result should be stored as a pair."); | ||
|
||
static_assert( | ||
std::is_same<std::tuple<char, int, long>, | ||
detail::functionArgSaver< | ||
std::function<void(char, int, long)>>::StorageT>::value, | ||
"Three-arg result should be stored as a tuple."); | ||
|
||
static_assert(std::is_same<Dummy, detail::functionArgSaver<std::function< | ||
void(const Dummy&)>>::StorageT>::value, | ||
"Reference should be stored by copy."); | ||
|
||
/* | ||
* Verifies that HIDL_INVOKE can be used with methods that take the result | ||
* callback as a by-value parameter. (This reflects the current implementation | ||
* of HIDL-generated code.) | ||
*/ | ||
TEST(HidlInvokeTest, WorksWithMethodThatTakesResultCallbackByValue) { | ||
::android::sp<IExample> sp = new IExample(); | ||
EXPECT_EQ(IExample::kByCopyResult, HIDL_INVOKE(sp, startWithCallbackCopy)); | ||
} | ||
|
||
/* | ||
* Verifies that HIDL_INVOKE can be used with methods that take the result | ||
* callback as a const-reference parameter. (This ensures that HIDL_INVOKE will | ||
* continue to work, if the HIDL-generated code switches to const-ref.) | ||
*/ | ||
TEST(HidlInvokeTest, WorksWithMethodThatTakesResultCallbackByConstReference) { | ||
::android::sp<IExample> sp = new IExample(); | ||
EXPECT_EQ(IExample::kByReferenceResult, | ||
HIDL_INVOKE(sp, startWithCallbackReference)); | ||
} |
Oops, something went wrong.