blob: ec9123a57017be4d7139071be95f30e59ae83aa9 [file] [log] [blame]
Martijn Coenen72110162016-08-19 14:28:25 +02001/*
2 * Copyright (C) 2016 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 ANDROID_HIDL_SUPPORT_H
18#define ANDROID_HIDL_SUPPORT_H
19
Iliyan Malchev692070a2016-09-12 16:30:44 -070020#include <algorithm>
Zhuoyao Zhang7e1286c2016-09-12 17:28:48 -070021#include <dirent.h>
Steven Morelandbdf26662016-09-02 11:03:15 -070022#include <dlfcn.h>
Zhuoyao Zhang28e03af2016-10-21 11:25:49 -070023#include <cutils/properties.h>
Martijn Coenen72110162016-08-19 14:28:25 +020024#include <hwbinder/Parcel.h>
Andreas Huber00a985c2016-09-28 14:24:53 -070025#include <tuple>
Iliyan Malchev692070a2016-09-12 16:30:44 -070026#include <utils/Errors.h>
27#include <utils/RefBase.h>
28#include <utils/StrongPointer.h>
Martijn Coenen72110162016-08-19 14:28:25 +020029
30namespace android {
31namespace hardware {
32
33struct hidl_string {
34 hidl_string();
35 ~hidl_string();
36
37 hidl_string(const hidl_string &);
38 hidl_string &operator=(const hidl_string &);
39
40 const char *c_str() const;
41 size_t size() const;
42 bool empty() const;
43
44 hidl_string &operator=(const char *s);
45 void clear();
46
47 // Reference an external char array. Ownership is _not_ transferred.
48 // Caller is responsible for ensuring that underlying memory is valid
49 // for the lifetime of this hidl_string.
50 void setToExternal(const char *data, size_t size);
51
52 status_t readEmbeddedFromParcel(
53 const Parcel &parcel, size_t parentHandle, size_t parentOffset);
54
55 status_t writeEmbeddedToParcel(
56 Parcel *parcel, size_t parentHandle, size_t parentOffset) const;
57
Andreas Huberebfeb362016-08-25 13:39:05 -070058 // offsetof(hidl_string, mBuffer) exposed since mBuffer is private.
59 static const size_t kOffsetOfBuffer;
60
Martijn Coenen72110162016-08-19 14:28:25 +020061private:
62 char *mBuffer;
63 size_t mSize; // NOT including the terminating '\0'.
64 bool mOwnsBuffer;
65
66 hidl_string &setTo(const char *data, size_t size);
67};
68
Andreas Huber20dce082016-09-22 19:39:13 -070069////////////////////////////////////////////////////////////////////////////////
70
Martijn Coenen72110162016-08-19 14:28:25 +020071template<typename T>
72struct hidl_vec {
73 hidl_vec()
74 : mBuffer(NULL),
75 mSize(0),
76 mOwnsBuffer(true) {
77 }
78
79 hidl_vec(const hidl_vec<T> &other)
80 : mBuffer(NULL),
81 mSize(0),
82 mOwnsBuffer(true) {
83 *this = other;
84 }
85
Alexey Polyudov0ebdbe82016-10-18 09:31:46 -070086 hidl_vec(hidl_vec<T> &&other) {
87 *this = static_cast<hidl_vec &&>(other);
88 }
89
Martijn Coenen72110162016-08-19 14:28:25 +020090 ~hidl_vec() {
91 if (mOwnsBuffer) {
92 delete[] mBuffer;
93 }
94 mBuffer = NULL;
95 }
96
Alexey Polyudove2299012016-10-19 09:52:00 -070097 // Reference an existing array, optionally taking ownership. It is the
Martijn Coenen72110162016-08-19 14:28:25 +020098 // caller's responsibility to ensure that the underlying memory stays
99 // valid for the lifetime of this hidl_vec.
Alexey Polyudove2299012016-10-19 09:52:00 -0700100 void setToExternal(T *data, size_t size, bool shouldOwn = false) {
Martijn Coenen72110162016-08-19 14:28:25 +0200101 if (mOwnsBuffer) {
102 delete [] mBuffer;
103 }
104 mBuffer = data;
105 mSize = size;
Alexey Polyudove2299012016-10-19 09:52:00 -0700106 mOwnsBuffer = shouldOwn;
Martijn Coenen72110162016-08-19 14:28:25 +0200107 }
108
Alexey Polyudov6f0c9a12016-10-18 09:37:35 -0700109 T *data() {
110 return mBuffer;
111 }
112
113 const T *data() const {
114 return mBuffer;
115 }
116
Alexey Polyudovc98a99c2016-10-18 09:43:56 -0700117 T *releaseData() {
118 if (!mOwnsBuffer && mSize > 0) {
119 resize(mSize);
120 }
121 mOwnsBuffer = false;
122 return mBuffer;
123 }
124
Alexey Polyudov0ebdbe82016-10-18 09:31:46 -0700125 hidl_vec &operator=(hidl_vec &&other) {
126 mBuffer = other.mBuffer;
127 mSize = other.mSize;
128 mOwnsBuffer = other.mOwnsBuffer;
129 other.mOwnsBuffer = false;
130 return *this;
131 }
132
Martijn Coenen72110162016-08-19 14:28:25 +0200133 hidl_vec &operator=(const hidl_vec &other) {
134 if (this != &other) {
135 if (mOwnsBuffer) {
136 delete[] mBuffer;
137 }
138 mBuffer = NULL;
139 mSize = other.mSize;
140 mOwnsBuffer = true;
141 if (mSize > 0) {
142 mBuffer = new T[mSize];
143 for (size_t i = 0; i < mSize; ++i) {
144 mBuffer[i] = other.mBuffer[i];
145 }
146 }
147 }
148
149 return *this;
150 }
151
152 size_t size() const {
153 return mSize;
154 }
155
156 T &operator[](size_t index) {
157 return mBuffer[index];
158 }
159
160 const T &operator[](size_t index) const {
161 return mBuffer[index];
162 }
163
164 void resize(size_t size) {
165 T *newBuffer = new T[size];
166
167 for (size_t i = 0; i < std::min(size, mSize); ++i) {
168 newBuffer[i] = mBuffer[i];
169 }
170
171 if (mOwnsBuffer) {
172 delete[] mBuffer;
173 }
174 mBuffer = newBuffer;
175
176 mSize = size;
177 mOwnsBuffer = true;
178 }
179
180 status_t readEmbeddedFromParcel(
181 const Parcel &parcel,
182 size_t parentHandle,
183 size_t parentOffset,
184 size_t *handle);
185
186 status_t writeEmbeddedToParcel(
187 Parcel *parcel,
188 size_t parentHandle,
189 size_t parentOffset,
190 size_t *handle) const;
191
Yifan Hongb1d8d4c2016-08-23 17:39:06 -0700192 status_t findInParcel(const Parcel &parcel, size_t *handle) const {
193 return parcel.quickFindBuffer(mBuffer, handle);
194 }
195
196
Martijn Coenen72110162016-08-19 14:28:25 +0200197private:
198 T *mBuffer;
199 size_t mSize;
200 bool mOwnsBuffer;
201};
202
Andreas Huber20dce082016-09-22 19:39:13 -0700203////////////////////////////////////////////////////////////////////////////////
204
205namespace details {
206
207 template<size_t SIZE1, size_t... SIZES>
208 struct product {
209 static constexpr size_t value = SIZE1 * product<SIZES...>::value;
210 };
211
212 template<size_t SIZE1>
213 struct product<SIZE1> {
214 static constexpr size_t value = SIZE1;
215 };
216
217 template<typename T, size_t SIZE1, size_t... SIZES>
218 struct accessor {
219 explicit accessor(T *base)
220 : mBase(base) {
221 }
222
223 accessor<T, SIZES...> operator[](size_t index) {
224 return accessor<T, SIZES...>(
225 &mBase[index * product<SIZES...>::value]);
226 }
227
228 private:
229 T *mBase;
230 };
231
232 template<typename T, size_t SIZE1>
233 struct accessor<T, SIZE1> {
234 explicit accessor(T *base)
235 : mBase(base) {
236 }
237
238 T &operator[](size_t index) {
239 return mBase[index];
240 }
241
242 private:
243 T *mBase;
244 };
245
246 template<typename T, size_t SIZE1, size_t... SIZES>
247 struct const_accessor {
248 explicit const_accessor(const T *base)
249 : mBase(base) {
250 }
251
252 const_accessor<T, SIZES...> operator[](size_t index) {
253 return const_accessor<T, SIZES...>(
254 &mBase[index * product<SIZES...>::value]);
255 }
256
257 private:
258 const T *mBase;
259 };
260
261 template<typename T, size_t SIZE1>
262 struct const_accessor<T, SIZE1> {
263 explicit const_accessor(const T *base)
264 : mBase(base) {
265 }
266
267 const T &operator[](size_t index) const {
268 return mBase[index];
269 }
270
271 private:
272 const T *mBase;
273 };
274
275} // namespace details
276
277////////////////////////////////////////////////////////////////////////////////
278
279template<typename T, size_t SIZE1, size_t... SIZES>
280struct hidl_array {
281 hidl_array() = default;
282
283 T *data() { return mBuffer; }
284 const T *data() const { return mBuffer; }
285
286 details::accessor<T, SIZES...> operator[](size_t index) {
287 return details::accessor<T, SIZES...>(
288 &mBuffer[index * details::product<SIZES...>::value]);
289 }
290
291 details::const_accessor<T, SIZES...> operator[](size_t index) const {
292 return details::const_accessor<T, SIZES...>(
293 &mBuffer[index * details::product<SIZES...>::value]);
294 }
295
Andreas Huber00a985c2016-09-28 14:24:53 -0700296 using size_tuple_type = std::tuple<decltype(SIZE1), decltype(SIZES)...>;
297
298 static constexpr size_tuple_type size() {
299 return std::make_tuple(SIZE1, SIZES...);
300 }
301
Andreas Huber20dce082016-09-22 19:39:13 -0700302private:
303 T mBuffer[details::product<SIZE1, SIZES...>::value];
304};
305
306template<typename T, size_t SIZE1>
307struct hidl_array<T, SIZE1> {
308 hidl_array() = default;
309
310 T *data() { return mBuffer; }
311 const T *data() const { return mBuffer; }
312
313 T &operator[](size_t index) {
314 return mBuffer[index];
315 }
316
317 const T &operator[](size_t index) const {
318 return mBuffer[index];
319 }
320
Andreas Huber00a985c2016-09-28 14:24:53 -0700321 static constexpr size_t size() { return SIZE1; }
322
Andreas Huber20dce082016-09-22 19:39:13 -0700323private:
324 T mBuffer[SIZE1];
325};
326
327////////////////////////////////////////////////////////////////////////////////
328
Martijn Coenen72110162016-08-19 14:28:25 +0200329template<typename T>
330status_t hidl_vec<T>::readEmbeddedFromParcel(
331 const Parcel &parcel,
332 size_t parentHandle,
333 size_t parentOffset,
334 size_t *handle) {
335 const void *ptr = parcel.readEmbeddedBuffer(
336 handle,
337 parentHandle,
338 parentOffset + offsetof(hidl_vec<T>, mBuffer));
339
340 return ptr != NULL ? OK : UNKNOWN_ERROR;
341}
342
343template<typename T>
344status_t hidl_vec<T>::writeEmbeddedToParcel(
345 Parcel *parcel,
346 size_t parentHandle,
347 size_t parentOffset,
348 size_t *handle) const {
349 return parcel->writeEmbeddedBuffer(
350 mBuffer,
351 sizeof(T) * mSize,
352 handle,
353 parentHandle,
354 parentOffset + offsetof(hidl_vec<T>, mBuffer));
355}
356
Yifan Hongb1d8d4c2016-08-23 17:39:06 -0700357///////////////////////////// pointers for HIDL
358
359template <typename T>
360static status_t readEmbeddedReferenceFromParcel(
361 T const* * /* bufptr */,
362 const Parcel & parcel,
363 size_t parentHandle,
364 size_t parentOffset,
365 size_t *handle,
366 bool *shouldResolveRefInBuffer
367 ) {
368 // *bufptr is ignored because, if I am embedded in some
369 // other buffer, the kernel should have fixed me up already.
370 bool isPreviouslyWritten;
371 status_t result = parcel.readEmbeddedReference(
372 nullptr, // ignored, not written to bufptr.
373 handle,
374 parentHandle,
375 parentOffset,
376 &isPreviouslyWritten);
377 // tell caller to run T::readEmbeddedToParcel and
378 // T::readEmbeddedReferenceToParcel if necessary.
379 // It is not called here because we don't know if these two are valid methods.
380 *shouldResolveRefInBuffer = !isPreviouslyWritten;
381 return result;
382}
383
384template <typename T>
385static status_t writeEmbeddedReferenceToParcel(
386 T const* buf,
387 Parcel *parcel, size_t parentHandle, size_t parentOffset,
388 size_t *handle,
389 bool *shouldResolveRefInBuffer
390 ) {
391
392 if(buf == nullptr) {
393 *shouldResolveRefInBuffer = false;
394 return parcel->writeEmbeddedNullReference(handle, parentHandle, parentOffset);
395 }
396
397 // find whether the buffer exists
398 size_t childHandle, childOffset;
399 status_t result;
400 bool found;
401
402 result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset);
403
404 // tell caller to run T::writeEmbeddedToParcel and
405 // T::writeEmbeddedReferenceToParcel if necessary.
406 // It is not called here because we don't know if these two are valid methods.
407 *shouldResolveRefInBuffer = !found;
408
409 if(result != OK) {
410 return result; // bad pointers and length given
411 }
412 if(!found) { // did not find it.
413 return parcel->writeEmbeddedBuffer(buf, sizeof(T), handle,
414 parentHandle, parentOffset);
415 }
416 // found the buffer. easy case.
417 return parcel->writeEmbeddedReference(
418 handle,
419 childHandle,
420 childOffset,
421 parentHandle,
422 parentOffset);
423}
424
425template <typename T>
426static status_t readReferenceFromParcel(
427 T const* *bufptr,
428 const Parcel & parcel,
429 size_t *handle,
430 bool *shouldResolveRefInBuffer
431 ) {
432 bool isPreviouslyWritten;
433 status_t result = parcel.readReference(reinterpret_cast<void const* *>(bufptr),
434 handle, &isPreviouslyWritten);
435 // tell caller to run T::readEmbeddedToParcel and
436 // T::readEmbeddedReferenceToParcel if necessary.
437 // It is not called here because we don't know if these two are valid methods.
438 *shouldResolveRefInBuffer = !isPreviouslyWritten;
439 return result;
440}
441
442template <typename T>
443static status_t writeReferenceToParcel(
444 T const *buf,
445 Parcel * parcel,
446 size_t *handle,
447 bool *shouldResolveRefInBuffer
448 ) {
449
450 if(buf == nullptr) {
451 *shouldResolveRefInBuffer = false;
452 return parcel->writeNullReference(handle);
453 }
454
455 // find whether the buffer exists
456 size_t childHandle, childOffset;
457 status_t result;
458 bool found;
459
460 result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset);
461
462 // tell caller to run T::writeEmbeddedToParcel and
463 // T::writeEmbeddedReferenceToParcel if necessary.
464 // It is not called here because we don't know if these two are valid methods.
465 *shouldResolveRefInBuffer = !found;
466
467 if(result != OK) {
468 return result; // bad pointers and length given
469 }
470 if(!found) { // did not find it.
471 return parcel->writeBuffer(buf, sizeof(T), handle);
472 }
473 // found the buffer. easy case.
474 return parcel->writeReference(handle,
475 childHandle, childOffset);
476}
477
Martijn Coenen72110162016-08-19 14:28:25 +0200478// ----------------------------------------------------------------------
479// Version functions
480struct hidl_version {
481public:
Chia-I Wu666b76b2016-10-06 14:15:59 +0800482 constexpr hidl_version(uint16_t major, uint16_t minor) : mMajor(major), mMinor(minor) {}
Martijn Coenen72110162016-08-19 14:28:25 +0200483
484 bool operator==(const hidl_version& other) {
485 return (mMajor == other.get_major() && mMinor == other.get_minor());
486 }
Martijn Coenenc28f1152016-08-22 14:06:56 +0200487
Martijn Coenen097a7672016-09-08 16:56:41 +0200488 constexpr uint16_t get_major() const { return mMajor; }
489 constexpr uint16_t get_minor() const { return mMinor; }
Martijn Coenen72110162016-08-19 14:28:25 +0200490
491 android::status_t writeToParcel(android::hardware::Parcel& parcel) const {
Chia-I Wu666b76b2016-10-06 14:15:59 +0800492 return parcel.writeUint32(static_cast<uint32_t>(mMajor) << 16 | mMinor);
Martijn Coenen72110162016-08-19 14:28:25 +0200493 }
494
495 static hidl_version* readFromParcel(const android::hardware::Parcel& parcel) {
496 uint32_t version;
497 android::status_t status = parcel.readUint32(&version);
498 if (status != OK) {
499 return nullptr;
500 } else {
501 return new hidl_version(version >> 16, version & 0xFFFF);
502 }
503 }
504
505private:
506 uint16_t mMajor;
507 uint16_t mMinor;
508};
509
510inline android::hardware::hidl_version make_hidl_version(uint16_t major, uint16_t minor) {
511 return hidl_version(major,minor);
512}
513
Steven Morelandbdf26662016-09-02 11:03:15 -0700514#if defined(__LP64__)
515#define HAL_LIBRARY_PATH_SYSTEM "/system/lib64/hw/"
516#define HAL_LIBRARY_PATH_VENDOR "/vendor/lib64/hw/"
517#define HAL_LIBRARY_PATH_ODM "/odm/lib64/hw/"
518#else
519#define HAL_LIBRARY_PATH_SYSTEM "/system/lib/hw/"
520#define HAL_LIBRARY_PATH_VENDOR "/vendor/lib/hw/"
521#define HAL_LIBRARY_PATH_ODM "/odm/lib/hw/"
522#endif
523
Martijn Coenenc28f1152016-08-22 14:06:56 +0200524#define DECLARE_REGISTER_AND_GET_SERVICE(INTERFACE) \
525 static ::android::sp<I##INTERFACE> getService( \
Iliyan Malchevb42ce262016-09-26 00:09:35 -0700526 const std::string &serviceName, bool getStub=false); \
Steven Morelandbdf26662016-09-02 11:03:15 -0700527 status_t registerAsService( \
Martijn Coenen097a7672016-09-08 16:56:41 +0200528 const std::string &serviceName); \
Martijn Coenenc28f1152016-08-22 14:06:56 +0200529
Steven Morelandbdf26662016-09-02 11:03:15 -0700530#define IMPLEMENT_REGISTER_AND_GET_SERVICE(INTERFACE, LIB) \
Martijn Coenenc28f1152016-08-22 14:06:56 +0200531 ::android::sp<I##INTERFACE> I##INTERFACE::getService( \
Iliyan Malchevb42ce262016-09-26 00:09:35 -0700532 const std::string &serviceName, bool getStub) \
Martijn Coenenc28f1152016-08-22 14:06:56 +0200533 { \
534 sp<I##INTERFACE> iface; \
Iliyan Malchevb42ce262016-09-26 00:09:35 -0700535 const struct timespec DELAY {1,0}; \
536 unsigned retries = 3; \
537 if (!getStub) { \
538 do { \
539 const sp<IServiceManager> sm = defaultServiceManager(); \
540 if (sm != nullptr) { \
541 sp<IBinder> binderIface = \
542 sm->checkService(String16(serviceName.c_str()), \
543 I##INTERFACE::version); \
544 iface = IHw##INTERFACE::asInterface(binderIface); \
545 } \
546 if (iface != nullptr) { \
547 return iface; \
548 } \
549 TEMP_FAILURE_RETRY(nanosleep(&DELAY, nullptr)); \
550 } while (retries--); \
Steven Morelandbdf26662016-09-02 11:03:15 -0700551 } \
552 int dlMode = RTLD_LAZY; \
553 void *handle = dlopen(HAL_LIBRARY_PATH_ODM LIB, dlMode); \
554 if (handle == nullptr) { \
555 handle = dlopen(HAL_LIBRARY_PATH_VENDOR LIB, dlMode); \
556 } \
557 if (handle == nullptr) { \
558 handle = dlopen(HAL_LIBRARY_PATH_SYSTEM LIB, dlMode); \
559 } \
560 if (handle == nullptr) { \
561 return iface; \
562 } \
563 I##INTERFACE* (*generator)(const char* name); \
564 *(void **)(&generator) = dlsym(handle, "HIDL_FETCH_I"#INTERFACE); \
565 if (generator) { \
Martijn Coenenf7a651d2016-09-08 13:38:12 +0200566 iface = (*generator)(serviceName.c_str()); \
Steven Moreland7391bc32016-09-14 10:31:48 -0700567 if (iface != nullptr) { \
568 iface = new Bs##INTERFACE(iface); \
569 } \
Steven Morelandbdf26662016-09-02 11:03:15 -0700570 } \
Martijn Coenenc28f1152016-08-22 14:06:56 +0200571 return iface; \
572 } \
Steven Morelandbdf26662016-09-02 11:03:15 -0700573 status_t I##INTERFACE::registerAsService( \
Martijn Coenen097a7672016-09-08 16:56:41 +0200574 const std::string &serviceName) \
Martijn Coenenc28f1152016-08-22 14:06:56 +0200575 { \
576 sp<Bn##INTERFACE> binderIface = new Bn##INTERFACE(this); \
577 const sp<IServiceManager> sm = defaultServiceManager(); \
Martijn Coenen097a7672016-09-08 16:56:41 +0200578 return sm->addService(String16(serviceName.c_str()), binderIface, \
579 I##INTERFACE::version); \
Martijn Coenenc28f1152016-08-22 14:06:56 +0200580 }
581
Zhuoyao Zhang7e1286c2016-09-12 17:28:48 -0700582// ----------------------------------------------------------------------
Zhuoyao Zhang28e03af2016-10-21 11:25:49 -0700583// Class that provides Hidl instrumentation utilities.
584struct HidlInstrumentor {
585 // Event that triggers the instrumentation. e.g. enter of an API call on
586 // the server/client side, exit of an API call on the server/client side
587 // etc.
588 enum InstrumentationEvent {
589 SERVER_API_ENTRY = 0,
590 SERVER_API_EXIT,
591 CLIENT_API_ENTRY,
592 CLIENT_API_EXIT,
593 SYNC_CALLBACK_ENTRY,
594 SYNC_CALLBACK_EXIT,
595 ASYNC_CALLBACK_ENTRY,
596 ASYNC_CALLBACK_EXIT,
597 };
Zhuoyao Zhang7e1286c2016-09-12 17:28:48 -0700598
Zhuoyao Zhang28e03af2016-10-21 11:25:49 -0700599 // Signature of the instrumentation callback function.
600 using InstrumentationCallback = std::function<void(
601 const InstrumentationEvent event,
602 const char *package,
603 const char *version,
604 const char *interface,
605 const char *method,
606 std::vector<void *> *args)>;
607
608 explicit HidlInstrumentor(const std::string &prefix);
609 virtual ~HidlInstrumentor();
610
611 protected:
612 // Function that lookup and dynamically loads the hidl instrumentation
613 // libraries and registers the instrumentation callback functions.
614 //
615 // The instrumentation libraries should be stored under any of the following
616 // directories: HAL_LIBRARY_PATH_SYSTEM, HAL_LIBRARY_PATH_VENDOR and
617 // HAL_LIBRARY_PATH_ODM. The name of instrumentation libraries should
618 // follow pattern: ^profilerPrefix(.*).profiler.so$
619 //
620 // Each instrumentation library is expected to implement the instrumentation
621 // function called HIDL_INSTRUMENTATION_FUNCTION.
622 //
623 // A no-op for user build.
624 void registerInstrumentationCallbacks(
625 const std::string &profilerPrefix,
626 std::vector<InstrumentationCallback> *instrumentationCallbacks);
627
628 // Utility function to determine whether a give file is a instrumentation
629 // library (i.e. the file name follow the expected pattern).
630 bool isInstrumentationLib(
631 const std::string &profilerPrefix,
632 const dirent *file);
633 // A list of registered instrumentation callbacks.
634 std::vector<InstrumentationCallback> mInstrumentationCallbacks;
635 // Flag whether to enable instrumentation.
636 bool mEnableInstrumentation;
Zhuoyao Zhang7e1286c2016-09-12 17:28:48 -0700637};
638
Martijn Coenen72110162016-08-19 14:28:25 +0200639} // namespace hardware
640} // namespace android
641
Martijn Coenenc28f1152016-08-22 14:06:56 +0200642
Martijn Coenen72110162016-08-19 14:28:25 +0200643#endif // ANDROID_HIDL_SUPPORT_H
644