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 <ui/DisplayInfo.h>
36 #include <ui/HdrCapabilities.h>
37 #include <ui/FrameStats.h>
38 #include <ui/Rect.h>
39 #include <ui/Region.h>
40 #include <utils/Log.h>
41 
42 // ----------------------------------------------------------------------------
43 
44 namespace android {
45 
46 static const char* const OutOfResourcesException =
47     "android/view/Surface$OutOfResourcesException";
48 
49 static struct {
50     jclass clazz;
51     jmethodID ctor;
52     jfieldID width;
53     jfieldID height;
54     jfieldID refreshRate;
55     jfieldID density;
56     jfieldID xDpi;
57     jfieldID yDpi;
58     jfieldID secure;
59     jfieldID appVsyncOffsetNanos;
60     jfieldID presentationDeadlineNanos;
61     jfieldID colorTransform;
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.
DeleteScreenshot(void * addr,void * context)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 
nativeCreate(JNIEnv * env,jclass clazz,jobject sessionObj,jstring nameStr,jint w,jint h,jint format,jint flags)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 
nativeRelease(JNIEnv * env,jclass clazz,jlong nativeObject)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 
nativeDestroy(JNIEnv * env,jclass clazz,jlong nativeObject)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 
nativeDisconnect(JNIEnv * env,jclass clazz,jlong nativeObject)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 
nativeScreenshotBitmap(JNIEnv * env,jclass clazz,jobject displayTokenObj,jobject sourceCropObj,jint width,jint height,jint minLayer,jint maxLayer,bool allLayers,bool useIdentityTransform,int rotation)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 
nativeScreenshot(JNIEnv * env,jclass clazz,jobject displayTokenObj,jobject surfaceObj,jobject sourceCropObj,jint width,jint height,jint minLayer,jint maxLayer,bool allLayers,bool useIdentityTransform)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 
nativeOpenTransaction(JNIEnv * env,jclass clazz)222 static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
223     SurfaceComposerClient::openGlobalTransaction();
224 }
225 
226 
nativeCloseTransaction(JNIEnv * env,jclass clazz,jboolean sync)227 static void nativeCloseTransaction(JNIEnv* env, jclass clazz, jboolean sync) {
228     SurfaceComposerClient::closeGlobalTransaction(sync);
229 }
230 
nativeSetAnimationTransaction(JNIEnv * env,jclass clazz)231 static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
232     SurfaceComposerClient::setAnimationTransaction();
233 }
234 
nativeSetLayer(JNIEnv * env,jclass clazz,jlong nativeObject,jint zorder)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 
nativeSetPosition(JNIEnv * env,jclass clazz,jlong nativeObject,jfloat x,jfloat y)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 
nativeSetPositionAppliesWithResize(JNIEnv * env,jclass clazz,jlong nativeObject)251 static void nativeSetPositionAppliesWithResize(JNIEnv* env, jclass clazz,
252         jlong nativeObject) {
253     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
254     status_t err = ctrl->setPositionAppliesWithResize();
255     if (err < 0 && err != NO_INIT) {
256         doThrowIAE(env);
257     }
258 }
259 
nativeSetSize(JNIEnv * env,jclass clazz,jlong nativeObject,jint w,jint h)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 
nativeSetFlags(JNIEnv * env,jclass clazz,jlong nativeObject,jint flags,jint mask)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 
nativeSetTransparentRegionHint(JNIEnv * env,jclass clazz,jlong nativeObject,jobject regionObj)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 
nativeSetAlpha(JNIEnv * env,jclass clazz,jlong nativeObject,jfloat alpha)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 
nativeSetMatrix(JNIEnv * env,jclass clazz,jlong nativeObject,jfloat dsdx,jfloat dtdx,jfloat dsdy,jfloat dtdy)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 
nativeSetWindowCrop(JNIEnv * env,jclass clazz,jlong nativeObject,jint l,jint t,jint r,jint b)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 
nativeSetFinalCrop(JNIEnv * env,jclass clazz,jlong nativeObject,jint l,jint t,jint r,jint b)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 
nativeSetLayerStack(JNIEnv * env,jclass clazz,jlong nativeObject,jint layerStack)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 
nativeGetBuiltInDisplay(JNIEnv * env,jclass clazz,jint id)346 static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
347     sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
348     return javaObjectForIBinder(env, token);
349 }
350 
nativeCreateDisplay(JNIEnv * env,jclass clazz,jstring nameObj,jboolean secure)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 
nativeDestroyDisplay(JNIEnv * env,jclass clazz,jobject tokenObj)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 
nativeSetDisplaySurface(JNIEnv * env,jclass clazz,jobject tokenObj,jlong nativeSurfaceObject)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 
nativeSetDisplayLayerStack(JNIEnv * env,jclass clazz,jobject tokenObj,jint layerStack)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 
nativeSetDisplayProjection(JNIEnv * env,jclass clazz,jobject tokenObj,jint orientation,jint layerStackRect_left,jint layerStackRect_top,jint layerStackRect_right,jint layerStackRect_bottom,jint displayRect_left,jint displayRect_top,jint displayRect_right,jint displayRect_bottom)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 
nativeSetDisplaySize(JNIEnv * env,jclass clazz,jobject tokenObj,jint width,jint height)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 
nativeGetDisplayConfigs(JNIEnv * env,jclass clazz,jobject tokenObj)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->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.colorTransform,
433                 info.colorTransform);
434         env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
435         env->DeleteLocalRef(infoObj);
436     }
437 
438     return configArray;
439 }
440 
nativeGetActiveConfig(JNIEnv * env,jclass clazz,jobject tokenObj)441 static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
442     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
443     if (token == NULL) return -1;
444     return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
445 }
446 
nativeSetActiveConfig(JNIEnv * env,jclass clazz,jobject tokenObj,jint id)447 static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj, jint id) {
448     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
449     if (token == NULL) return JNI_FALSE;
450     status_t err = SurfaceComposerClient::setActiveConfig(token, static_cast<int>(id));
451     return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
452 }
453 
nativeSetDisplayPowerMode(JNIEnv * env,jclass clazz,jobject tokenObj,jint mode)454 static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) {
455     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
456     if (token == NULL) return;
457 
458     ALOGD_IF_SLOW(100, "Excessive delay in setPowerMode()");
459     SurfaceComposerClient::setDisplayPowerMode(token, mode);
460 }
461 
nativeClearContentFrameStats(JNIEnv * env,jclass clazz,jlong nativeObject)462 static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
463     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
464     status_t err = ctrl->clearLayerFrameStats();
465 
466     if (err < 0 && err != NO_INIT) {
467         doThrowIAE(env);
468     }
469 
470     // The other end is not ready, just report we failed.
471     if (err == NO_INIT) {
472         return JNI_FALSE;
473     }
474 
475     return JNI_TRUE;
476 }
477 
nativeGetContentFrameStats(JNIEnv * env,jclass clazz,jlong nativeObject,jobject outStats)478 static jboolean nativeGetContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject,
479     jobject outStats) {
480     FrameStats stats;
481 
482     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
483     status_t err = ctrl->getLayerFrameStats(&stats);
484     if (err < 0 && err != NO_INIT) {
485         doThrowIAE(env);
486     }
487 
488     // The other end is not ready, fine just return empty stats.
489     if (err == NO_INIT) {
490         return JNI_FALSE;
491     }
492 
493     jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
494     size_t frameCount = stats.desiredPresentTimesNano.size();
495 
496     jlongArray postedTimesNanoDst = env->NewLongArray(frameCount);
497     if (postedTimesNanoDst == NULL) {
498         return JNI_FALSE;
499     }
500 
501     jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
502     if (presentedTimesNanoDst == NULL) {
503         return JNI_FALSE;
504     }
505 
506     jlongArray readyTimesNanoDst = env->NewLongArray(frameCount);
507     if (readyTimesNanoDst == NULL) {
508         return JNI_FALSE;
509     }
510 
511     nsecs_t postedTimesNanoSrc[frameCount];
512     nsecs_t presentedTimesNanoSrc[frameCount];
513     nsecs_t readyTimesNanoSrc[frameCount];
514 
515     for (size_t i = 0; i < frameCount; i++) {
516         nsecs_t postedTimeNano = stats.desiredPresentTimesNano[i];
517         if (postedTimeNano == INT64_MAX) {
518             postedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
519         }
520         postedTimesNanoSrc[i] = postedTimeNano;
521 
522         nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
523         if (presentedTimeNano == INT64_MAX) {
524             presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
525         }
526         presentedTimesNanoSrc[i] = presentedTimeNano;
527 
528         nsecs_t readyTimeNano = stats.frameReadyTimesNano[i];
529         if (readyTimeNano == INT64_MAX) {
530             readyTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
531         }
532         readyTimesNanoSrc[i] = readyTimeNano;
533     }
534 
535     env->SetLongArrayRegion(postedTimesNanoDst, 0, frameCount, postedTimesNanoSrc);
536     env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
537     env->SetLongArrayRegion(readyTimesNanoDst, 0, frameCount, readyTimesNanoSrc);
538 
539     env->CallVoidMethod(outStats, gWindowContentFrameStatsClassInfo.init, refreshPeriodNano,
540             postedTimesNanoDst, presentedTimesNanoDst, readyTimesNanoDst);
541 
542     if (env->ExceptionCheck()) {
543         return JNI_FALSE;
544     }
545 
546     return JNI_TRUE;
547 }
548 
nativeClearAnimationFrameStats(JNIEnv * env,jclass clazz)549 static jboolean nativeClearAnimationFrameStats(JNIEnv* env, jclass clazz) {
550     status_t err = SurfaceComposerClient::clearAnimationFrameStats();
551 
552     if (err < 0 && err != NO_INIT) {
553         doThrowIAE(env);
554     }
555 
556     // The other end is not ready, just report we failed.
557     if (err == NO_INIT) {
558         return JNI_FALSE;
559     }
560 
561     return JNI_TRUE;
562 }
563 
nativeGetAnimationFrameStats(JNIEnv * env,jclass clazz,jobject outStats)564 static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject outStats) {
565     FrameStats stats;
566 
567     status_t err = SurfaceComposerClient::getAnimationFrameStats(&stats);
568     if (err < 0 && err != NO_INIT) {
569         doThrowIAE(env);
570     }
571 
572     // The other end is not ready, fine just return empty stats.
573     if (err == NO_INIT) {
574         return JNI_FALSE;
575     }
576 
577     jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
578     size_t frameCount = stats.desiredPresentTimesNano.size();
579 
580     jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
581     if (presentedTimesNanoDst == NULL) {
582         return JNI_FALSE;
583     }
584 
585     nsecs_t presentedTimesNanoSrc[frameCount];
586 
587     for (size_t i = 0; i < frameCount; i++) {
588         nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
589         if (presentedTimeNano == INT64_MAX) {
590             presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
591         }
592         presentedTimesNanoSrc[i] = presentedTimeNano;
593     }
594 
595     env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
596 
597     env->CallVoidMethod(outStats, gWindowAnimationFrameStatsClassInfo.init, refreshPeriodNano,
598             presentedTimesNanoDst);
599 
600     if (env->ExceptionCheck()) {
601         return JNI_FALSE;
602     }
603 
604     return JNI_TRUE;
605 }
606 
607 
nativeDeferTransactionUntil(JNIEnv * env,jclass clazz,jlong nativeObject,jobject handleObject,jlong frameNumber)608 static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject,
609         jobject handleObject, jlong frameNumber) {
610     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
611     sp<IBinder> handle = ibinderForJavaObject(env, handleObject);
612 
613     ctrl->deferTransactionUntil(handle, frameNumber);
614 }
615 
nativeSetOverrideScalingMode(JNIEnv * env,jclass clazz,jlong nativeObject,jint scalingMode)616 static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong nativeObject,
617         jint scalingMode) {
618     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
619 
620     ctrl->setOverrideScalingMode(scalingMode);
621 }
622 
nativeGetHandle(JNIEnv * env,jclass clazz,jlong nativeObject)623 static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
624     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
625 
626     return javaObjectForIBinder(env, ctrl->getHandle());
627 }
628 
nativeGetHdrCapabilities(JNIEnv * env,jclass clazz,jobject tokenObject)629 static jobject nativeGetHdrCapabilities(JNIEnv* env, jclass clazz, jobject tokenObject) {
630     sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
631     if (token == NULL) return NULL;
632 
633     HdrCapabilities capabilities;
634     SurfaceComposerClient::getHdrCapabilities(token, &capabilities);
635 
636     const auto& types = capabilities.getSupportedHdrTypes();
637     auto typesArray = env->NewIntArray(types.size());
638     env->SetIntArrayRegion(typesArray, 0, types.size(), types.data());
639 
640     return env->NewObject(gHdrCapabilitiesClassInfo.clazz, gHdrCapabilitiesClassInfo.ctor,
641             typesArray, capabilities.getDesiredMaxLuminance(),
642             capabilities.getDesiredMaxAverageLuminance(), capabilities.getDesiredMinLuminance());
643 }
644 
645 // ----------------------------------------------------------------------------
646 
647 static const JNINativeMethod sSurfaceControlMethods[] = {
648     {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)J",
649             (void*)nativeCreate },
650     {"nativeRelease", "(J)V",
651             (void*)nativeRelease },
652     {"nativeDestroy", "(J)V",
653             (void*)nativeDestroy },
654     {"nativeDisconnect", "(J)V",
655             (void*)nativeDisconnect },
656     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
657             (void*)nativeScreenshotBitmap },
658     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
659             (void*)nativeScreenshot },
660     {"nativeOpenTransaction", "()V",
661             (void*)nativeOpenTransaction },
662     {"nativeCloseTransaction", "(Z)V",
663             (void*)nativeCloseTransaction },
664     {"nativeSetAnimationTransaction", "()V",
665             (void*)nativeSetAnimationTransaction },
666     {"nativeSetLayer", "(JI)V",
667             (void*)nativeSetLayer },
668     {"nativeSetPosition", "(JFF)V",
669             (void*)nativeSetPosition },
670     {"nativeSetPositionAppliesWithResize", "(J)V",
671             (void*)nativeSetPositionAppliesWithResize },
672     {"nativeSetSize", "(JII)V",
673             (void*)nativeSetSize },
674     {"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",
675             (void*)nativeSetTransparentRegionHint },
676     {"nativeSetAlpha", "(JF)V",
677             (void*)nativeSetAlpha },
678     {"nativeSetMatrix", "(JFFFF)V",
679             (void*)nativeSetMatrix },
680     {"nativeSetFlags", "(JII)V",
681             (void*)nativeSetFlags },
682     {"nativeSetWindowCrop", "(JIIII)V",
683             (void*)nativeSetWindowCrop },
684     {"nativeSetFinalCrop", "(JIIII)V",
685             (void*)nativeSetFinalCrop },
686     {"nativeSetLayerStack", "(JI)V",
687             (void*)nativeSetLayerStack },
688     {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
689             (void*)nativeGetBuiltInDisplay },
690     {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
691             (void*)nativeCreateDisplay },
692     {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
693             (void*)nativeDestroyDisplay },
694     {"nativeSetDisplaySurface", "(Landroid/os/IBinder;J)V",
695             (void*)nativeSetDisplaySurface },
696     {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
697             (void*)nativeSetDisplayLayerStack },
698     {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
699             (void*)nativeSetDisplayProjection },
700     {"nativeSetDisplaySize", "(Landroid/os/IBinder;II)V",
701             (void*)nativeSetDisplaySize },
702     {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
703             (void*)nativeGetDisplayConfigs },
704     {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
705             (void*)nativeGetActiveConfig },
706     {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
707             (void*)nativeSetActiveConfig },
708     {"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;",
709             (void*)nativeGetHdrCapabilities },
710     {"nativeClearContentFrameStats", "(J)Z",
711             (void*)nativeClearContentFrameStats },
712     {"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
713             (void*)nativeGetContentFrameStats },
714     {"nativeClearAnimationFrameStats", "()Z",
715             (void*)nativeClearAnimationFrameStats },
716     {"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
717             (void*)nativeGetAnimationFrameStats },
718     {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
719             (void*)nativeSetDisplayPowerMode },
720     {"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V",
721             (void*)nativeDeferTransactionUntil },
722     {"nativeSetOverrideScalingMode", "(JI)V",
723             (void*)nativeSetOverrideScalingMode },
724     {"nativeGetHandle", "(J)Landroid/os/IBinder;",
725             (void*)nativeGetHandle }
726 };
727 
register_android_view_SurfaceControl(JNIEnv * env)728 int register_android_view_SurfaceControl(JNIEnv* env)
729 {
730     int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl",
731             sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
732 
733     jclass clazz = FindClassOrDie(env, "android/view/SurfaceControl$PhysicalDisplayInfo");
734     gPhysicalDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
735     gPhysicalDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env,
736             gPhysicalDisplayInfoClassInfo.clazz, "<init>", "()V");
737     gPhysicalDisplayInfoClassInfo.width =       GetFieldIDOrDie(env, clazz, "width", "I");
738     gPhysicalDisplayInfoClassInfo.height =      GetFieldIDOrDie(env, clazz, "height", "I");
739     gPhysicalDisplayInfoClassInfo.refreshRate = GetFieldIDOrDie(env, clazz, "refreshRate", "F");
740     gPhysicalDisplayInfoClassInfo.density =     GetFieldIDOrDie(env, clazz, "density", "F");
741     gPhysicalDisplayInfoClassInfo.xDpi =        GetFieldIDOrDie(env, clazz, "xDpi", "F");
742     gPhysicalDisplayInfoClassInfo.yDpi =        GetFieldIDOrDie(env, clazz, "yDpi", "F");
743     gPhysicalDisplayInfoClassInfo.secure =      GetFieldIDOrDie(env, clazz, "secure", "Z");
744     gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = GetFieldIDOrDie(env,
745             clazz, "appVsyncOffsetNanos", "J");
746     gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env,
747             clazz, "presentationDeadlineNanos", "J");
748     gPhysicalDisplayInfoClassInfo.colorTransform = GetFieldIDOrDie(env, clazz,
749             "colorTransform", "I");
750 
751     jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
752     gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
753     gRectClassInfo.left =   GetFieldIDOrDie(env, rectClazz, "left", "I");
754     gRectClassInfo.right =  GetFieldIDOrDie(env, rectClazz, "right", "I");
755     gRectClassInfo.top =    GetFieldIDOrDie(env, rectClazz, "top", "I");
756 
757     jclass frameStatsClazz = FindClassOrDie(env, "android/view/FrameStats");
758     jfieldID undefined_time_nano_field = GetStaticFieldIDOrDie(env,
759             frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
760     nsecs_t undefined_time_nano = env->GetStaticLongField(frameStatsClazz, undefined_time_nano_field);
761 
762     jclass contFrameStatsClazz = FindClassOrDie(env, "android/view/WindowContentFrameStats");
763     gWindowContentFrameStatsClassInfo.init = GetMethodIDOrDie(env,
764             contFrameStatsClazz, "init", "(J[J[J[J)V");
765     gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
766 
767     jclass animFrameStatsClazz = FindClassOrDie(env, "android/view/WindowAnimationFrameStats");
768     gWindowAnimationFrameStatsClassInfo.init =  GetMethodIDOrDie(env,
769             animFrameStatsClazz, "init", "(J[J)V");
770     gWindowAnimationFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
771 
772     jclass hdrCapabilitiesClazz = FindClassOrDie(env, "android/view/Display$HdrCapabilities");
773     gHdrCapabilitiesClassInfo.clazz = MakeGlobalRefOrDie(env, hdrCapabilitiesClazz);
774     gHdrCapabilitiesClassInfo.ctor = GetMethodIDOrDie(env, hdrCapabilitiesClazz, "<init>",
775             "([IFFF)V");
776 
777     return err;
778 }
779 
780 };
781