xref: /aosp_15_r20/external/skia/src/gpu/ganesh/gl/AHardwareBufferGL.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2023 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/android/GrAHardwareBufferUtils.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
11*c8dee2aaSAndroid Build Coastguard Worker #define GL_GLEXT_PROTOTYPES
12*c8dee2aaSAndroid Build Coastguard Worker #define EGL_EGLEXT_PROTOTYPES
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrBackendSurface.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/gl/GrGLBackendSurface.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/gl/GrGLTypes.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDirectContextPriv.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/gl/GrGLDefines.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/gl/GrGLUtil.h"
21*c8dee2aaSAndroid Build Coastguard Worker 
22*c8dee2aaSAndroid Build Coastguard Worker #include <android/hardware_buffer.h>
23*c8dee2aaSAndroid Build Coastguard Worker #include <EGL/egl.h>
24*c8dee2aaSAndroid Build Coastguard Worker #include <EGL/eglext.h>
25*c8dee2aaSAndroid Build Coastguard Worker #include <GLES/gl.h>
26*c8dee2aaSAndroid Build Coastguard Worker #include <GLES/glext.h>
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
29*c8dee2aaSAndroid Build Coastguard Worker #define EGL_PROTECTED_CONTENT_EXT 0x32C0
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker namespace GrAHardwareBufferUtils {
32*c8dee2aaSAndroid Build Coastguard Worker 
GetGLBackendFormat(GrDirectContext * dContext,uint32_t bufferFormat,bool requireKnownFormat)33*c8dee2aaSAndroid Build Coastguard Worker GrBackendFormat GetGLBackendFormat(GrDirectContext* dContext,
34*c8dee2aaSAndroid Build Coastguard Worker                                    uint32_t bufferFormat, bool requireKnownFormat) {
35*c8dee2aaSAndroid Build Coastguard Worker     GrBackendApi backend = dContext->backend();
36*c8dee2aaSAndroid Build Coastguard Worker     if (backend != GrBackendApi::kOpenGL) {
37*c8dee2aaSAndroid Build Coastguard Worker         return GrBackendFormat();
38*c8dee2aaSAndroid Build Coastguard Worker     }
39*c8dee2aaSAndroid Build Coastguard Worker     switch (bufferFormat) {
40*c8dee2aaSAndroid Build Coastguard Worker         //TODO: find out if we can detect, which graphic buffers support GR_GL_TEXTURE_2D
41*c8dee2aaSAndroid Build Coastguard Worker         case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
42*c8dee2aaSAndroid Build Coastguard Worker         case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
43*c8dee2aaSAndroid Build Coastguard Worker             return GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
44*c8dee2aaSAndroid Build Coastguard Worker         case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
45*c8dee2aaSAndroid Build Coastguard Worker             return GrBackendFormats::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_EXTERNAL);
46*c8dee2aaSAndroid Build Coastguard Worker         case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
47*c8dee2aaSAndroid Build Coastguard Worker             return GrBackendFormats::MakeGL(GR_GL_RGB565, GR_GL_TEXTURE_EXTERNAL);
48*c8dee2aaSAndroid Build Coastguard Worker         case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
49*c8dee2aaSAndroid Build Coastguard Worker             return GrBackendFormats::MakeGL(GR_GL_RGB10_A2, GR_GL_TEXTURE_EXTERNAL);
50*c8dee2aaSAndroid Build Coastguard Worker         case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
51*c8dee2aaSAndroid Build Coastguard Worker             return GrBackendFormats::MakeGL(GR_GL_RGB8, GR_GL_TEXTURE_EXTERNAL);
52*c8dee2aaSAndroid Build Coastguard Worker #if __ANDROID_API__ >= 33
53*c8dee2aaSAndroid Build Coastguard Worker         case AHARDWAREBUFFER_FORMAT_R8_UNORM:
54*c8dee2aaSAndroid Build Coastguard Worker             return GrBackendFormats::MakeGL(GR_GL_R8, GR_GL_TEXTURE_EXTERNAL);
55*c8dee2aaSAndroid Build Coastguard Worker #endif
56*c8dee2aaSAndroid Build Coastguard Worker         default:
57*c8dee2aaSAndroid Build Coastguard Worker             if (requireKnownFormat) {
58*c8dee2aaSAndroid Build Coastguard Worker                 return GrBackendFormat();
59*c8dee2aaSAndroid Build Coastguard Worker             } else {
60*c8dee2aaSAndroid Build Coastguard Worker                 return GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
61*c8dee2aaSAndroid Build Coastguard Worker             }
62*c8dee2aaSAndroid Build Coastguard Worker     }
63*c8dee2aaSAndroid Build Coastguard Worker     SkUNREACHABLE;
64*c8dee2aaSAndroid Build Coastguard Worker }
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker class GLTextureHelper {
67*c8dee2aaSAndroid Build Coastguard Worker public:
GLTextureHelper(GrGLuint texID,EGLImageKHR image,EGLDisplay display,GrGLuint texTarget)68*c8dee2aaSAndroid Build Coastguard Worker     GLTextureHelper(GrGLuint texID, EGLImageKHR image, EGLDisplay display, GrGLuint texTarget)
69*c8dee2aaSAndroid Build Coastguard Worker         : fTexID(texID)
70*c8dee2aaSAndroid Build Coastguard Worker         , fImage(image)
71*c8dee2aaSAndroid Build Coastguard Worker         , fDisplay(display)
72*c8dee2aaSAndroid Build Coastguard Worker         , fTexTarget(texTarget) { }
~GLTextureHelper()73*c8dee2aaSAndroid Build Coastguard Worker     ~GLTextureHelper() {
74*c8dee2aaSAndroid Build Coastguard Worker         glDeleteTextures(1, &fTexID);
75*c8dee2aaSAndroid Build Coastguard Worker         // eglDestroyImageKHR will remove a ref from the AHardwareBuffer
76*c8dee2aaSAndroid Build Coastguard Worker         eglDestroyImageKHR(fDisplay, fImage);
77*c8dee2aaSAndroid Build Coastguard Worker     }
78*c8dee2aaSAndroid Build Coastguard Worker     void rebind(GrDirectContext*);
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker private:
81*c8dee2aaSAndroid Build Coastguard Worker     GrGLuint    fTexID;
82*c8dee2aaSAndroid Build Coastguard Worker     EGLImageKHR fImage;
83*c8dee2aaSAndroid Build Coastguard Worker     EGLDisplay  fDisplay;
84*c8dee2aaSAndroid Build Coastguard Worker     GrGLuint    fTexTarget;
85*c8dee2aaSAndroid Build Coastguard Worker };
86*c8dee2aaSAndroid Build Coastguard Worker 
rebind(GrDirectContext * dContext)87*c8dee2aaSAndroid Build Coastguard Worker void GLTextureHelper::rebind(GrDirectContext* dContext) {
88*c8dee2aaSAndroid Build Coastguard Worker     glBindTexture(fTexTarget, fTexID);
89*c8dee2aaSAndroid Build Coastguard Worker     GLenum status = GL_NO_ERROR;
90*c8dee2aaSAndroid Build Coastguard Worker     if ((status = glGetError()) != GL_NO_ERROR) {
91*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("glBindTexture(%#x, %d) failed (%#x)", (int) fTexTarget,
92*c8dee2aaSAndroid Build Coastguard Worker             (int) fTexID, (int) status);
93*c8dee2aaSAndroid Build Coastguard Worker         return;
94*c8dee2aaSAndroid Build Coastguard Worker     }
95*c8dee2aaSAndroid Build Coastguard Worker     glEGLImageTargetTexture2DOES(fTexTarget, fImage);
96*c8dee2aaSAndroid Build Coastguard Worker     if ((status = glGetError()) != GL_NO_ERROR) {
97*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("glEGLImageTargetTexture2DOES failed (%#x)", (int) status);
98*c8dee2aaSAndroid Build Coastguard Worker         return;
99*c8dee2aaSAndroid Build Coastguard Worker     }
100*c8dee2aaSAndroid Build Coastguard Worker     dContext->resetContext(kTextureBinding_GrGLBackendState);
101*c8dee2aaSAndroid Build Coastguard Worker }
102*c8dee2aaSAndroid Build Coastguard Worker 
delete_gl_texture(void * context)103*c8dee2aaSAndroid Build Coastguard Worker void delete_gl_texture(void* context) {
104*c8dee2aaSAndroid Build Coastguard Worker     GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context);
105*c8dee2aaSAndroid Build Coastguard Worker     delete cleanupHelper;
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker 
update_gl_texture(void * context,GrDirectContext * dContext)108*c8dee2aaSAndroid Build Coastguard Worker void update_gl_texture(void* context, GrDirectContext* dContext) {
109*c8dee2aaSAndroid Build Coastguard Worker     GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context);
110*c8dee2aaSAndroid Build Coastguard Worker     cleanupHelper->rebind(dContext);
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker 
make_gl_backend_texture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & backendFormat,bool isRenderable)113*c8dee2aaSAndroid Build Coastguard Worker static GrBackendTexture make_gl_backend_texture(
114*c8dee2aaSAndroid Build Coastguard Worker         GrDirectContext* dContext,
115*c8dee2aaSAndroid Build Coastguard Worker         AHardwareBuffer* hardwareBuffer,
116*c8dee2aaSAndroid Build Coastguard Worker         int width, int height,
117*c8dee2aaSAndroid Build Coastguard Worker         DeleteImageProc* deleteProc,
118*c8dee2aaSAndroid Build Coastguard Worker         UpdateImageProc* updateProc,
119*c8dee2aaSAndroid Build Coastguard Worker         TexImageCtx* imageCtx,
120*c8dee2aaSAndroid Build Coastguard Worker         bool isProtectedContent,
121*c8dee2aaSAndroid Build Coastguard Worker         const GrBackendFormat& backendFormat,
122*c8dee2aaSAndroid Build Coastguard Worker         bool isRenderable) {
123*c8dee2aaSAndroid Build Coastguard Worker     while (GL_NO_ERROR != glGetError()) {} //clear GL errors
124*c8dee2aaSAndroid Build Coastguard Worker 
125*c8dee2aaSAndroid Build Coastguard Worker     EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer);
126*c8dee2aaSAndroid Build Coastguard Worker     EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
127*c8dee2aaSAndroid Build Coastguard Worker                          isProtectedContent ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
128*c8dee2aaSAndroid Build Coastguard Worker                          isProtectedContent ? EGL_TRUE : EGL_NONE,
129*c8dee2aaSAndroid Build Coastguard Worker                          EGL_NONE };
130*c8dee2aaSAndroid Build Coastguard Worker     EGLDisplay display = eglGetCurrentDisplay();
131*c8dee2aaSAndroid Build Coastguard Worker     // eglCreateImageKHR will add a ref to the AHardwareBuffer
132*c8dee2aaSAndroid Build Coastguard Worker     EGLImageKHR image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
133*c8dee2aaSAndroid Build Coastguard Worker                                           clientBuffer, attribs);
134*c8dee2aaSAndroid Build Coastguard Worker     if (EGL_NO_IMAGE_KHR == image) {
135*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("Could not create EGL image, err = (%#x)", (int) eglGetError() );
136*c8dee2aaSAndroid Build Coastguard Worker         return GrBackendTexture();
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker     GrGLuint texID;
140*c8dee2aaSAndroid Build Coastguard Worker     glGenTextures(1, &texID);
141*c8dee2aaSAndroid Build Coastguard Worker     if (!texID) {
142*c8dee2aaSAndroid Build Coastguard Worker         eglDestroyImageKHR(display, image);
143*c8dee2aaSAndroid Build Coastguard Worker         return GrBackendTexture();
144*c8dee2aaSAndroid Build Coastguard Worker     }
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker     GrGLuint target = isRenderable ? GR_GL_TEXTURE_2D : GR_GL_TEXTURE_EXTERNAL;
147*c8dee2aaSAndroid Build Coastguard Worker 
148*c8dee2aaSAndroid Build Coastguard Worker     glBindTexture(target, texID);
149*c8dee2aaSAndroid Build Coastguard Worker     GLenum status = GL_NO_ERROR;
150*c8dee2aaSAndroid Build Coastguard Worker     if ((status = glGetError()) != GL_NO_ERROR) {
151*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("glBindTexture failed (%#x)", (int) status);
152*c8dee2aaSAndroid Build Coastguard Worker         glDeleteTextures(1, &texID);
153*c8dee2aaSAndroid Build Coastguard Worker         eglDestroyImageKHR(display, image);
154*c8dee2aaSAndroid Build Coastguard Worker         return GrBackendTexture();
155*c8dee2aaSAndroid Build Coastguard Worker     }
156*c8dee2aaSAndroid Build Coastguard Worker     glEGLImageTargetTexture2DOES(target, image);
157*c8dee2aaSAndroid Build Coastguard Worker     if ((status = glGetError()) != GL_NO_ERROR) {
158*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("glEGLImageTargetTexture2DOES failed (%#x)", (int) status);
159*c8dee2aaSAndroid Build Coastguard Worker         glDeleteTextures(1, &texID);
160*c8dee2aaSAndroid Build Coastguard Worker         eglDestroyImageKHR(display, image);
161*c8dee2aaSAndroid Build Coastguard Worker         return GrBackendTexture();
162*c8dee2aaSAndroid Build Coastguard Worker     }
163*c8dee2aaSAndroid Build Coastguard Worker     dContext->resetContext(kTextureBinding_GrGLBackendState);
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     GrGLTextureInfo textureInfo;
166*c8dee2aaSAndroid Build Coastguard Worker     textureInfo.fID = texID;
167*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(backendFormat.isValid());
168*c8dee2aaSAndroid Build Coastguard Worker     textureInfo.fTarget = target;
169*c8dee2aaSAndroid Build Coastguard Worker     textureInfo.fFormat = GrBackendFormats::AsGLFormatEnum(backendFormat);
170*c8dee2aaSAndroid Build Coastguard Worker     textureInfo.fProtected = skgpu::Protected(isProtectedContent);
171*c8dee2aaSAndroid Build Coastguard Worker 
172*c8dee2aaSAndroid Build Coastguard Worker     *deleteProc = delete_gl_texture;
173*c8dee2aaSAndroid Build Coastguard Worker     *updateProc = update_gl_texture;
174*c8dee2aaSAndroid Build Coastguard Worker     *imageCtx = new GLTextureHelper(texID, image, display, target);
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker     return GrBackendTextures::MakeGL(width, height, skgpu::Mipmapped::kNo, textureInfo);
177*c8dee2aaSAndroid Build Coastguard Worker }
178*c8dee2aaSAndroid Build Coastguard Worker 
can_import_protected_content_eglimpl()179*c8dee2aaSAndroid Build Coastguard Worker static bool can_import_protected_content_eglimpl() {
180*c8dee2aaSAndroid Build Coastguard Worker     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
181*c8dee2aaSAndroid Build Coastguard Worker     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
182*c8dee2aaSAndroid Build Coastguard Worker     size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
183*c8dee2aaSAndroid Build Coastguard Worker     size_t extsLen = strlen(exts);
184*c8dee2aaSAndroid Build Coastguard Worker     bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
185*c8dee2aaSAndroid Build Coastguard Worker     bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen+1);
186*c8dee2aaSAndroid Build Coastguard Worker     bool atEnd = (cropExtLen+1) < extsLen
187*c8dee2aaSAndroid Build Coastguard Worker                   && !strcmp(" " PROT_CONTENT_EXT_STR,
188*c8dee2aaSAndroid Build Coastguard Worker                   exts + extsLen - (cropExtLen+1));
189*c8dee2aaSAndroid Build Coastguard Worker     bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
190*c8dee2aaSAndroid Build Coastguard Worker     return equal || atStart || atEnd || inMiddle;
191*c8dee2aaSAndroid Build Coastguard Worker }
192*c8dee2aaSAndroid Build Coastguard Worker 
can_import_protected_content(GrDirectContext * dContext)193*c8dee2aaSAndroid Build Coastguard Worker static bool can_import_protected_content(GrDirectContext* dContext) {
194*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(GrBackendApi::kOpenGL == dContext->backend());
195*c8dee2aaSAndroid Build Coastguard Worker     // Only compute whether the extension is present once the first time this
196*c8dee2aaSAndroid Build Coastguard Worker     // function is called.
197*c8dee2aaSAndroid Build Coastguard Worker     static bool hasIt = can_import_protected_content_eglimpl();
198*c8dee2aaSAndroid Build Coastguard Worker     return hasIt;
199*c8dee2aaSAndroid Build Coastguard Worker }
200*c8dee2aaSAndroid Build Coastguard Worker 
MakeGLBackendTexture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & backendFormat,bool isRenderable)201*c8dee2aaSAndroid Build Coastguard Worker GrBackendTexture MakeGLBackendTexture(GrDirectContext* dContext,
202*c8dee2aaSAndroid Build Coastguard Worker                                       AHardwareBuffer* hardwareBuffer,
203*c8dee2aaSAndroid Build Coastguard Worker                                       int width, int height,
204*c8dee2aaSAndroid Build Coastguard Worker                                       DeleteImageProc* deleteProc,
205*c8dee2aaSAndroid Build Coastguard Worker                                       UpdateImageProc* updateProc,
206*c8dee2aaSAndroid Build Coastguard Worker                                       TexImageCtx* imageCtx,
207*c8dee2aaSAndroid Build Coastguard Worker                                       bool isProtectedContent,
208*c8dee2aaSAndroid Build Coastguard Worker                                       const GrBackendFormat& backendFormat,
209*c8dee2aaSAndroid Build Coastguard Worker                                       bool isRenderable) {
210*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(dContext);
211*c8dee2aaSAndroid Build Coastguard Worker     if (!dContext || dContext->abandoned()) {
212*c8dee2aaSAndroid Build Coastguard Worker         return GrBackendTexture();
213*c8dee2aaSAndroid Build Coastguard Worker     }
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker     if (GrBackendApi::kOpenGL != dContext->backend()) {
216*c8dee2aaSAndroid Build Coastguard Worker         return GrBackendTexture();
217*c8dee2aaSAndroid Build Coastguard Worker     }
218*c8dee2aaSAndroid Build Coastguard Worker 
219*c8dee2aaSAndroid Build Coastguard Worker     if (isProtectedContent && !can_import_protected_content(dContext)) {
220*c8dee2aaSAndroid Build Coastguard Worker         return GrBackendTexture();
221*c8dee2aaSAndroid Build Coastguard Worker     }
222*c8dee2aaSAndroid Build Coastguard Worker 
223*c8dee2aaSAndroid Build Coastguard Worker     return make_gl_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
224*c8dee2aaSAndroid Build Coastguard Worker                                    updateProc, imageCtx, isProtectedContent, backendFormat,
225*c8dee2aaSAndroid Build Coastguard Worker                                    isRenderable);
226*c8dee2aaSAndroid Build Coastguard Worker }
227*c8dee2aaSAndroid Build Coastguard Worker 
228*c8dee2aaSAndroid Build Coastguard Worker }  // namespace GrAHardwareBufferUtils
229*c8dee2aaSAndroid Build Coastguard Worker 
230*c8dee2aaSAndroid Build Coastguard Worker #endif
231