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 <stdio.h>
20 
21 #include "jni.h"
22 #include "JNIHelp.h"
23 
24 #include "android_os_Parcel.h"
25 #include "android_util_Binder.h"
26 #include "android/graphics/Bitmap.h"
27 #include "android/graphics/GraphicsJNI.h"
28 #include "android/graphics/Region.h"
29 
30 #include "core_jni_helpers.h"
31 #include <android_runtime/android_view_Surface.h>
32 #include <android_runtime/android_view_SurfaceSession.h>
33 
34 #include <gui/Surface.h>
35 #include <gui/SurfaceComposerClient.h>
36 
37 #include <ui/DisplayInfo.h>
38 #include <ui/FrameStats.h>
39 #include <ui/Rect.h>
40 #include <ui/Region.h>
41 
42 #include <utils/Log.h>
43 
44 #include <ScopedUtfChars.h>
45 
46 #include "SkTemplates.h"
47 
48 // ----------------------------------------------------------------------------
49 
50 namespace android {
51 
52 static const char* const OutOfResourcesException =
53     "android/view/Surface$OutOfResourcesException";
54 
55 static struct {
56     jclass clazz;
57     jmethodID ctor;
58     jfieldID width;
59     jfieldID height;
60     jfieldID refreshRate;
61     jfieldID density;
62     jfieldID xDpi;
63     jfieldID yDpi;
64     jfieldID secure;
65     jfieldID appVsyncOffsetNanos;
66     jfieldID presentationDeadlineNanos;
67 } gPhysicalDisplayInfoClassInfo;
68 
69 static struct {
70     jfieldID bottom;
71     jfieldID left;
72     jfieldID right;
73     jfieldID top;
74 } gRectClassInfo;
75 
76 // Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
DeleteScreenshot(void * addr,void * context)77 void DeleteScreenshot(void* addr, void* context) {
78     SkASSERT(addr == ((ScreenshotClient*) context)->getPixels());
79     delete ((ScreenshotClient*) context);
80 }
81 
82 static struct {
83     nsecs_t UNDEFINED_TIME_NANO;
84     jmethodID init;
85 } gWindowContentFrameStatsClassInfo;
86 
87 static struct {
88     nsecs_t UNDEFINED_TIME_NANO;
89     jmethodID init;
90 } gWindowAnimationFrameStatsClassInfo;
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 
nativeScreenshotBitmap(JNIEnv * env,jclass clazz,jobject displayTokenObj,jobject sourceCropObj,jint width,jint height,jint minLayer,jint maxLayer,bool allLayers,bool useIdentityTransform,int rotation)119 static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
120         jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
121         jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
122         int rotation) {
123     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
124     if (displayToken == NULL) {
125         return NULL;
126     }
127 
128     int left = env->GetIntField(sourceCropObj, gRectClassInfo.left);
129     int top = env->GetIntField(sourceCropObj, gRectClassInfo.top);
130     int right = env->GetIntField(sourceCropObj, gRectClassInfo.right);
131     int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom);
132     Rect sourceCrop(left, top, right, bottom);
133 
134     SkAutoTDelete<ScreenshotClient> screenshot(new ScreenshotClient());
135     status_t res;
136     if (allLayers) {
137         minLayer = 0;
138         maxLayer = -1;
139     }
140 
141     res = screenshot->update(displayToken, sourceCrop, width, height,
142         minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation));
143     if (res != NO_ERROR) {
144         return NULL;
145     }
146 
147     SkImageInfo screenshotInfo;
148     screenshotInfo.fWidth = screenshot->getWidth();
149     screenshotInfo.fHeight = screenshot->getHeight();
150 
151     switch (screenshot->getFormat()) {
152         case PIXEL_FORMAT_RGBX_8888: {
153             screenshotInfo.fColorType = kRGBA_8888_SkColorType;
154             screenshotInfo.fAlphaType = kOpaque_SkAlphaType;
155             break;
156         }
157         case PIXEL_FORMAT_RGBA_8888: {
158             screenshotInfo.fColorType = kRGBA_8888_SkColorType;
159             screenshotInfo.fAlphaType = kPremul_SkAlphaType;
160             break;
161         }
162         case PIXEL_FORMAT_RGB_565: {
163             screenshotInfo.fColorType = kRGB_565_SkColorType;
164             screenshotInfo.fAlphaType = kOpaque_SkAlphaType;
165             break;
166         }
167         default: {
168             return NULL;
169         }
170     }
171 
172     const size_t rowBytes =
173             screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());
174 
175     if (!screenshotInfo.fWidth || !screenshotInfo.fHeight) {
176         return NULL;
177     }
178 
179     Bitmap* bitmap = new Bitmap(
180             (void*) screenshot->getPixels(), (void*) screenshot.get(), DeleteScreenshot,
181             screenshotInfo, rowBytes, nullptr);
182     screenshot.detach();
183     bitmap->peekAtPixelRef()->setImmutable();
184 
185     return GraphicsJNI::createBitmap(env, bitmap,
186             GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL);
187 }
188 
nativeScreenshot(JNIEnv * env,jclass clazz,jobject displayTokenObj,jobject surfaceObj,jobject sourceCropObj,jint width,jint height,jint minLayer,jint maxLayer,bool allLayers,bool useIdentityTransform)189 static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
190         jobject surfaceObj, jobject sourceCropObj, jint width, jint height,
191         jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) {
192     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
193     if (displayToken != NULL) {
194         sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
195         if (consumer != NULL) {
196             int left = env->GetIntField(sourceCropObj, gRectClassInfo.left);
197             int top = env->GetIntField(sourceCropObj, gRectClassInfo.top);
198             int right = env->GetIntField(sourceCropObj, gRectClassInfo.right);
199             int bottom = env->GetIntField(sourceCropObj, gRectClassInfo.bottom);
200             Rect sourceCrop(left, top, right, bottom);
201 
202             if (allLayers) {
203                 minLayer = 0;
204                 maxLayer = -1;
205             }
206             ScreenshotClient::capture(displayToken,
207                     consumer->getIGraphicBufferProducer(), sourceCrop,
208                     width, height, uint32_t(minLayer), uint32_t(maxLayer),
209                     useIdentityTransform);
210         }
211     }
212 }
213 
nativeOpenTransaction(JNIEnv * env,jclass clazz)214 static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
215     SurfaceComposerClient::openGlobalTransaction();
216 }
217 
nativeCloseTransaction(JNIEnv * env,jclass clazz)218 static void nativeCloseTransaction(JNIEnv* env, jclass clazz) {
219     SurfaceComposerClient::closeGlobalTransaction();
220 }
221 
nativeSetAnimationTransaction(JNIEnv * env,jclass clazz)222 static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
223     SurfaceComposerClient::setAnimationTransaction();
224 }
225 
nativeSetLayer(JNIEnv * env,jclass clazz,jlong nativeObject,jint zorder)226 static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong nativeObject, jint zorder) {
227     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
228     status_t err = ctrl->setLayer(zorder);
229     if (err < 0 && err != NO_INIT) {
230         doThrowIAE(env);
231     }
232 }
233 
nativeSetPosition(JNIEnv * env,jclass clazz,jlong nativeObject,jfloat x,jfloat y)234 static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat x, jfloat y) {
235     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
236     status_t err = ctrl->setPosition(x, y);
237     if (err < 0 && err != NO_INIT) {
238         doThrowIAE(env);
239     }
240 }
241 
nativeSetSize(JNIEnv * env,jclass clazz,jlong nativeObject,jint w,jint h)242 static void nativeSetSize(JNIEnv* env, jclass clazz, jlong nativeObject, jint w, jint h) {
243     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
244     status_t err = ctrl->setSize(w, h);
245     if (err < 0 && err != NO_INIT) {
246         doThrowIAE(env);
247     }
248 }
249 
nativeSetFlags(JNIEnv * env,jclass clazz,jlong nativeObject,jint flags,jint mask)250 static void nativeSetFlags(JNIEnv* env, jclass clazz, jlong nativeObject, jint flags, jint mask) {
251     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
252     status_t err = ctrl->setFlags(flags, mask);
253     if (err < 0 && err != NO_INIT) {
254         doThrowIAE(env);
255     }
256 }
257 
nativeSetTransparentRegionHint(JNIEnv * env,jclass clazz,jlong nativeObject,jobject regionObj)258 static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong nativeObject, jobject regionObj) {
259     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
260     SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
261     if (!region) {
262         doThrowIAE(env);
263         return;
264     }
265 
266     const SkIRect& b(region->getBounds());
267     Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
268     if (region->isComplex()) {
269         SkRegion::Iterator it(*region);
270         while (!it.done()) {
271             const SkIRect& r(it.rect());
272             reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
273             it.next();
274         }
275     }
276 
277     status_t err = ctrl->setTransparentRegionHint(reg);
278     if (err < 0 && err != NO_INIT) {
279         doThrowIAE(env);
280     }
281 }
282 
nativeSetAlpha(JNIEnv * env,jclass clazz,jlong nativeObject,jfloat alpha)283 static void nativeSetAlpha(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat alpha) {
284     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
285     status_t err = ctrl->setAlpha(alpha);
286     if (err < 0 && err != NO_INIT) {
287         doThrowIAE(env);
288     }
289 }
290 
nativeSetMatrix(JNIEnv * env,jclass clazz,jlong nativeObject,jfloat dsdx,jfloat dtdx,jfloat dsdy,jfloat dtdy)291 static void nativeSetMatrix(JNIEnv* env, jclass clazz, jlong nativeObject,
292         jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
293     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
294     status_t err = ctrl->setMatrix(dsdx, dtdx, dsdy, dtdy);
295     if (err < 0 && err != NO_INIT) {
296         doThrowIAE(env);
297     }
298 }
299 
nativeSetWindowCrop(JNIEnv * env,jclass clazz,jlong nativeObject,jint l,jint t,jint r,jint b)300 static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jlong nativeObject,
301         jint l, jint t, jint r, jint b) {
302     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
303     Rect crop(l, t, r, b);
304     status_t err = ctrl->setCrop(crop);
305     if (err < 0 && err != NO_INIT) {
306         doThrowIAE(env);
307     }
308 }
309 
nativeSetLayerStack(JNIEnv * env,jclass clazz,jlong nativeObject,jint layerStack)310 static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong nativeObject, jint layerStack) {
311     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
312     status_t err = ctrl->setLayerStack(layerStack);
313     if (err < 0 && err != NO_INIT) {
314         doThrowIAE(env);
315     }
316 }
317 
nativeGetBuiltInDisplay(JNIEnv * env,jclass clazz,jint id)318 static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
319     sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
320     return javaObjectForIBinder(env, token);
321 }
322 
nativeCreateDisplay(JNIEnv * env,jclass clazz,jstring nameObj,jboolean secure)323 static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
324         jboolean secure) {
325     ScopedUtfChars name(env, nameObj);
326     sp<IBinder> token(SurfaceComposerClient::createDisplay(
327             String8(name.c_str()), bool(secure)));
328     return javaObjectForIBinder(env, token);
329 }
330 
nativeDestroyDisplay(JNIEnv * env,jclass clazz,jobject tokenObj)331 static void nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
332     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
333     if (token == NULL) return;
334     SurfaceComposerClient::destroyDisplay(token);
335 }
336 
nativeSetDisplaySurface(JNIEnv * env,jclass clazz,jobject tokenObj,jlong nativeSurfaceObject)337 static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
338         jobject tokenObj, jlong nativeSurfaceObject) {
339     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
340     if (token == NULL) return;
341     sp<IGraphicBufferProducer> bufferProducer;
342     sp<Surface> sur(reinterpret_cast<Surface *>(nativeSurfaceObject));
343     if (sur != NULL) {
344         bufferProducer = sur->getIGraphicBufferProducer();
345     }
346     SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
347 }
348 
nativeSetDisplayLayerStack(JNIEnv * env,jclass clazz,jobject tokenObj,jint layerStack)349 static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
350         jobject tokenObj, jint layerStack) {
351     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
352     if (token == NULL) return;
353 
354     SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
355 }
356 
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)357 static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
358         jobject tokenObj, jint orientation,
359         jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
360         jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
361     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
362     if (token == NULL) return;
363     Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
364     Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
365     SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
366 }
367 
nativeSetDisplaySize(JNIEnv * env,jclass clazz,jobject tokenObj,jint width,jint height)368 static void nativeSetDisplaySize(JNIEnv* env, jclass clazz,
369         jobject tokenObj, jint width, jint height) {
370     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
371     if (token == NULL) return;
372     SurfaceComposerClient::setDisplaySize(token, width, height);
373 }
374 
nativeGetDisplayConfigs(JNIEnv * env,jclass clazz,jobject tokenObj)375 static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
376         jobject tokenObj) {
377     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
378     if (token == NULL) return NULL;
379 
380     Vector<DisplayInfo> configs;
381     if (SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
382             configs.size() == 0) {
383         return NULL;
384     }
385 
386     jobjectArray configArray = env->NewObjectArray(configs.size(),
387             gPhysicalDisplayInfoClassInfo.clazz, NULL);
388 
389     for (size_t c = 0; c < configs.size(); ++c) {
390         const DisplayInfo& info = configs[c];
391         jobject infoObj = env->NewObject(gPhysicalDisplayInfoClassInfo.clazz,
392                 gPhysicalDisplayInfoClassInfo.ctor);
393         env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
394         env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
395         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
396         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
397         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
398         env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
399         env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
400         env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos,
401                 info.appVsyncOffset);
402         env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos,
403                 info.presentationDeadline);
404         env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
405         env->DeleteLocalRef(infoObj);
406     }
407 
408     return configArray;
409 }
410 
nativeGetActiveConfig(JNIEnv * env,jclass clazz,jobject tokenObj)411 static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
412     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
413     if (token == NULL) return -1;
414     return static_cast<jint>(SurfaceComposerClient::getActiveConfig(token));
415 }
416 
nativeSetActiveConfig(JNIEnv * env,jclass clazz,jobject tokenObj,jint id)417 static jboolean nativeSetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj, jint id) {
418     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
419     if (token == NULL) return JNI_FALSE;
420     status_t err = SurfaceComposerClient::setActiveConfig(token, static_cast<int>(id));
421     return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
422 }
423 
nativeSetDisplayPowerMode(JNIEnv * env,jclass clazz,jobject tokenObj,jint mode)424 static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) {
425     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
426     if (token == NULL) return;
427 
428     ALOGD_IF_SLOW(100, "Excessive delay in setPowerMode()");
429     SurfaceComposerClient::setDisplayPowerMode(token, mode);
430 }
431 
nativeClearContentFrameStats(JNIEnv * env,jclass clazz,jlong nativeObject)432 static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
433     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
434     status_t err = ctrl->clearLayerFrameStats();
435 
436     if (err < 0 && err != NO_INIT) {
437         doThrowIAE(env);
438     }
439 
440     // The other end is not ready, just report we failed.
441     if (err == NO_INIT) {
442         return JNI_FALSE;
443     }
444 
445     return JNI_TRUE;
446 }
447 
nativeGetContentFrameStats(JNIEnv * env,jclass clazz,jlong nativeObject,jobject outStats)448 static jboolean nativeGetContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject,
449     jobject outStats) {
450     FrameStats stats;
451 
452     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
453     status_t err = ctrl->getLayerFrameStats(&stats);
454     if (err < 0 && err != NO_INIT) {
455         doThrowIAE(env);
456     }
457 
458     // The other end is not ready, fine just return empty stats.
459     if (err == NO_INIT) {
460         return JNI_FALSE;
461     }
462 
463     jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
464     size_t frameCount = stats.desiredPresentTimesNano.size();
465 
466     jlongArray postedTimesNanoDst = env->NewLongArray(frameCount);
467     if (postedTimesNanoDst == NULL) {
468         return JNI_FALSE;
469     }
470 
471     jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
472     if (presentedTimesNanoDst == NULL) {
473         return JNI_FALSE;
474     }
475 
476     jlongArray readyTimesNanoDst = env->NewLongArray(frameCount);
477     if (readyTimesNanoDst == NULL) {
478         return JNI_FALSE;
479     }
480 
481     nsecs_t postedTimesNanoSrc[frameCount];
482     nsecs_t presentedTimesNanoSrc[frameCount];
483     nsecs_t readyTimesNanoSrc[frameCount];
484 
485     for (size_t i = 0; i < frameCount; i++) {
486         nsecs_t postedTimeNano = stats.desiredPresentTimesNano[i];
487         if (postedTimeNano == INT64_MAX) {
488             postedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
489         }
490         postedTimesNanoSrc[i] = postedTimeNano;
491 
492         nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
493         if (presentedTimeNano == INT64_MAX) {
494             presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
495         }
496         presentedTimesNanoSrc[i] = presentedTimeNano;
497 
498         nsecs_t readyTimeNano = stats.frameReadyTimesNano[i];
499         if (readyTimeNano == INT64_MAX) {
500             readyTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
501         }
502         readyTimesNanoSrc[i] = readyTimeNano;
503     }
504 
505     env->SetLongArrayRegion(postedTimesNanoDst, 0, frameCount, postedTimesNanoSrc);
506     env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
507     env->SetLongArrayRegion(readyTimesNanoDst, 0, frameCount, readyTimesNanoSrc);
508 
509     env->CallVoidMethod(outStats, gWindowContentFrameStatsClassInfo.init, refreshPeriodNano,
510             postedTimesNanoDst, presentedTimesNanoDst, readyTimesNanoDst);
511 
512     if (env->ExceptionCheck()) {
513         return JNI_FALSE;
514     }
515 
516     return JNI_TRUE;
517 }
518 
nativeClearAnimationFrameStats(JNIEnv * env,jclass clazz)519 static jboolean nativeClearAnimationFrameStats(JNIEnv* env, jclass clazz) {
520     status_t err = SurfaceComposerClient::clearAnimationFrameStats();
521 
522     if (err < 0 && err != NO_INIT) {
523         doThrowIAE(env);
524     }
525 
526     // The other end is not ready, just report we failed.
527     if (err == NO_INIT) {
528         return JNI_FALSE;
529     }
530 
531     return JNI_TRUE;
532 }
533 
nativeGetAnimationFrameStats(JNIEnv * env,jclass clazz,jobject outStats)534 static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject outStats) {
535     FrameStats stats;
536 
537     status_t err = SurfaceComposerClient::getAnimationFrameStats(&stats);
538     if (err < 0 && err != NO_INIT) {
539         doThrowIAE(env);
540     }
541 
542     // The other end is not ready, fine just return empty stats.
543     if (err == NO_INIT) {
544         return JNI_FALSE;
545     }
546 
547     jlong refreshPeriodNano = static_cast<jlong>(stats.refreshPeriodNano);
548     size_t frameCount = stats.desiredPresentTimesNano.size();
549 
550     jlongArray presentedTimesNanoDst = env->NewLongArray(frameCount);
551     if (presentedTimesNanoDst == NULL) {
552         return JNI_FALSE;
553     }
554 
555     nsecs_t presentedTimesNanoSrc[frameCount];
556 
557     for (size_t i = 0; i < frameCount; i++) {
558         nsecs_t presentedTimeNano = stats.actualPresentTimesNano[i];
559         if (presentedTimeNano == INT64_MAX) {
560             presentedTimeNano = gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO;
561         }
562         presentedTimesNanoSrc[i] = presentedTimeNano;
563     }
564 
565     env->SetLongArrayRegion(presentedTimesNanoDst, 0, frameCount, presentedTimesNanoSrc);
566 
567     env->CallVoidMethod(outStats, gWindowAnimationFrameStatsClassInfo.init, refreshPeriodNano,
568             presentedTimesNanoDst);
569 
570     if (env->ExceptionCheck()) {
571         return JNI_FALSE;
572     }
573 
574     return JNI_TRUE;
575 }
576 
577 // ----------------------------------------------------------------------------
578 
579 static JNINativeMethod sSurfaceControlMethods[] = {
580     {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)J",
581             (void*)nativeCreate },
582     {"nativeRelease", "(J)V",
583             (void*)nativeRelease },
584     {"nativeDestroy", "(J)V",
585             (void*)nativeDestroy },
586     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
587             (void*)nativeScreenshotBitmap },
588     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
589             (void*)nativeScreenshot },
590     {"nativeOpenTransaction", "()V",
591             (void*)nativeOpenTransaction },
592     {"nativeCloseTransaction", "()V",
593             (void*)nativeCloseTransaction },
594     {"nativeSetAnimationTransaction", "()V",
595             (void*)nativeSetAnimationTransaction },
596     {"nativeSetLayer", "(JI)V",
597             (void*)nativeSetLayer },
598     {"nativeSetPosition", "(JFF)V",
599             (void*)nativeSetPosition },
600     {"nativeSetSize", "(JII)V",
601             (void*)nativeSetSize },
602     {"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",
603             (void*)nativeSetTransparentRegionHint },
604     {"nativeSetAlpha", "(JF)V",
605             (void*)nativeSetAlpha },
606     {"nativeSetMatrix", "(JFFFF)V",
607             (void*)nativeSetMatrix },
608     {"nativeSetFlags", "(JII)V",
609             (void*)nativeSetFlags },
610     {"nativeSetWindowCrop", "(JIIII)V",
611             (void*)nativeSetWindowCrop },
612     {"nativeSetLayerStack", "(JI)V",
613             (void*)nativeSetLayerStack },
614     {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
615             (void*)nativeGetBuiltInDisplay },
616     {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
617             (void*)nativeCreateDisplay },
618     {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
619             (void*)nativeDestroyDisplay },
620     {"nativeSetDisplaySurface", "(Landroid/os/IBinder;J)V",
621             (void*)nativeSetDisplaySurface },
622     {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
623             (void*)nativeSetDisplayLayerStack },
624     {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
625             (void*)nativeSetDisplayProjection },
626     {"nativeSetDisplaySize", "(Landroid/os/IBinder;II)V",
627             (void*)nativeSetDisplaySize },
628     {"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
629             (void*)nativeGetDisplayConfigs },
630     {"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
631             (void*)nativeGetActiveConfig },
632     {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
633             (void*)nativeSetActiveConfig },
634     {"nativeClearContentFrameStats", "(J)Z",
635             (void*)nativeClearContentFrameStats },
636     {"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
637             (void*)nativeGetContentFrameStats },
638     {"nativeClearAnimationFrameStats", "()Z",
639             (void*)nativeClearAnimationFrameStats },
640     {"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
641             (void*)nativeGetAnimationFrameStats },
642     {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
643             (void*)nativeSetDisplayPowerMode },
644 };
645 
register_android_view_SurfaceControl(JNIEnv * env)646 int register_android_view_SurfaceControl(JNIEnv* env)
647 {
648     int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl",
649             sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
650 
651     jclass clazz = FindClassOrDie(env, "android/view/SurfaceControl$PhysicalDisplayInfo");
652     gPhysicalDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
653     gPhysicalDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env,
654             gPhysicalDisplayInfoClassInfo.clazz, "<init>", "()V");
655     gPhysicalDisplayInfoClassInfo.width =       GetFieldIDOrDie(env, clazz, "width", "I");
656     gPhysicalDisplayInfoClassInfo.height =      GetFieldIDOrDie(env, clazz, "height", "I");
657     gPhysicalDisplayInfoClassInfo.refreshRate = GetFieldIDOrDie(env, clazz, "refreshRate", "F");
658     gPhysicalDisplayInfoClassInfo.density =     GetFieldIDOrDie(env, clazz, "density", "F");
659     gPhysicalDisplayInfoClassInfo.xDpi =        GetFieldIDOrDie(env, clazz, "xDpi", "F");
660     gPhysicalDisplayInfoClassInfo.yDpi =        GetFieldIDOrDie(env, clazz, "yDpi", "F");
661     gPhysicalDisplayInfoClassInfo.secure =      GetFieldIDOrDie(env, clazz, "secure", "Z");
662     gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = GetFieldIDOrDie(env,
663             clazz, "appVsyncOffsetNanos", "J");
664     gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env,
665             clazz, "presentationDeadlineNanos", "J");
666 
667     jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
668     gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
669     gRectClassInfo.left =   GetFieldIDOrDie(env, rectClazz, "left", "I");
670     gRectClassInfo.right =  GetFieldIDOrDie(env, rectClazz, "right", "I");
671     gRectClassInfo.top =    GetFieldIDOrDie(env, rectClazz, "top", "I");
672 
673     jclass frameStatsClazz = FindClassOrDie(env, "android/view/FrameStats");
674     jfieldID undefined_time_nano_field = GetStaticFieldIDOrDie(env,
675             frameStatsClazz, "UNDEFINED_TIME_NANO", "J");
676     nsecs_t undefined_time_nano = env->GetStaticLongField(frameStatsClazz, undefined_time_nano_field);
677 
678     jclass contFrameStatsClazz = FindClassOrDie(env, "android/view/WindowContentFrameStats");
679     gWindowContentFrameStatsClassInfo.init = GetMethodIDOrDie(env,
680             contFrameStatsClazz, "init", "(J[J[J[J)V");
681     gWindowContentFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
682 
683     jclass animFrameStatsClazz = FindClassOrDie(env, "android/view/WindowAnimationFrameStats");
684     gWindowAnimationFrameStatsClassInfo.init =  GetMethodIDOrDie(env,
685             animFrameStatsClazz, "init", "(J[J)V");
686     gWindowAnimationFrameStatsClassInfo.UNDEFINED_TIME_NANO = undefined_time_nano;
687 
688     return err;
689 }
690 
691 };
692