OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / core / jni / android_view_SurfaceControl.cpp
1 /*
2  * Copyright (C) 2013 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 "SurfaceControl"
18
19 #include "android_os_Parcel.h"
20 #include "android_util_Binder.h"
21 #include "android/graphics/Bitmap.h"
22 #include "android/graphics/GraphicsJNI.h"
23 #include "android/graphics/Region.h"
24 #include "core_jni_helpers.h"
25
26 #include <JNIHelp.h>
27 #include <ScopedUtfChars.h>
28 #include <android_runtime/android_view_Surface.h>
29 #include <android_runtime/android_view_SurfaceSession.h>
30 #include <gui/Surface.h>
31 #include <gui/SurfaceComposerClient.h>
32 #include <jni.h>
33 #include <memory>
34 #include <stdio.h>
35 #include <system/graphics.h>
36 #include <ui/DisplayInfo.h>
37 #include <ui/HdrCapabilities.h>
38 #include <ui/FrameStats.h>
39 #include <ui/Rect.h>
40 #include <ui/Region.h>
41 #include <utils/Log.h>
42
43 // ----------------------------------------------------------------------------
44
45 namespace android {
46
47 static const char* const OutOfResourcesException =
48     "android/view/Surface$OutOfResourcesException";
49
50 static struct {
51     jclass clazz;
52     jmethodID ctor;
53     jfieldID width;
54     jfieldID height;
55     jfieldID refreshRate;
56     jfieldID density;
57     jfieldID xDpi;
58     jfieldID yDpi;
59     jfieldID secure;
60     jfieldID appVsyncOffsetNanos;
61     jfieldID presentationDeadlineNanos;
62 } gPhysicalDisplayInfoClassInfo;
63
64 static struct {
65     jfieldID bottom;
66     jfieldID left;
67     jfieldID right;
68     jfieldID top;
69 } gRectClassInfo;
70
71 // Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
72 void DeleteScreenshot(void* addr, void* context) {
73     SkASSERT(addr == ((ScreenshotClient*) context)->getPixels());
74     delete ((ScreenshotClient*) context);
75 }
76
77 static struct {
78     nsecs_t UNDEFINED_TIME_NANO;
79     jmethodID init;
80 } gWindowContentFrameStatsClassInfo;
81
82 static struct {
83     nsecs_t UNDEFINED_TIME_NANO;
84     jmethodID init;
85 } gWindowAnimationFrameStatsClassInfo;
86
87 static struct {
88     jclass clazz;
89     jmethodID ctor;
90 } gHdrCapabilitiesClassInfo;
91
92 // ----------------------------------------------------------------------------
93
94 static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
95         jstring nameStr, jint w, jint h, jint format, jint flags) {
96     ScopedUtfChars name(env, nameStr);
97     sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
98     sp<SurfaceControl> surface = client->createSurface(
99             String8(name.c_str()), w, h, format, flags);
100     if (surface == NULL) {
101         jniThrowException(env, OutOfResourcesException, NULL);
102         return 0;
103     }
104     surface->incStrong((void *)nativeCreate);
105     return reinterpret_cast<jlong>(surface.get());
106 }
107
108 static void nativeRelease(JNIEnv* env, jclass clazz, jlong nativeObject) {
109     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
110     ctrl->decStrong((void *)nativeCreate);
111 }
112
113 static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) {
114     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
115     ctrl->clear();
116     ctrl->decStrong((void *)nativeCreate);
117 }
118
119 static void nativeDisconnect(JNIEnv* env, jclass clazz, jlong nativeObject) {
120     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
121     if (ctrl != NULL) {
122         ctrl->disconnect();
123     }
124 }
125
126 static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
127         jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
128         jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
129         int rotation) {
130     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
131     if (displayToken == NULL) {
132         return NULL;
133     }
134
135     int left = env->GetIntField(sourceCropObj, gRectClassInfo.left);
136     int top = env->GetIntField(sourceCropObj, gRectClassInfo.top);
137     int right = env->GetIntField(sourceCropObj, gRectClassInfo.right);
138     int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom);
139     Rect sourceCrop(left, top, right, bottom);
140
141     std::unique_ptr<ScreenshotClient> screenshot(new ScreenshotClient());
142     status_t res;
143     if (allLayers) {
144         minLayer = 0;
145         maxLayer = -1;
146     }
147
148     res = screenshot->update(displayToken, sourceCrop, width, height,
149         minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation));
150     if (res != NO_ERROR) {
151         return NULL;
152     }
153
154     SkColorType colorType;
155     SkAlphaType alphaType;
156     switch (screenshot->getFormat()) {
157         case PIXEL_FORMAT_RGBX_8888: {
158             colorType = kRGBA_8888_SkColorType;
159             alphaType = kOpaque_SkAlphaType;
160             break;
161         }
162         case PIXEL_FORMAT_RGBA_8888: {
163             colorType = kRGBA_8888_SkColorType;
164             alphaType = kPremul_SkAlphaType;
165             break;
166         }
167         case PIXEL_FORMAT_RGB_565: {
168             colorType = kRGB_565_SkColorType;
169             alphaType = kOpaque_SkAlphaType;
170             break;
171         }
172         default: {
173             return NULL;
174         }
175     }
176     SkImageInfo screenshotInfo = SkImageInfo::Make(screenshot->getWidth(),
177                                                    screenshot->getHeight(),
178                                                    colorType, alphaType);
179
180     const size_t rowBytes =
181             screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());
182
183     if (!screenshotInfo.width() || !screenshotInfo.height()) {
184         return NULL;
185     }
186
187     Bitmap* bitmap = new Bitmap(
188             (void*) screenshot->getPixels(), (void*) screenshot.get(), DeleteScreenshot,
189             screenshotInfo, rowBytes, nullptr);
190     screenshot.release();
191     bitmap->peekAtPixelRef()->setImmutable();
192
193     return GraphicsJNI::createBitmap(env, bitmap,
194             GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL);
195 }
196
197 static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
198         jobject surfaceObj, jobject sourceCropObj, jint width, jint height,
199         jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) {
200     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
201     if (displayToken != NULL) {
202         sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
203         if (consumer != NULL) {
204             int left = env->GetIntField(sourceCropObj, gRectClassInfo.left);
205             int top = env->GetIntField(sourceCropObj, gRectClassInfo.top);
206             int right = env->GetIntField(sourceCropObj, gRectClassInfo.right);
207             int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom);
208             Rect sourceCrop(left, top, right, bottom);
209
210             if (allLayers) {
211                 minLayer = 0;
212                 maxLayer = -1;
213             }
214             ScreenshotClient::capture(displayToken,
215                     consumer->getIGraphicBufferProducer(), sourceCrop,
216                     width, height, uint32_t(minLayer), uint32_t(maxLayer),
217                     useIdentityTransform);
218         }
219     }
220 }
221
222 static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
223     SurfaceComposerClient::openGlobalTransaction();
224 }
225
226
227 static void nativeCloseTransaction(JNIEnv* env, jclass clazz, jboolean sync) {
228     SurfaceComposerClient::closeGlobalTransaction(sync);
229 }
230
231 static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
232     SurfaceComposerClient::setAnimationTransaction();
233 }
234
235 static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong nativeObject, jint zorder) {
236     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
237     status_t err = ctrl->setLayer(zorder);
238     if (err < 0 && err != NO_INIT) {
239         doThrowIAE(env);
240     }
241 }
242
243 static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat x, jfloat y) {
244     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
245     status_t err = ctrl->setPosition(x, y);
246     if (err < 0 && err != NO_INIT) {
247         doThrowIAE(env);
248     }
249 }
250
251 static void nativeSetGeometryAppliesWithResize(JNIEnv* env, jclass clazz,
252         jlong nativeObject) {
253     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
254     status_t err = ctrl->setGeometryAppliesWithResize();
255     if (err < 0 && err != NO_INIT) {
256         doThrowIAE(env);
257     }
258 }
259
260 static void nativeSetSize(JNIEnv* env, jclass clazz, jlong nativeObject, jint w, jint h) {
261     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
262     status_t err = ctrl->setSize(w, h);
263     if (err < 0 && err != NO_INIT) {
264         doThrowIAE(env);
265     }
266 }
267
268 static void nativeSetFlags(JNIEnv* env, jclass clazz, jlong nativeObject, jint flags, jint mask) {
269     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
270     status_t err = ctrl->setFlags(flags, mask);
271     if (err < 0 && err != NO_INIT) {
272         doThrowIAE(env);
273     }
274 }
275
276 static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong nativeObject, jobject regionObj) {
277     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
278     SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
279     if (!region) {
280         doThrowIAE(env);
281         return;
282     }
283
284     const SkIRect& b(region->getBounds());
285     Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
286     if (region->isComplex()) {
287         SkRegion::Iterator it(*region);
288         while (!it.done()) {
289             const SkIRect& r(it.rect());
290             reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
291             it.next();
292         }
293     }
294
295     status_t err = ctrl->setTransparentRegionHint(reg);
296     if (err < 0 && err != NO_INIT) {
297         doThrowIAE(env);
298     }
299 }
300
301 static void nativeSetAlpha(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat alpha) {
302     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
303     status_t err = ctrl->setAlpha(alpha);
304     if (err < 0 && err != NO_INIT) {
305         doThrowIAE(env);
306     }
307 }
308
309 static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong nativeObject,
310         jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
311     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
312     status_t err = ctrl->setMatrix(dsdx, dtdx, dsdy, dtdy);
313     if (err < 0 && err != NO_INIT) {
314         doThrowIAE(env);
315     }
316 }
317
318 static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jlong nativeObject,
319         jint l, jint t, jint r, jint b) {
320     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
321     Rect crop(l, t, r, b);
322     status_t err = ctrl->setCrop(crop);
323     if (err < 0 && err != NO_INIT) {
324         doThrowIAE(env);
325     }
326 }
327
328 static void nativeSetFinalCrop(JNIEnv* env, jclass clazz, jlong nativeObject,
329         jint l, jint t, jint r, jint b) {
330     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
331     Rect crop(l, t, r, b);
332     status_t err = ctrl->setFinalCrop(crop);
333     if (err < 0 && err != NO_INIT) {
334         doThrowIAE(env);
335     }
336 }
337
338 static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong nativeObject, jint layerStack) {
339     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
340     status_t err = ctrl->setLayerStack(layerStack);
341     if (err < 0 && err != NO_INIT) {
342         doThrowIAE(env);
343     }
344 }
345
346 static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
347     sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
348     return javaObjectForIBinder(env, token);
349 }
350
351 static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
352         jboolean secure) {
353     ScopedUtfChars name(env, nameObj);
354     sp<IBinder> token(SurfaceComposerClient::createDisplay(
355             String8(name.c_str()), bool(secure)));
356     return javaObjectForIBinder(env, token);
357 }
358
359 static void nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
360     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
361     if (token == NULL) return;
362     SurfaceComposerClient::destroyDisplay(token);
363 }
364
365 static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
366         jobject tokenObj, jlong nativeSurfaceObject) {
367     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
368     if (token == NULL) return;
369     sp<IGraphicBufferProducer> bufferProducer;
370     sp<Surface> sur(reinterpret_cast<Surface *>(nativeSurfaceObject));
371     if (sur != NULL) {
372         bufferProducer = sur->getIGraphicBufferProducer();
373     }
374     SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
375 }
376
377 static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
378         jobject tokenObj, jint layerStack) {
379     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
380     if (token == NULL) return;
381
382     SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
383 }
384
385 static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
386         jobject tokenObj, jint orientation,
387         jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
388         jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
389     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
390     if (token == NULL) return;
391     Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
392     Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
393     SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
394 }
395
396 static void nativeSetDisplaySize(JNIEnv* env, jclass clazz,
397         jobject tokenObj, jint width, jint height) {
398     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
399     if (token == NULL) return;
400     SurfaceComposerClient::setDisplaySize(token, width, height);
401 }
402
403 static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
404         jobject tokenObj) {
405     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
406     if (token == NULL) return NULL;
407
408     Vector<DisplayInfo> configs;
409     if (SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
410             configs.size() == 0) {
411         return NULL;
412     }
413
414     jobjectArray configArray = env->NewObjectArray(configs.size(),
415             gPhysicalDisplayInfoClassInfo.clazz, NULL);
416
417     for (size_t c = 0; c < configs.size(); ++c) {
418         const DisplayInfo& info = configs[c];
419         jobject infoObj = env->NewObject(gPhysicalDisplayInfoClassInfo.clazz,
420                 gPhysicalDisplayInfoClassInfo.ctor);
421         env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
422         env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
423         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
424         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
425         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
426         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
427         env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
428         env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos,
429                 info.appVsyncOffset);
430         env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos,
431                 info.presentationDeadline);
432         env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
433         env->DeleteLocalRef(infoObj);
434     }
435
436     return configArray;
437 }
438
439 static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
440     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
441     if (token == NULL) return -1;
442     return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
443 }
444
445 static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj, jint id) {
446     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
447     if (token == NULL) return JNI_FALSE;
448     status_t err = SurfaceComposerClient::setActiveConfig(token, static_cast<int>(id));
449     return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
450 }
451
452 static jintArray nativeGetDisplayColorModes(JNIEnv* env, jclass, jobject tokenObj) {
453     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
454     if (token == NULL) return NULL;
455     Vector<android_color_mode_t> colorModes;
456     if (SurfaceComposerClient::getDisplayColorModes(token, &colorModes) != NO_ERROR ||
457             colorModes.isEmpty()) {
458         return NULL;
459     }
460
461     jintArray colorModesArray = env->NewIntArray(colorModes.size());
462     if (colorModesArray == NULL) {
463         jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
464         return NULL;
465     }
466     jint* colorModesArrayValues = env->GetIntArrayElements(colorModesArray, 0);
467     for (size_t i = 0; i < colorModes.size(); i++) {
468         colorModesArrayValues[i] = static_cast<jint>(colorModes[i]);
469     }
470     env->ReleaseIntArrayElements(colorModesArray, colorModesArrayValues, 0);
471     return colorModesArray;
472 }
473
474 static jint nativeGetActiveColorMode(JNIEnv* env, jclass, jobject tokenObj) {
475     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
476     if (token == NULL) return -1;
477     return static_cast<jint>(SurfaceComposerClient::getActiveColorMode(token));
478 }
479
480 static jboolean nativeSetActiveColorMode(JNIEnv* env, jclass,
481         jobject tokenObj, jint colorMode) {
482     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
483     if (token == NULL) return JNI_FALSE;
484     status_t err = SurfaceComposerClient::setActiveColorMode(token,
485             static_cast<android_color_mode_t>(colorMode));
486     return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
487 }
488
489 static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) {
490     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
491     if (token == NULL) return;
492
493     ALOGD_IF_SLOW(100, "Excessive delay in setPowerMode()");
494     SurfaceComposerClient::setDisplayPowerMode(token, mode);
495 }
496
497 static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
498     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
499     status_t err = ctrl->clearLayerFrameStats();
500
501     if (err < 0 && err != NO_INIT) {
502         doThrowIAE(env);
503     }
504
505     // The other end is not ready, just report we failed.
506     if (err == NO_INIT) {
507         return JNI_FALSE;
508     }
509
510     return JNI_TRUE;
511 }
512
513 static jboolean nativeGetContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject,
514     jobject outStats) {
515     FrameStats stats;
516
517     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
518     status_t err = ctrl->getLayerFrameStats(&stats);
519     if (err < 0 && err != NO_INIT) {
520         doThrowIAE(env);
521     }
522
523     // The other end is not ready, fine just return empty stats.
524     if (err == NO_INIT) {
525         return JNI_FALSE;
526     }
527
528     jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
529     size_t frameCount = stats.desiredPresentTimesNano.size();
530
531     jlongArray postedTimesNanoDst = env->NewLongArray(frameCount);
532     if (postedTimesNanoDst == NULL) {
533         return JNI_FALSE;
534     }
535
536     jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
537     if (presentedTimesNanoDst == NULL) {
538         return JNI_FALSE;
539     }
540
541     jlongArray readyTimesNanoDst = env->NewLongArray(frameCount);
542     if (readyTimesNanoDst == NULL) {
543         return JNI_FALSE;
544     }
545
546     nsecs_t postedTimesNanoSrc[frameCount];
547     nsecs_t presentedTimesNanoSrc[frameCount];
548     nsecs_t readyTimesNanoSrc[frameCount];
549
550     for (size_t i = 0; i < frameCount; i++) {
551         nsecs_t postedTimeNano = stats.desiredPresentTimesNano[i];
552         if (postedTimeNano == INT64_MAX) {
553             postedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
554         }
555         postedTimesNanoSrc[i] = postedTimeNano;
556
557         nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
558         if (presentedTimeNano == INT64_MAX) {
559             presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
560         }
561         presentedTimesNanoSrc[i] = presentedTimeNano;
562
563         nsecs_t readyTimeNano = stats.frameReadyTimesNano[i];
564         if (readyTimeNano == INT64_MAX) {
565             readyTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
566         }
567         readyTimesNanoSrc[i] = readyTimeNano;
568     }
569
570     env->SetLongArrayRegion(postedTimesNanoDst, 0, frameCount, postedTimesNanoSrc);
571     env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
572     env->SetLongArrayRegion(readyTimesNanoDst, 0, frameCount, readyTimesNanoSrc);
573
574     env->CallVoidMethod(outStats, gWindowContentFrameStatsClassInfo.init, refreshPeriodNano,
575             postedTimesNanoDst, presentedTimesNanoDst, readyTimesNanoDst);
576
577     if (env->ExceptionCheck()) {
578         return JNI_FALSE;
579     }
580
581     return JNI_TRUE;
582 }
583
584 static jboolean nativeClearAnimationFrameStats(JNIEnv* env, jclass clazz) {
585     status_t err = SurfaceComposerClient::clearAnimationFrameStats();
586
587     if (err < 0 && err != NO_INIT) {
588         doThrowIAE(env);
589     }
590
591     // The other end is not ready, just report we failed.
592     if (err == NO_INIT) {
593         return JNI_FALSE;
594     }
595
596     return JNI_TRUE;
597 }
598
599 static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject outStats) {
600     FrameStats stats;
601
602     status_t err = SurfaceComposerClient::getAnimationFrameStats(&stats);
603     if (err < 0 && err != NO_INIT) {
604         doThrowIAE(env);
605     }
606
607     // The other end is not ready, fine just return empty stats.
608     if (err == NO_INIT) {
609         return JNI_FALSE;
610     }
611
612     jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
613     size_t frameCount = stats.desiredPresentTimesNano.size();
614
615     jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
616     if (presentedTimesNanoDst == NULL) {
617         return JNI_FALSE;
618     }
619
620     nsecs_t presentedTimesNanoSrc[frameCount];
621
622     for (size_t i = 0; i < frameCount; i++) {
623         nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
624         if (presentedTimeNano == INT64_MAX) {
625             presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
626         }
627         presentedTimesNanoSrc[i] = presentedTimeNano;
628     }
629
630     env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
631
632     env->CallVoidMethod(outStats, gWindowAnimationFrameStatsClassInfo.init, refreshPeriodNano,
633             presentedTimesNanoDst);
634
635     if (env->ExceptionCheck()) {
636         return JNI_FALSE;
637     }
638
639     return JNI_TRUE;
640 }
641
642
643 static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject,
644         jobject handleObject, jlong frameNumber) {
645     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
646     sp<IBinder> handle = ibinderForJavaObject(env, handleObject);
647
648     ctrl->deferTransactionUntil(handle, frameNumber);
649 }
650
651 static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong nativeObject,
652         jint scalingMode) {
653     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
654
655     ctrl->setOverrideScalingMode(scalingMode);
656 }
657
658 static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
659     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
660
661     return javaObjectForIBinder(env, ctrl->getHandle());
662 }
663
664 static jboolean nativeGetTransformToDisplayInverse(JNIEnv* env, jclass clazz, jlong nativeObject) {
665     bool out = false;
666     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
667     status_t status = ctrl->getTransformToDisplayInverse(&out);
668     if (status != NO_ERROR) {
669         return false;
670     }
671     return out;
672 }
673
674 static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject tokenObject) {
675     sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
676     if (token == NULL) return NULL;
677
678     HdrCapabilities capabilities;
679     SurfaceComposerClient::getHdrCapabilities(token, &capabilities);
680
681     const auto& types = capabilities.getSupportedHdrTypes();
682     auto typesArray = env->NewIntArray(types.size());
683     env->SetIntArrayRegion(typesArray, 0, types.size(), types.data());
684
685     return env->NewObject(gHdrCapabilitiesClassInfo.clazz, gHdrCapabilitiesClassInfo.ctor,
686             typesArray, capabilities.getDesiredMaxLuminance(),
687             capabilities.getDesiredMaxAverageLuminance(), capabilities.getDesiredMinLuminance());
688 }
689
690 // ----------------------------------------------------------------------------
691
692 static const JNINativeMethod sSurfaceControlMethods[] = {
693     {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)J",
694             (void*)nativeCreate },
695     {"nativeRelease", "(J)V",
696             (void*)nativeRelease },
697     {"nativeDestroy", "(J)V",
698             (void*)nativeDestroy },
699     {"nativeDisconnect", "(J)V",
700             (void*)nativeDisconnect },
701     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
702             (void*)nativeScreenshotBitmap },
703     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
704             (void*)nativeScreenshot },
705     {"nativeOpenTransaction", "()V",
706             (void*)nativeOpenTransaction },
707     {"nativeCloseTransaction", "(Z)V",
708             (void*)nativeCloseTransaction },
709     {"nativeSetAnimationTransaction", "()V",
710             (void*)nativeSetAnimationTransaction },
711     {"nativeSetLayer", "(JI)V",
712             (void*)nativeSetLayer },
713     {"nativeSetPosition", "(JFF)V",
714             (void*)nativeSetPosition },
715     {"nativeSetGeometryAppliesWithResize", "(J)V",
716             (void*)nativeSetGeometryAppliesWithResize },
717     {"nativeSetSize", "(JII)V",
718             (void*)nativeSetSize },
719     {"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",
720             (void*)nativeSetTransparentRegionHint },
721     {"nativeSetAlpha", "(JF)V",
722             (void*)nativeSetAlpha },
723     {"nativeSetMatrix", "(JFFFF)V",
724             (void*)nativeSetMatrix },
725     {"nativeSetFlags", "(JII)V",
726             (void*)nativeSetFlags },
727     {"nativeSetWindowCrop", "(JIIII)V",
728             (void*)nativeSetWindowCrop },
729     {"nativeSetFinalCrop", "(JIIII)V",
730             (void*)nativeSetFinalCrop },
731     {"nativeSetLayerStack", "(JI)V",
732             (void*)nativeSetLayerStack },
733     {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
734             (void*)nativeGetBuiltInDisplay },
735     {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
736             (void*)nativeCreateDisplay },
737     {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
738             (void*)nativeDestroyDisplay },
739     {"nativeSetDisplaySurface", "(Landroid/os/IBinder;J)V",
740             (void*)nativeSetDisplaySurface },
741     {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
742             (void*)nativeSetDisplayLayerStack },
743     {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
744             (void*)nativeSetDisplayProjection },
745     {"nativeSetDisplaySize", "(Landroid/os/IBinder;II)V",
746             (void*)nativeSetDisplaySize },
747     {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
748             (void*)nativeGetDisplayConfigs },
749     {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
750             (void*)nativeGetActiveConfig },
751     {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
752             (void*)nativeSetActiveConfig },
753     {"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
754             (void*)nativeGetDisplayColorModes},
755     {"nativeGetActiveColorMode", "(Landroid/os/IBinder;)I",
756             (void*)nativeGetActiveColorMode},
757     {"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z",
758             (void*)nativeSetActiveColorMode},
759     {"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;",
760             (void*)nativeGetHdrCapabilities },
761     {"nativeClearContentFrameStats", "(J)Z",
762             (void*)nativeClearContentFrameStats },
763     {"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
764             (void*)nativeGetContentFrameStats },
765     {"nativeClearAnimationFrameStats", "()Z",
766             (void*)nativeClearAnimationFrameStats },
767     {"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
768             (void*)nativeGetAnimationFrameStats },
769     {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
770             (void*)nativeSetDisplayPowerMode },
771     {"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V",
772             (void*)nativeDeferTransactionUntil },
773     {"nativeSetOverrideScalingMode", "(JI)V",
774             (void*)nativeSetOverrideScalingMode },
775     {"nativeGetHandle", "(J)Landroid/os/IBinder;",
776             (void*)nativeGetHandle },
777     {"nativeGetTransformToDisplayInverse", "(J)Z",
778             (void*)nativeGetTransformToDisplayInverse },
779 };
780
781 int register_android_view_SurfaceControl(JNIEnv* env)
782 {
783     int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl",
784             sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
785
786     jclass clazz = FindClassOrDie(env, "android/view/SurfaceControl$PhysicalDisplayInfo");
787     gPhysicalDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
788     gPhysicalDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env,
789             gPhysicalDisplayInfoClassInfo.clazz, "<init>", "()V");
790     gPhysicalDisplayInfoClassInfo.width =       GetFieldIDOrDie(env, clazz, "width", "I");
791     gPhysicalDisplayInfoClassInfo.height =      GetFieldIDOrDie(env, clazz, "height", "I");
792     gPhysicalDisplayInfoClassInfo.refreshRate = GetFieldIDOrDie(env, clazz, "refreshRate", "F");
793     gPhysicalDisplayInfoClassInfo.density =     GetFieldIDOrDie(env, clazz, "density", "F");
794     gPhysicalDisplayInfoClassInfo.xDpi =        GetFieldIDOrDie(env, clazz, "xDpi", "F");
795     gPhysicalDisplayInfoClassInfo.yDpi =        GetFieldIDOrDie(env, clazz, "yDpi", "F");
796     gPhysicalDisplayInfoClassInfo.secure =      GetFieldIDOrDie(env, clazz, "secure", "Z");
797     gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = GetFieldIDOrDie(env,
798             clazz, "appVsyncOffsetNanos", "J");
799     gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env,
800             clazz, "presentationDeadlineNanos", "J");
801
802     jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
803     gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
804     gRectClassInfo.left =   GetFieldIDOrDie(env, rectClazz, "left", "I");
805     gRectClassInfo.right =  GetFieldIDOrDie(env, rectClazz, "right", "I");
806     gRectClassInfo.top =    GetFieldIDOrDie(env, rectClazz, "top", "I");
807
808     jclass frameStatsClazz = FindClassOrDie(env, "android/view/FrameStats");
809     jfieldID undefined_time_nano_field = GetStaticFieldIDOrDie(env,
810             frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
811     nsecs_t undefined_time_nano = env->GetStaticLongField(frameStatsClazz, undefined_time_nano_field);
812
813     jclass contFrameStatsClazz = FindClassOrDie(env, "android/view/WindowContentFrameStats");
814     gWindowContentFrameStatsClassInfo.init = GetMethodIDOrDie(env,
815             contFrameStatsClazz, "init", "(J[J[J[J)V");
816     gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
817
818     jclass animFrameStatsClazz = FindClassOrDie(env, "android/view/WindowAnimationFrameStats");
819     gWindowAnimationFrameStatsClassInfo.init =  GetMethodIDOrDie(env,
820             animFrameStatsClazz, "init", "(J[J)V");
821     gWindowAnimationFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
822
823     jclass hdrCapabilitiesClazz = FindClassOrDie(env, "android/view/Display$HdrCapabilities");
824     gHdrCapabilitiesClassInfo.clazz = MakeGlobalRefOrDie(env, hdrCapabilitiesClazz);
825     gHdrCapabilitiesClassInfo.ctor = GetMethodIDOrDie(env, hdrCapabilitiesClazz, "<init>",
826             "([IFFF)V");
827
828     return err;
829 }
830
831 };