• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <gui/BufferQueue.h>
20 #include <gui/BufferItemConsumer.h>
21 #include <gui/Surface.h>
22 #include <gui/ISurfaceComposer.h>
23 #include <gui/SurfaceComposerClient.h>
24 
25 #include <sys/epoll.h>
26 
27 #include <gralloc_cb_bp.h>
28 #include <qemu_pipe_bp.h>
29 
30 #include "utils/Log.h"
31 #include "nativehelper/JNIHelp.h"
32 #include <nativehelper/ScopedLocalRef.h>
33 #include "jni.h"
34 #include "android_runtime/AndroidRuntime.h"
35 #include "android_runtime/android_view_Surface.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 
fillMsg(std::vector<uint8_t> & buf,uint8_t cmd,uint8_t * data,uint32_t size)47 static void fillMsg(std::vector<uint8_t>& buf, uint8_t cmd, uint8_t* data, uint32_t size) {
48     // msg format is size(4B) + cmd(1B) + data(size B)
49     uint32_t totalSize = size + 1;
50     uint8_t* p = (uint8_t*)&totalSize;
51     buf.insert(buf.end(), p, p + 4);
52     buf.push_back(cmd);
53     if (data) {
54         buf.insert(buf.end(), data, data + size);
55     }
56 }
57 
58 struct FrameListener : public ConsumerBase::FrameAvailableListener {
59     sp<BufferItemConsumer> mConsumer;
60     uint32_t mId;
61     uint32_t mCb;
62 public:
onFrameAvailableFrameListener63     void onFrameAvailable(const BufferItem& item) override {
64         BufferItem bufferItem;
65         mConsumer->acquireBuffer(&bufferItem, 0);
66         ANativeWindowBuffer* b = bufferItem.mGraphicBuffer->getNativeBuffer();
67         if (b && b->handle) {
68             const cb_handle_t* cb = cb_handle_t::from(b->handle);
69             if (mCb != cb->hostHandle) {
70                 ALOGI("sent cb %d", cb->hostHandle);
71                 mCb = cb->hostHandle;
72                 uint32_t data[] = {mId, mCb};
73                 std::vector<uint8_t> buf;
74                 fillMsg(buf, BIND, (uint8_t*)data, sizeof(data));
75                 qemu_pipe_write_fully(gFd, buf.data(), buf.size());
76             }
77         }
78         else {
79             ALOGE("cannot get native buffer handler");
80         }
81         mConsumer->releaseBuffer(bufferItem);
82     }
setDefaultBufferSizeFrameListener83     void setDefaultBufferSize(uint32_t w, uint32_t h) {
84         mConsumer->setDefaultBufferSize(w, h);
85     }
FrameListenerFrameListener86     FrameListener(sp<BufferItemConsumer>& consumer, uint32_t id)
87         : mConsumer(consumer), mId(id), mCb(0) { }
88 };
89 
90 sp<FrameListener> gFrameListener[MAX_DISPLAYS + 1];
91 
nativeCreateSurface(JNIEnv * env,jobject obj,jint id,jint width,jint height)92 static jobject nativeCreateSurface(JNIEnv *env, jobject obj, jint id, jint width, jint height)
93 {
94     ALOGI("create surface for %d", id);
95     // Create surface for this new display
96     sp<IGraphicBufferProducer> producer;
97     sp<IGraphicBufferConsumer> consumer;
98     sp<BufferItemConsumer> bufferItemConsumer;
99     BufferQueue::createBufferQueue(&producer, &consumer);
100     bufferItemConsumer = new BufferItemConsumer(consumer, GRALLOC_USAGE_HW_RENDER);
101     gFrameListener[id] = new FrameListener(bufferItemConsumer, id);
102     gFrameListener[id]->setDefaultBufferSize(width, height);
103     bufferItemConsumer->setFrameAvailableListener(gFrameListener[id]);
104     return android_view_Surface_createFromIGraphicBufferProducer(env, producer);
105 }
106 
nativeOpen(JNIEnv * env,jobject obj)107 static jint nativeOpen(JNIEnv* env, jobject obj) {
108     // Open pipe
109     gFd = qemu_pipe_open_ns(NULL, "multidisplay", O_RDWR);
110     if (gFd < 0) {
111         ALOGE("Error opening multidisplay pipe %d", gFd);
112     } else {
113         std::vector<uint8_t> buf;
114         fillMsg(buf, QUERY, nullptr, 0);
115         qemu_pipe_write_fully(gFd, buf.data(), buf.size());
116         ALOGI("multidisplay pipe connected!!!");
117     }
118     return gFd;
119 }
120 
nativeReadPipe(JNIEnv * env,jobject obj,jintArray arr)121 static bool nativeReadPipe(JNIEnv* env, jobject obj, jintArray arr) {
122     int* arrp = env->GetIntArrayElements(arr, 0);
123     uint32_t length;
124     qemu_pipe_read_fully(gFd, &length, sizeof(length));
125     std::vector<uint8_t> args(length, 0);
126     qemu_pipe_read_fully(gFd, args.data(), (size_t)length);
127     switch(args[0]) {
128         case ADD: {
129             ALOGV("received add event");
130             *arrp = ADD;
131             for (int i = 1; i < 6; i++) {
132                 *(arrp + i) = *(uint32_t*)(&args[(i - 1) * 4 + 1]);
133             }
134             env->ReleaseIntArrayElements(arr, arrp, JNI_COMMIT);
135             break;
136         }
137         case DEL: {
138             ALOGV("received del event");
139             *arrp = DEL;
140             *(arrp + 1) = *(uint32_t*)(&args[1]);
141             env->ReleaseIntArrayElements(arr, arrp, JNI_COMMIT);
142             break;
143         }
144         default: {
145             ALOGE("unexpected event %d", args[0]);
146             return false;
147         }
148     }
149     return true;
150 }
151 
nativeReleaseListener(JNIEnv * env,jobject obj,jint id)152 static bool nativeReleaseListener(JNIEnv* env, jobject obj, jint id) {
153     if (gFrameListener[id].get()) {
154         ALOGV("clear gFrameListener %d", id);
155         gFrameListener[id].clear();
156         gFrameListener[id] = nullptr;
157     }
158     return true;
159 }
160 
nativeResizeListener(JNIEnv * env,jobject obj,jint id,jint w,jint h)161 static bool nativeResizeListener(JNIEnv* env, jobject obj, jint id, jint w, jint h) {
162     if (gFrameListener[id]) {
163         gFrameListener[id]->setDefaultBufferSize(w, h);
164         return true;
165     }
166     return false;
167 }
168 
169 static JNINativeMethod sMethods[] = {
170     { "nativeOpen", "()I", (void*) nativeOpen },
171     { "nativeCreateSurface", "(III)Landroid/view/Surface;", (void*) nativeCreateSurface },
172     { "nativeReadPipe", "([I)Z", (void*) nativeReadPipe},
173     { "nativeReleaseListener", "(I)Z", (void*) nativeReleaseListener},
174     { "nativeResizeListener", "(III)Z", (void*) nativeResizeListener},
175 };
176 
177 /*
178  * JNI Initialization
179  */
JNI_OnLoad(JavaVM * jvm,void * reserved)180 jint JNI_OnLoad(JavaVM *jvm, void *reserved)
181 {
182     JNIEnv *env;
183 
184     // Check JNI version
185     if (jvm->GetEnv((void **)&env, JNI_VERSION_1_6)) {
186         ALOGE("JNI version mismatch error");
187         return JNI_ERR;
188     }
189 
190     jniRegisterNativeMethods(env, "com/android/emulator/multidisplay/MultiDisplayService",
191                                     sMethods, NELEM(sMethods));
192 
193     return JNI_VERSION_1_6;
194 }
195