blob: d3d532bb882ddba96738c78e6d8914f41980caa2 [file] [log] [blame]
/*
* Copyright 2020 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.
*/
#define LOG_TAG "SurfaceToNativeHandleConverter"
#include <android_os_NativeHandle.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
#include <utils/Log.h>
#include "jni.h"
namespace android {
namespace {
constexpr int WINDOW_HAL_TOKEN_SIZE_MAX = 256;
native_handle_t* convertHalTokenToNativeHandle(const HalToken& halToken) {
// We attempt to store halToken in the ints of the native_handle_t after its
// size. The first int stores the size of the token. We store this in an int
// to avoid alignment issues where size_t and int do not have the same
// alignment.
size_t nhDataByteSize = halToken.size();
if (nhDataByteSize > WINDOW_HAL_TOKEN_SIZE_MAX) {
// The size of the token isn't reasonable..
return nullptr;
}
size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;
// We don't check for overflow, whether numInts can fit in an int, since we
// expect WINDOW_HAL_TOKEN_SIZE_MAX to be a reasonable limit.
// create a native_handle_t with 0 numFds and numInts number of ints.
native_handle_t* nh = native_handle_create(0, numInts);
if (!nh) {
return nullptr;
}
// Store the size of the token in the first int.
nh->data[0] = nhDataByteSize;
memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
return nh;
}
HalToken convertNativeHandleToHalToken(native_handle_t* handle) {
int size = handle->data[0];
auto data = reinterpret_cast<uint8_t*>(&handle->data[1]);
HalToken halToken;
halToken.setToExternal(data, size);
return halToken;
}
jobject acquireSurfaceHandle(JNIEnv* env, jobject /* clazz */, jobject jSurface) {
ALOGD("%s", __func__);
if (jSurface == nullptr) {
ALOGE("%s: jSurface is null", __func__);
return nullptr;
}
sp<Surface> surface = android_view_Surface_getSurface(env, jSurface);
if (surface == nullptr) {
ALOGE("%s: surface is null", __func__);
return nullptr;
}
sp<IGraphicBufferProducer> igbp = surface->getIGraphicBufferProducer();
sp<HGraphicBufferProducer> hgbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(igbp);
// The HAL token will be closed in releaseSurfaceHandle.
HalToken halToken;
createHalToken(hgbp, &halToken);
native_handle_t* native_handle = convertHalTokenToNativeHandle(halToken);
if (native_handle == nullptr) {
ALOGE("%s: native_handle is null", __func__);
return nullptr;
}
jobject jHandle = JNativeHandle::MakeJavaNativeHandleObj(env, native_handle);
native_handle_delete(native_handle);
return jHandle;
}
void releaseSurfaceHandle(JNIEnv* env, jobject /* clazz */, jobject jHandle) {
ALOGD("%s", __func__);
// Creates a native handle from a Java handle. We must call native_handle_delete when we're done
// with it because we created it, but we shouldn't call native_handle_close because we don't own
// the underlying FDs.
native_handle_t* handle =
JNativeHandle::MakeCppNativeHandle(env, jHandle, nullptr /* storage */);
if (handle == nullptr) {
ALOGE("%s: handle is null", __func__);
return;
}
HalToken token = convertNativeHandleToHalToken(handle);
ALOGD("%s: deleteHalToken, success: %d", __func__, deleteHalToken(token));
ALOGD("%s: native_handle_delete, success: %d", __func__, !native_handle_delete(handle));
}
const JNINativeMethod method_table[] = {
{"acquireSurfaceHandle", "(Landroid/view/Surface;)Landroid/os/NativeHandle;",
reinterpret_cast<void*>(acquireSurfaceHandle)},
{"releaseSurfaceHandle", "(Landroid/os/NativeHandle;)V",
reinterpret_cast<void*>(releaseSurfaceHandle)},
};
} // namespace
int register_android_server_FaceService(JNIEnv* env) {
return AndroidRuntime::
registerNativeMethods(env, "com/android/server/biometrics/sensors/face/FaceService",
method_table, NELEM(method_table));
}
} // namespace android