1 /*
2 **
3 ** Copyright 2017, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #define LOG_TAG "android_emulator_multidisplay_JNI"
19
20 #include <com_android_graphics_libgui_flags.h>
21 #include <gralloc_cb_bp.h>
22 #include <gui/BufferItemConsumer.h>
23 #include <gui/BufferQueue.h>
24 #include <gui/ISurfaceComposer.h>
25 #include <gui/Surface.h>
26 #include <gui/SurfaceComposerClient.h>
27 #include <nativehelper/ScopedLocalRef.h>
28 #include <qemu_pipe_bp.h>
29 #include <sys/epoll.h>
30
31 #include "android_runtime/AndroidRuntime.h"
32 #include "android_runtime/android_view_Surface.h"
33 #include "jni.h"
34 #include "nativehelper/JNIHelp.h"
35 #include "utils/Log.h"
36
37 #define MAX_DISPLAYS 10
38
39 using namespace android;
40
41 static int gFd = 0;
42 static const uint8_t ADD = 1;
43 static const uint8_t DEL = 2;
44 static const uint8_t QUERY = 3;
45 static const uint8_t BIND = 4;
46 static const uint8_t SET_DISPLAY = 0x10;
47
fillMsg(std::vector<uint8_t> & buf,uint8_t cmd,uint8_t * data,uint32_t size)48 static void fillMsg(std::vector<uint8_t>& buf, uint8_t cmd, uint8_t* data, uint32_t size) {
49 // msg format is size(4B) + cmd(1B) + data(size B)
50 uint32_t totalSize = size + 1;
51 uint8_t* p = (uint8_t*)&totalSize;
52 buf.insert(buf.end(), p, p + 4);
53 buf.push_back(cmd);
54 if (data) {
55 buf.insert(buf.end(), data, data + size);
56 }
57 }
58
59 struct FrameListener : public ConsumerBase::FrameAvailableListener {
60 sp<BufferItemConsumer> mConsumer;
61 uint32_t mId;
62 uint32_t mCb;
63 public:
onFrameAvailableFrameListener64 void onFrameAvailable(const BufferItem& item) override {
65 BufferItem bufferItem;
66 mConsumer->acquireBuffer(&bufferItem, 0);
67 ANativeWindowBuffer* b = bufferItem.mGraphicBuffer->getNativeBuffer();
68 if (b && b->handle) {
69 const cb_handle_t* cb = cb_handle_t::from(b->handle);
70 if (mCb != cb->hostHandle) {
71 ALOGI("sent cb %d", cb->hostHandle);
72 mCb = cb->hostHandle;
73 uint32_t data[] = {mId, mCb};
74 std::vector<uint8_t> buf;
75 fillMsg(buf, BIND, (uint8_t*)data, sizeof(data));
76 qemu_pipe_write_fully(gFd, buf.data(), buf.size());
77 }
78 }
79 else {
80 ALOGE("cannot get native buffer handler");
81 }
82 mConsumer->releaseBuffer(bufferItem);
83 }
setDefaultBufferSizeFrameListener84 void setDefaultBufferSize(uint32_t w, uint32_t h) {
85 mConsumer->setDefaultBufferSize(w, h);
86 }
FrameListenerFrameListener87 FrameListener(sp<BufferItemConsumer>& consumer, uint32_t id)
88 : mConsumer(consumer), mId(id), mCb(0) { }
89 };
90
91 sp<FrameListener> gFrameListener[MAX_DISPLAYS + 1];
92
nativeCreateSurface(JNIEnv * env,jobject obj,jint id,jint width,jint height)93 static jobject nativeCreateSurface(JNIEnv *env, jobject obj, jint id, jint width, jint height)
94 {
95 ALOGI("create surface for %d", id);
96 // Create surface for this new display
97 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
98 sp<BufferItemConsumer> bufferItemConsumer =
99 new BufferItemConsumer(GRALLOC_USAGE_HW_RENDER);
100 #else
101 sp<IGraphicBufferProducer> producer;
102 sp<IGraphicBufferConsumer> consumer;
103 sp<BufferItemConsumer> bufferItemConsumer;
104 BufferQueue::createBufferQueue(&producer, &consumer);
105 bufferItemConsumer = new BufferItemConsumer(consumer, GRALLOC_USAGE_HW_RENDER);
106 #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
107 gFrameListener[id] = new FrameListener(bufferItemConsumer, id);
108 gFrameListener[id]->setDefaultBufferSize(width, height);
109 bufferItemConsumer->setFrameAvailableListener(gFrameListener[id]);
110 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
111 return android_view_Surface_createFromSurface(
112 env, bufferItemConsumer->getSurface());
113 #else
114 return android_view_Surface_createFromIGraphicBufferProducer(env, producer);
115 #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
116 }
117
nativeOpen(JNIEnv * env,jobject obj)118 static jint nativeOpen(JNIEnv* env, jobject obj) {
119 // Open pipe
120 gFd = qemu_pipe_open_ns(NULL, "multidisplay", O_RDWR);
121 if (gFd < 0) {
122 ALOGE("Error opening multidisplay pipe %d", gFd);
123 } else {
124 std::vector<uint8_t> buf;
125 fillMsg(buf, QUERY, nullptr, 0);
126 qemu_pipe_write_fully(gFd, buf.data(), buf.size());
127 ALOGI("multidisplay pipe connected!!!");
128 }
129 return gFd;
130 }
131
nativeReadPipe(JNIEnv * env,jobject obj,jintArray arr)132 static bool nativeReadPipe(JNIEnv* env, jobject obj, jintArray arr) {
133 int* arrp = env->GetIntArrayElements(arr, 0);
134 uint32_t length;
135 qemu_pipe_read_fully(gFd, &length, sizeof(length));
136 std::vector<uint8_t> args(length, 0);
137 qemu_pipe_read_fully(gFd, args.data(), (size_t)length);
138 switch(args[0]) {
139 case SET_DISPLAY:
140 ALOGV("received setdisplay event");
141 *arrp = SET_DISPLAY;
142 for (int i = 1; i < 6; i++) {
143 *(arrp + i) = *(uint32_t*)(&args[(i - 1) * 4 + 1]);
144 }
145 env->ReleaseIntArrayElements(arr, arrp, JNI_COMMIT);
146 break;
147 case ADD: {
148 ALOGV("received add event");
149 *arrp = ADD;
150 for (int i = 1; i < 6; i++) {
151 *(arrp + i) = *(uint32_t*)(&args[(i - 1) * 4 + 1]);
152 }
153 env->ReleaseIntArrayElements(arr, arrp, JNI_COMMIT);
154 break;
155 }
156 case DEL: {
157 ALOGV("received del event");
158 *arrp = DEL;
159 *(arrp + 1) = *(uint32_t*)(&args[1]);
160 env->ReleaseIntArrayElements(arr, arrp, JNI_COMMIT);
161 break;
162 }
163 default: {
164 ALOGE("unexpected event %d", args[0]);
165 return false;
166 }
167 }
168 return true;
169 }
170
nativeReleaseListener(JNIEnv * env,jobject obj,jint id)171 static bool nativeReleaseListener(JNIEnv* env, jobject obj, jint id) {
172 if (gFrameListener[id].get()) {
173 ALOGV("clear gFrameListener %d", id);
174 gFrameListener[id].clear();
175 gFrameListener[id] = nullptr;
176 }
177 return true;
178 }
179
nativeResizeListener(JNIEnv * env,jobject obj,jint id,jint w,jint h)180 static bool nativeResizeListener(JNIEnv* env, jobject obj, jint id, jint w, jint h) {
181 if (gFrameListener[id]) {
182 gFrameListener[id]->setDefaultBufferSize(w, h);
183 return true;
184 }
185 return false;
186 }
187
188 static JNINativeMethod sMethods[] = {
189 { "nativeOpen", "()I", (void*) nativeOpen },
190 { "nativeCreateSurface", "(III)Landroid/view/Surface;", (void*) nativeCreateSurface },
191 { "nativeReadPipe", "([I)Z", (void*) nativeReadPipe},
192 { "nativeReleaseListener", "(I)Z", (void*) nativeReleaseListener},
193 { "nativeResizeListener", "(III)Z", (void*) nativeResizeListener},
194 };
195
196 /*
197 * JNI Initialization
198 */
JNI_OnLoad(JavaVM * jvm,void * reserved)199 jint JNI_OnLoad(JavaVM *jvm, void *reserved)
200 {
201 JNIEnv *env;
202
203 // Check JNI version
204 if (jvm->GetEnv((void **)&env, JNI_VERSION_1_6)) {
205 ALOGE("JNI version mismatch error");
206 return JNI_ERR;
207 }
208
209 jniRegisterNativeMethods(env, "com/android/emulator/multidisplay/MultiDisplayService",
210 sMethods, NELEM(sMethods));
211
212 return JNI_VERSION_1_6;
213 }
214