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#define LOG_TAG "HardwareBuffer"
18
19#include "jni.h"
20#include "JNIHelp.h"
21
22#include "android_os_Parcel.h"
23#include "android/graphics/GraphicsJNI.h"
24
25#include <android/hardware_buffer.h>
26#include <android_runtime/android_hardware_HardwareBuffer.h>
27#include <android_runtime/AndroidRuntime.h>
28#include <android_runtime/Log.h>
29#include <private/android/AHardwareBufferHelpers.h>
30
31#include <binder/Parcel.h>
32
33#include <ui/GraphicBuffer.h>
34#include <private/gui/ComposerService.h>
35
36#include <hardware/gralloc1.h>
37#include <grallocusage/GrallocUsageConversion.h>
38
39#include "core_jni_helpers.h"
40
41using namespace android;
42
43// ----------------------------------------------------------------------------
44// Defines
45// ----------------------------------------------------------------------------
46
47// Debug
48static constexpr bool kDebugGraphicBuffer = false;
49
50// ----------------------------------------------------------------------------
51// Types
52// ----------------------------------------------------------------------------
53
54static struct {
55    jclass clazz;
56    jfieldID mNativeObject;
57    jmethodID ctor;
58} gHardwareBufferClassInfo;
59
60class GraphicBufferWrapper {
61public:
62    explicit GraphicBufferWrapper(const sp<GraphicBuffer>& buffer)
63            : buffer(buffer) {}
64
65    sp<GraphicBuffer> buffer;
66};
67
68// ----------------------------------------------------------------------------
69// HardwareBuffer lifecycle
70// ----------------------------------------------------------------------------
71
72static jlong android_hardware_HardwareBuffer_create(JNIEnv* env, jobject clazz,
73        jint width, jint height, jint format, jint layers, jlong usage) {
74
75    // TODO: update createGraphicBuffer to take two 64-bit values.
76    int pixelFormat = android_hardware_HardwareBuffer_convertToPixelFormat(format);
77    if (pixelFormat == 0) {
78        if (kDebugGraphicBuffer) {
79            ALOGW("createGraphicBufferAlloc() invalid pixel format in HardwareBuffer.create()");
80        }
81        return NULL;
82    }
83
84    uint64_t grallocUsage = AHardwareBuffer_convertToGrallocUsageBits(usage);
85    sp<GraphicBuffer> buffer = new GraphicBuffer(width, height, pixelFormat, layers,
86            grallocUsage, std::string("HardwareBuffer pid [") + std::to_string(getpid()) +"]");
87    status_t error = buffer->initCheck();
88    if (error < 0) {
89        if (kDebugGraphicBuffer) {
90            ALOGW("createGraphicBuffer() failed in HardwareBuffer.create()");
91        }
92        return NULL;
93    }
94
95    GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
96    return reinterpret_cast<jlong>(wrapper);
97}
98
99static void destroyWrapper(GraphicBufferWrapper* wrapper) {
100    delete wrapper;
101}
102
103static jlong android_hardware_HardwareBuffer_getNativeFinalizer(JNIEnv* env, jobject clazz) {
104    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyWrapper));
105}
106
107//----------------------------------------------------------------------------
108// Accessors
109// ----------------------------------------------------------------------------
110
111static inline GraphicBuffer* GraphicBufferWrapper_to_GraphicBuffer(
112        jlong nativeObject) {
113    return reinterpret_cast<GraphicBufferWrapper*>(nativeObject)->buffer.get();
114}
115
116static jint android_hardware_HardwareBuffer_getWidth(JNIEnv* env, jobject clazz,
117    jlong nativeObject) {
118    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
119    return static_cast<jint>(buffer->getWidth());
120}
121
122static jint android_hardware_HardwareBuffer_getHeight(JNIEnv* env,
123    jobject clazz, jlong nativeObject) {
124    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
125    return static_cast<jint>(buffer->getHeight());
126}
127
128static jint android_hardware_HardwareBuffer_getFormat(JNIEnv* env,
129    jobject clazz, jlong nativeObject) {
130    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
131    return static_cast<jint>(android_hardware_HardwareBuffer_convertFromPixelFormat(
132            buffer->getPixelFormat()));
133}
134
135static jint android_hardware_HardwareBuffer_getLayers(JNIEnv* env,
136    jobject clazz, jlong nativeObject) {
137    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
138    return static_cast<jint>(buffer->getLayerCount());
139}
140
141static jlong android_hardware_HardwareBuffer_getUsage(JNIEnv* env,
142    jobject clazz, jlong nativeObject) {
143    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
144    return AHardwareBuffer_convertFromGrallocUsageBits(buffer->getUsage());
145}
146
147// ----------------------------------------------------------------------------
148// Serialization
149// ----------------------------------------------------------------------------
150
151static void android_hardware_HardwareBuffer_write(JNIEnv* env, jobject clazz,
152        jlong nativeObject, jobject dest) {
153    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
154    Parcel* parcel = parcelForJavaObject(env, dest);
155    if (parcel) {
156        parcel->write(*buffer);
157    }
158}
159
160static jlong android_hardware_HardwareBuffer_read(JNIEnv* env, jobject clazz,
161        jobject in) {
162    Parcel* parcel = parcelForJavaObject(env, in);
163    if (parcel) {
164        sp<GraphicBuffer> buffer = new GraphicBuffer();
165        parcel->read(*buffer);
166        return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer));
167    }
168
169    return NULL;
170}
171
172// ----------------------------------------------------------------------------
173// Public functions
174// ----------------------------------------------------------------------------
175
176namespace android {
177
178AHardwareBuffer* android_hardware_HardwareBuffer_getNativeHardwareBuffer(
179        JNIEnv* env, jobject hardwareBufferObj) {
180    if (env->IsInstanceOf(hardwareBufferObj, gHardwareBufferClassInfo.clazz)) {
181        GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(
182                env->GetLongField(hardwareBufferObj, gHardwareBufferClassInfo.mNativeObject));
183        return AHardwareBuffer_from_GraphicBuffer(buffer);
184
185    } else {
186        return nullptr;
187    }
188}
189
190jobject android_hardware_HardwareBuffer_createFromAHardwareBuffer(
191        JNIEnv* env, AHardwareBuffer* hardwareBuffer) {
192    GraphicBuffer* buffer = AHardwareBuffer_to_GraphicBuffer(hardwareBuffer);
193    GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
194    jobject hardwareBufferObj = env->NewObject(gHardwareBufferClassInfo.clazz,
195            gHardwareBufferClassInfo.ctor, reinterpret_cast<jlong>(wrapper));
196    if (hardwareBufferObj == NULL) {
197        delete wrapper;
198        if (env->ExceptionCheck()) {
199            ALOGE("Could not create instance of HardwareBuffer from AHardwareBuffer.");
200            LOGE_EX(env);
201            env->ExceptionClear();
202        }
203        return nullptr;
204    }
205    return hardwareBufferObj;
206}
207
208uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(uint32_t format) {
209    return AHardwareBuffer_convertFromPixelFormat(format);
210}
211
212uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(uint32_t format) {
213    return AHardwareBuffer_convertToPixelFormat(format);
214}
215
216uint64_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage) {
217    return AHardwareBuffer_convertToGrallocUsageBits(usage);
218}
219
220}  // namespace android
221
222// ----------------------------------------------------------------------------
223// JNI Glue
224// ----------------------------------------------------------------------------
225
226const char* const kClassPathName = "android/hardware/HardwareBuffer";
227
228static const JNINativeMethod gMethods[] = {
229    { "nCreateHardwareBuffer",  "(IIIIJ)J",
230            (void*) android_hardware_HardwareBuffer_create },
231    { "nGetNativeFinalizer", "()J",
232            (void*) android_hardware_HardwareBuffer_getNativeFinalizer },
233    { "nWriteHardwareBufferToParcel",  "(JLandroid/os/Parcel;)V",
234            (void*) android_hardware_HardwareBuffer_write },
235    { "nReadHardwareBufferFromParcel", "(Landroid/os/Parcel;)J",
236            (void*) android_hardware_HardwareBuffer_read },
237
238    // --------------- @FastNative ----------------------
239    { "nGetWidth", "(J)I",      (void*) android_hardware_HardwareBuffer_getWidth },
240    { "nGetHeight", "(J)I",     (void*) android_hardware_HardwareBuffer_getHeight },
241    { "nGetFormat", "(J)I",     (void*) android_hardware_HardwareBuffer_getFormat },
242    { "nGetLayers", "(J)I",     (void*) android_hardware_HardwareBuffer_getLayers },
243    { "nGetUsage", "(J)J",      (void*) android_hardware_HardwareBuffer_getUsage },
244};
245
246int register_android_hardware_HardwareBuffer(JNIEnv* env) {
247    int err = RegisterMethodsOrDie(env, kClassPathName, gMethods,
248            NELEM(gMethods));
249
250    jclass clazz = FindClassOrDie(env, "android/hardware/HardwareBuffer");
251    gHardwareBufferClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
252    gHardwareBufferClassInfo.mNativeObject = GetFieldIDOrDie(env,
253            gHardwareBufferClassInfo.clazz, "mNativeObject", "J");
254    gHardwareBufferClassInfo.ctor = GetMethodIDOrDie(env,
255            gHardwareBufferClassInfo.clazz, "<init>", "(J)V");
256
257    return err;
258}
259