blob: 656c2141ff2ee01010eb125516b7b2d75bd15270 [file] [log] [blame]
Jungshik Jang0792d372014-04-23 17:57:26 +09001/*
2 * Copyright (C) 2014 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#define LOG_TAG "HdmiCecControllerJni"
18
19#define LOG_NDEBUG 1
20
Jinsuk Kim8c688ad2014-07-24 14:48:34 +090021#include <JNIHelp.h>
22#include <ScopedPrimitiveArray.h>
Jungshik Jange9c77c82014-04-24 20:30:09 +090023
Jungshik Jang4085d0e2014-05-27 19:52:39 +090024#include <cstring>
Jungshik Jang0792d372014-04-23 17:57:26 +090025
Jungshik Jang4085d0e2014-05-27 19:52:39 +090026#include <android_os_MessageQueue.h>
Jungshik Jang0792d372014-04-23 17:57:26 +090027#include <android_runtime/AndroidRuntime.h>
28#include <android_runtime/Log.h>
29#include <hardware/hdmi_cec.h>
Jungshik Jange9c77c82014-04-24 20:30:09 +090030#include <sys/param.h>
Jungshik Jang4085d0e2014-05-27 19:52:39 +090031#include <utils/Looper.h>
32#include <utils/RefBase.h>
Jungshik Jang0792d372014-04-23 17:57:26 +090033
34namespace android {
35
36static struct {
Jungshik Jange9c77c82014-04-24 20:30:09 +090037 jmethodID handleIncomingCecCommand;
38 jmethodID handleHotplug;
Jungshik Jang0792d372014-04-23 17:57:26 +090039} gHdmiCecControllerClassInfo;
40
Jungshik Jang0792d372014-04-23 17:57:26 +090041class HdmiCecController {
42public:
Jungshik Jang4085d0e2014-05-27 19:52:39 +090043 HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj,
44 const sp<Looper>& looper);
Jungshik Jange9c77c82014-04-24 20:30:09 +090045
46 void init();
47
48 // Send message to other device. Note that it runs in IO thread.
49 int sendMessage(const cec_message_t& message);
Jungshik Janga9095ba2014-05-02 13:06:22 +090050 // Add a logical address to device.
51 int addLogicalAddress(cec_logical_address_t address);
52 // Clear all logical address registered to the device.
53 void clearLogicaladdress();
54 // Get physical address of device.
55 int getPhysicalAddress();
56 // Get CEC version from driver.
57 int getVersion();
58 // Get vendor id used for vendor command.
59 uint32_t getVendorId();
Jinsuk Kim0340bbc2014-06-05 11:07:47 +090060 // Get Port information on all the HDMI ports.
61 jobjectArray getPortInfos();
Jungshik Jang092b4452014-06-11 15:19:17 +090062 // Set a flag and its value.
63 void setOption(int flag, int value);
64 // Set audio return channel status.
Jinsuk Kim1481a422014-12-17 16:15:05 +090065 void setAudioReturnChannel(int port, bool flag);
Jungshik Jang092b4452014-06-11 15:19:17 +090066 // Whether to hdmi device is connected to the given port.
67 bool isConnected(int port);
Jungshik Jang0792d372014-04-23 17:57:26 +090068
Jungshik Jang4085d0e2014-05-27 19:52:39 +090069 jobject getCallbacksObj() const {
70 return mCallbacksObj;
71 }
Jungshik Jang0792d372014-04-23 17:57:26 +090072
Jungshik Jang4085d0e2014-05-27 19:52:39 +090073private:
Jinsuk Kima6ce7702014-05-11 06:54:49 +090074 static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
Jungshik Jange9c77c82014-04-24 20:30:09 +090075 static void onReceived(const hdmi_event_t* event, void* arg);
Jungshik Jange9c77c82014-04-24 20:30:09 +090076
77 hdmi_cec_device_t* mDevice;
Jungshik Jang0792d372014-04-23 17:57:26 +090078 jobject mCallbacksObj;
Jungshik Jang4085d0e2014-05-27 19:52:39 +090079 sp<Looper> mLooper;
Jungshik Jang0792d372014-04-23 17:57:26 +090080};
81
Jungshik Jang4085d0e2014-05-27 19:52:39 +090082// RefBase wrapper for hdmi_event_t. As hdmi_event_t coming from HAL
83// may keep its own lifetime, we need to copy it in order to delegate
84// it to service thread.
85class CecEventWrapper : public LightRefBase<CecEventWrapper> {
86public:
87 CecEventWrapper(const hdmi_event_t& event) {
88 // Copy message.
89 switch (event.type) {
90 case HDMI_EVENT_CEC_MESSAGE:
91 mEvent.cec.initiator = event.cec.initiator;
92 mEvent.cec.destination = event.cec.destination;
93 mEvent.cec.length = event.cec.length;
94 std::memcpy(mEvent.cec.body, event.cec.body, event.cec.length);
95 break;
96 case HDMI_EVENT_HOT_PLUG:
97 mEvent.hotplug.connected = event.hotplug.connected;
Jinsuk Kim284c31b2014-07-11 07:26:45 +090098 mEvent.hotplug.port_id = event.hotplug.port_id;
Jungshik Jang4085d0e2014-05-27 19:52:39 +090099 break;
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900100 default:
101 // TODO: add more type whenever new type is introduced.
102 break;
103 }
104 }
105
106 const cec_message_t& cec() const {
107 return mEvent.cec;
108 }
109
110 const hotplug_event_t& hotplug() const {
111 return mEvent.hotplug;
112 }
113
114 virtual ~CecEventWrapper() {}
115
116private:
117 hdmi_event_t mEvent;
118};
119
120// Handler class to delegate incoming message to service thread.
121class HdmiCecEventHandler : public MessageHandler {
122public:
123 HdmiCecEventHandler(HdmiCecController* controller, const sp<CecEventWrapper>& event)
124 : mController(controller),
125 mEventWrapper(event) {
126 }
127
128 virtual ~HdmiCecEventHandler() {}
129
130 void handleMessage(const Message& message) {
131 switch (message.what) {
132 case HDMI_EVENT_CEC_MESSAGE:
133 propagateCecCommand(mEventWrapper->cec());
134 break;
135 case HDMI_EVENT_HOT_PLUG:
136 propagateHotplugEvent(mEventWrapper->hotplug());
137 break;
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900138 default:
139 // TODO: add more type whenever new type is introduced.
140 break;
141 }
142 }
143
144private:
145 // Propagate the message up to Java layer.
146 void propagateCecCommand(const cec_message_t& message) {
147 jint srcAddr = message.initiator;
148 jint dstAddr = message.destination;
149 JNIEnv* env = AndroidRuntime::getJNIEnv();
150 jbyteArray body = env->NewByteArray(message.length);
151 const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body);
152 env->SetByteArrayRegion(body, 0, message.length, bodyPtr);
153
154 env->CallVoidMethod(mController->getCallbacksObj(),
155 gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr,
156 dstAddr, body);
157 env->DeleteLocalRef(body);
158
159 checkAndClearExceptionFromCallback(env, __FUNCTION__);
160 }
161
162 void propagateHotplugEvent(const hotplug_event_t& event) {
163 // Note that this method should be called in service thread.
164 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jinsuk Kim284c31b2014-07-11 07:26:45 +0900165 jint port = event.port_id;
Jungshik Jang42230722014-07-07 17:40:25 +0900166 jboolean connected = (jboolean) event.connected;
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900167 env->CallVoidMethod(mController->getCallbacksObj(),
Jungshik Jang42230722014-07-07 17:40:25 +0900168 gHdmiCecControllerClassInfo.handleHotplug, port, connected);
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900169
170 checkAndClearExceptionFromCallback(env, __FUNCTION__);
171 }
172
173 // static
174 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
175 if (env->ExceptionCheck()) {
176 ALOGE("An exception was thrown by callback '%s'.", methodName);
177 LOGE_EX(env);
178 env->ExceptionClear();
179 }
180 }
181
182 HdmiCecController* mController;
183 sp<CecEventWrapper> mEventWrapper;
184};
185
186HdmiCecController::HdmiCecController(hdmi_cec_device_t* device,
187 jobject callbacksObj, const sp<Looper>& looper) :
Jungshik Jange9c77c82014-04-24 20:30:09 +0900188 mDevice(device),
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900189 mCallbacksObj(callbacksObj),
190 mLooper(looper) {
Jungshik Jang0792d372014-04-23 17:57:26 +0900191}
192
Jungshik Jange9c77c82014-04-24 20:30:09 +0900193void HdmiCecController::init() {
194 mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this);
195}
196
Jungshik Jange9c77c82014-04-24 20:30:09 +0900197int HdmiCecController::sendMessage(const cec_message_t& message) {
198 // TODO: propagate send_message's return value.
199 return mDevice->send_message(mDevice, &message);
200}
201
Jungshik Janga9095ba2014-05-02 13:06:22 +0900202int HdmiCecController::addLogicalAddress(cec_logical_address_t address) {
203 return mDevice->add_logical_address(mDevice, address);
204}
205
206void HdmiCecController::clearLogicaladdress() {
207 mDevice->clear_logical_address(mDevice);
208}
209
210int HdmiCecController::getPhysicalAddress() {
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900211 uint16_t addr;
212 if (!mDevice->get_physical_address(mDevice, &addr)) {
213 return addr;
Jungshik Janga9095ba2014-05-02 13:06:22 +0900214 }
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900215 return INVALID_PHYSICAL_ADDRESS;
Jungshik Janga9095ba2014-05-02 13:06:22 +0900216}
217
218int HdmiCecController::getVersion() {
219 int version = 0;
220 mDevice->get_version(mDevice, &version);
221 return version;
222}
223
224uint32_t HdmiCecController::getVendorId() {
225 uint32_t vendorId = 0;
226 mDevice->get_vendor_id(mDevice, &vendorId);
227 return vendorId;
228}
229
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900230jobjectArray HdmiCecController::getPortInfos() {
231 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jinsuk Kim63dd3bb2014-06-13 14:46:17 +0900232 jclass hdmiPortInfo = env->FindClass("android/hardware/hdmi/HdmiPortInfo");
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900233 if (hdmiPortInfo == NULL) {
234 return NULL;
235 }
236 jmethodID ctor = env->GetMethodID(hdmiPortInfo, "<init>", "(IIIZZZ)V");
237 if (ctor == NULL) {
238 return NULL;
239 }
240 hdmi_port_info* ports;
241 int numPorts;
242 mDevice->get_port_info(mDevice, &ports, &numPorts);
243 jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL);
244
245 // MHL support field will be obtained from MHL HAL. Leave it to false.
246 jboolean mhlSupported = (jboolean) 0;
247 for (int i = 0; i < numPorts; ++i) {
248 hdmi_port_info* info = &ports[i];
249 jboolean cecSupported = (jboolean) info->cec_supported;
250 jboolean arcSupported = (jboolean) info->arc_supported;
Jinsuk Kim284c31b2014-07-11 07:26:45 +0900251 jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_id, info->type,
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900252 info->physical_address, cecSupported, mhlSupported, arcSupported);
253 env->SetObjectArrayElement(res, i, infoObj);
254 }
255 return res;
256}
257
Jungshik Jang092b4452014-06-11 15:19:17 +0900258void HdmiCecController::setOption(int flag, int value) {
259 mDevice->set_option(mDevice, flag, value);
260}
261
262// Set audio return channel status.
Jinsuk Kim1481a422014-12-17 16:15:05 +0900263 void HdmiCecController::setAudioReturnChannel(int port, bool enabled) {
264 mDevice->set_audio_return_channel(mDevice, port, enabled ? 1 : 0);
Jungshik Jang092b4452014-06-11 15:19:17 +0900265}
266
267// Whether to hdmi device is connected to the given port.
268bool HdmiCecController::isConnected(int port) {
269 return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED;
270}
271
Jungshik Jang0792d372014-04-23 17:57:26 +0900272// static
273void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
Jungshik Jange9c77c82014-04-24 20:30:09 +0900274 HdmiCecController* controller = static_cast<HdmiCecController*>(arg);
275 if (controller == NULL) {
Jungshik Jang0792d372014-04-23 17:57:26 +0900276 return;
277 }
278
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900279 sp<CecEventWrapper> spEvent(new CecEventWrapper(*event));
280 sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(controller, spEvent));
281 controller->mLooper->sendMessage(handler, event->type);
Jungshik Jang0792d372014-04-23 17:57:26 +0900282}
283
Jungshik Jang0792d372014-04-23 17:57:26 +0900284//------------------------------------------------------------------------------
Jungshik Jange9c77c82014-04-24 20:30:09 +0900285#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
286 var = env->GetMethodID(clazz, methodName, methodDescriptor); \
287 LOG_FATAL_IF(! var, "Unable to find method " methodName);
288
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900289static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj,
290 jobject messageQueueObj) {
Jungshik Jange9c77c82014-04-24 20:30:09 +0900291 int err;
Jungshik Jange9c77c82014-04-24 20:30:09 +0900292 hw_module_t* module;
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900293 err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID,
Jungshik Jange9c77c82014-04-24 20:30:09 +0900294 const_cast<const hw_module_t **>(&module));
295 if (err != 0) {
296 ALOGE("Error acquiring hardware module: %d", err);
297 return 0;
298 }
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900299
Jungshik Jange9c77c82014-04-24 20:30:09 +0900300 hw_device_t* device;
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900301 err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device);
Jungshik Jange9c77c82014-04-24 20:30:09 +0900302 if (err != 0) {
303 ALOGE("Error opening hardware module: %d", err);
304 return 0;
305 }
Jungshik Jang0792d372014-04-23 17:57:26 +0900306
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900307 sp<MessageQueue> messageQueue =
308 android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
309
Jungshik Jang0792d372014-04-23 17:57:26 +0900310 HdmiCecController* controller = new HdmiCecController(
Jungshik Jange9c77c82014-04-24 20:30:09 +0900311 reinterpret_cast<hdmi_cec_device*>(device),
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900312 env->NewGlobalRef(callbacksObj),
313 messageQueue->getLooper());
Jungshik Jange9c77c82014-04-24 20:30:09 +0900314 controller->init();
315
316 GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz,
317 "handleIncomingCecCommand", "(II[B)V");
318 GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz,
Jungshik Jang42230722014-07-07 17:40:25 +0900319 "handleHotplug", "(IZ)V");
Jungshik Jang0792d372014-04-23 17:57:26 +0900320
321 return reinterpret_cast<jlong>(controller);
322}
323
Jungshik Jange9c77c82014-04-24 20:30:09 +0900324static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
325 jint srcAddr, jint dstAddr, jbyteArray body) {
326 cec_message_t message;
327 message.initiator = static_cast<cec_logical_address_t>(srcAddr);
328 message.destination = static_cast<cec_logical_address_t>(dstAddr);
329
330 jsize len = env->GetArrayLength(body);
331 message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
332 ScopedByteArrayRO bodyPtr(env, body);
Jae Seod0efcbb2016-02-12 00:12:36 -0800333 std::memcpy(message.body, bodyPtr.get(), message.length);
Jungshik Jange9c77c82014-04-24 20:30:09 +0900334
335 HdmiCecController* controller =
336 reinterpret_cast<HdmiCecController*>(controllerPtr);
337 return controller->sendMessage(message);
338}
339
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900340static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
341 jint logicalAddress) {
342 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
343 return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress));
Jungshik Janga9095ba2014-05-02 13:06:22 +0900344}
345
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900346static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
347 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Janga9095ba2014-05-02 13:06:22 +0900348 controller->clearLogicaladdress();
349}
350
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900351static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
352 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Janga9095ba2014-05-02 13:06:22 +0900353 return controller->getPhysicalAddress();
354}
355
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900356static jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) {
357 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Janga9095ba2014-05-02 13:06:22 +0900358 return controller->getVersion();
359}
360
361static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900362 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Janga9095ba2014-05-02 13:06:22 +0900363 return controller->getVendorId();
364}
365
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900366static jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controllerPtr) {
367 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
368 return controller->getPortInfos();
369}
370
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900371static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
372 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Jang092b4452014-06-11 15:19:17 +0900373 controller->setOption(flag, value);
374}
375
376static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
Jinsuk Kim1481a422014-12-17 16:15:05 +0900377 jint port, jboolean enabled) {
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900378 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jinsuk Kim1481a422014-12-17 16:15:05 +0900379 controller->setAudioReturnChannel(port, enabled == JNI_TRUE);
Jungshik Jang092b4452014-06-11 15:19:17 +0900380}
381
382static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900383 HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
Jungshik Jang092b4452014-06-11 15:19:17 +0900384 return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
385}
386
Daniel Micay76f6a862015-09-19 17:31:01 -0400387static const JNINativeMethod sMethods[] = {
Jungshik Jang0792d372014-04-23 17:57:26 +0900388 /* name, signature, funcPtr */
Jungshik Jang4085d0e2014-05-27 19:52:39 +0900389 { "nativeInit",
390 "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J",
391 (void *) nativeInit },
Jungshik Janga9095ba2014-05-02 13:06:22 +0900392 { "nativeSendCecCommand", "(JII[B)I", (void *) nativeSendCecCommand },
393 { "nativeAddLogicalAddress", "(JI)I", (void *) nativeAddLogicalAddress },
394 { "nativeClearLogicalAddress", "(J)V", (void *) nativeClearLogicalAddress },
395 { "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
396 { "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
397 { "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900398 { "nativeGetPortInfos",
Jinsuk Kim63dd3bb2014-06-13 14:46:17 +0900399 "(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
Jinsuk Kim0340bbc2014-06-05 11:07:47 +0900400 (void *) nativeGetPortInfos },
Jungshik Jang092b4452014-06-11 15:19:17 +0900401 { "nativeSetOption", "(JII)V", (void *) nativeSetOption },
Jinsuk Kim1481a422014-12-17 16:15:05 +0900402 { "nativeSetAudioReturnChannel", "(JIZ)V", (void *) nativeSetAudioReturnChannel },
Jungshik Jang092b4452014-06-11 15:19:17 +0900403 { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
Jungshik Jang0792d372014-04-23 17:57:26 +0900404};
405
406#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
407
408int register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
Jinsuk Kima6ce7702014-05-11 06:54:49 +0900409 int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
Jungshik Jang0792d372014-04-23 17:57:26 +0900410 LOG_FATAL_IF(res < 0, "Unable to register native methods.");
Bernhard Rosenkränzer4048a4b2014-11-23 22:24:32 +0100411 (void)res; // Don't scream about unused variable in the LOG_NDEBUG case
Jungshik Jang0792d372014-04-23 17:57:26 +0900412 return 0;
413}
414
415} /* namespace android */