Create pre-process gralloc pipe on the guest

https://buganizer.corp.google.com/issues/29457657

This patch create a pre-process pipe in gralloc. It tells the host which
process holds which color buffer, so that on process exit the host can
correctly reduce the reference counters of all gralloc color buffers.

Each process will get a 64bit identifier from the host, to help the host
identifying it.

It works with host patch:
https://android-review.googlesource.com/#/c/246823/

Change-Id: I8d9a512a1f151f4f29a3b318ccf17d62d8f46512
diff --git a/system/GLESv1_enc/gl_client_context.h b/system/GLESv1_enc/gl_client_context.h
index 8074095..6d46a9b 100644
--- a/system/GLESv1_enc/gl_client_context.h
+++ b/system/GLESv1_enc/gl_client_context.h
@@ -301,7 +301,7 @@
 	glExtGetProgramBinarySourceQCOM_client_proc_t glExtGetProgramBinarySourceQCOM;
 	glStartTilingQCOM_client_proc_t glStartTilingQCOM;
 	glEndTilingQCOM_client_proc_t glEndTilingQCOM;
-	 virtual ~gl_client_context_t() {}
+	virtual ~gl_client_context_t() {}
 
 	typedef gl_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
 	static void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);
diff --git a/system/GLESv2_enc/gl2_client_context.h b/system/GLESv2_enc/gl2_client_context.h
index 7035fec..5d8b653 100644
--- a/system/GLESv2_enc/gl2_client_context.h
+++ b/system/GLESv2_enc/gl2_client_context.h
@@ -218,7 +218,7 @@
 	glGetCompressedTextureFormats_client_proc_t glGetCompressedTextureFormats;
 	glShaderString_client_proc_t glShaderString;
 	glFinishRoundTrip_client_proc_t glFinishRoundTrip;
-	 virtual ~gl2_client_context_t() {}
+	virtual ~gl2_client_context_t() {}
 
 	typedef gl2_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
 	static void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);
diff --git a/system/gralloc/gralloc.cpp b/system/gralloc/gralloc.cpp
index 28d6dc8..ee6d84e 100644
--- a/system/gralloc/gralloc.cpp
+++ b/system/gralloc/gralloc.cpp
@@ -43,6 +43,15 @@
 #endif
 
 #define DBG_FUNC DBG("%s\n", __FUNCTION__)
+
+#include <hardware/qemu_pipe.h>
+
+// Associate PID with color buffers
+// See the comments in gralloc_proc_init() for more details
+#define PID_CMD(func, ...) \
+    (sGrallocProcPipe ? rcEnc->func##Pid(rcEnc, __VA_ARGS__, sGrallocProcID) \
+                     : rcEnc->func(rcEnc, __VA_ARGS__))
+
 //
 // our private gralloc module structure
 //
@@ -60,6 +69,13 @@
 static void fallback_init(void);  // forward
 
 
+static int                sGrallocProcPipe = 0;
+static pthread_once_t     sGrallocProcPipeOnce = PTHREAD_ONCE_INIT;
+// sGrallocProcID is a unique ID pre process assigned by the host.
+// It is different from getpid().
+static uint64_t           sGrallocProcID = 0;
+static void gralloc_proc_init();
+
 typedef struct _alloc_list_node {
     buffer_handle_t handle;
     _alloc_list_node *next;
@@ -355,7 +371,8 @@
 #endif // PLATFORM_SDK_VERSION >= 16
         DEFINE_HOST_CONNECTION;
         if (hostCon && rcEnc) {
-            cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, glFormat);
+            pthread_once(&sGrallocProcPipeOnce, gralloc_proc_init);
+            cb->hostHandle = PID_CMD(rcCreateColorBuffer, w, h, glFormat);
             D("Created host ColorBuffer 0x%x\n", cb->hostHandle);
         }
 
@@ -407,7 +424,8 @@
     if (cb->hostHandle != 0) {
         DEFINE_AND_VALIDATE_HOST_CONNECTION;
         D("Closing host ColorBuffer 0x%x\n", cb->hostHandle);
-        rcEnc->rcCloseColorBuffer(rcEnc, cb->hostHandle);
+        pthread_once(&sGrallocProcPipeOnce, gralloc_proc_init);
+        PID_CMD(rcCloseColorBuffer, cb->hostHandle);
     }
 
     //
@@ -564,6 +582,7 @@
     if (sFallback != NULL) {
         return sFallback->registerBuffer(sFallback, handle);
     }
+    pthread_once(&sGrallocProcPipeOnce, gralloc_proc_init);
 
     D("gralloc_register_buffer(%p) called", handle);
 
@@ -577,7 +596,7 @@
     if (cb->hostHandle != 0) {
         DEFINE_AND_VALIDATE_HOST_CONNECTION;
         D("Opening host ColorBuffer 0x%x\n", cb->hostHandle);
-        rcEnc->rcOpenColorBuffer2(rcEnc, cb->hostHandle);
+        PID_CMD(rcOpenColorBuffer2, cb->hostHandle);
     }
 
     //
@@ -614,7 +633,8 @@
     if (cb->hostHandle != 0) {
         DEFINE_AND_VALIDATE_HOST_CONNECTION;
         D("Closing host ColorBuffer 0x%x\n", cb->hostHandle);
-        rcEnc->rcCloseColorBuffer(rcEnc, cb->hostHandle);
+        pthread_once(&sGrallocProcPipeOnce, gralloc_proc_init);
+        PID_CMD(rcCloseColorBuffer, cb->hostHandle);
     }
 
     //
@@ -1122,3 +1142,41 @@
         ALOGE("Could not find software fallback module!?");
     }
 }
+
+// The host associates color buffers with PID for memory cleanup.
+// It will fallback to the default path if host does not support it.
+// We discussed PID reuse issue when designing this component, but we considered
+// it not to be an issue because as new processes fork in, PIDs will increase to
+// a system-dependent limit and then wrap around.
+static void gralloc_proc_init() {
+    sGrallocProcPipe = qemu_pipe_open("grallocPipe");
+    if (sGrallocProcPipe < 0) {
+        sGrallocProcPipe = 0;
+        ALOGW("Gralloc pipe failed");
+        return;
+    }
+    int32_t pid = static_cast<int32_t>(getpid());
+    ssize_t stat = 0;
+    do {
+        stat = ::write(sGrallocProcPipe, (const char*)&pid, sizeof(pid));
+    } while (stat < 0 && errno == EINTR);
+
+    if (stat != 4) { // failed
+        close(sGrallocProcPipe);
+        sGrallocProcPipe = 0;
+        ALOGW("Gralloc pipe failed");
+        return;
+    }
+
+    do {
+        stat = ::read(sGrallocProcPipe, (char*)&sGrallocProcID,
+                      sizeof(sGrallocProcID));
+    } while (stat < 0 && errno == EINTR);
+
+    if (stat != 8) {
+        close(sGrallocProcPipe);
+        sGrallocProcPipe = 0;
+        ALOGW("Gralloc pipe failed");
+        return;
+    }
+}
diff --git a/system/renderControl_enc/renderControl_client_context.cpp b/system/renderControl_enc/renderControl_client_context.cpp
index 51b62a6..acaa4cf 100644
--- a/system/renderControl_enc/renderControl_client_context.cpp
+++ b/system/renderControl_enc/renderControl_client_context.cpp
@@ -39,6 +39,9 @@
 	rcCreateClientImage = (rcCreateClientImage_client_proc_t) getProc("rcCreateClientImage", userData);
 	rcDestroyClientImage = (rcDestroyClientImage_client_proc_t) getProc("rcDestroyClientImage", userData);
 	rcSelectChecksumHelper = (rcSelectChecksumHelper_client_proc_t) getProc("rcSelectChecksumHelper", userData);
+	rcCreateColorBufferPid = (rcCreateColorBufferPid_client_proc_t) getProc("rcCreateColorBufferPid", userData);
+	rcOpenColorBuffer2Pid = (rcOpenColorBuffer2Pid_client_proc_t) getProc("rcOpenColorBuffer2Pid", userData);
+	rcCloseColorBufferPid = (rcCloseColorBufferPid_client_proc_t) getProc("rcCloseColorBufferPid", userData);
 	return 0;
 }
 
diff --git a/system/renderControl_enc/renderControl_client_context.h b/system/renderControl_enc/renderControl_client_context.h
index f5230f1..99be683 100644
--- a/system/renderControl_enc/renderControl_client_context.h
+++ b/system/renderControl_enc/renderControl_client_context.h
@@ -39,7 +39,10 @@
 	rcCreateClientImage_client_proc_t rcCreateClientImage;
 	rcDestroyClientImage_client_proc_t rcDestroyClientImage;
 	rcSelectChecksumHelper_client_proc_t rcSelectChecksumHelper;
-	 virtual ~renderControl_client_context_t() {}
+	rcCreateColorBufferPid_client_proc_t rcCreateColorBufferPid;
+	rcOpenColorBuffer2Pid_client_proc_t rcOpenColorBuffer2Pid;
+	rcCloseColorBufferPid_client_proc_t rcCloseColorBufferPid;
+	virtual ~renderControl_client_context_t() {}
 
 	typedef renderControl_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
 	static void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);
diff --git a/system/renderControl_enc/renderControl_client_proc.h b/system/renderControl_enc/renderControl_client_proc.h
index 7b213d5..61bb307 100644
--- a/system/renderControl_enc/renderControl_client_proc.h
+++ b/system/renderControl_enc/renderControl_client_proc.h
@@ -38,6 +38,9 @@
 typedef uint32_t (renderControl_APIENTRY *rcCreateClientImage_client_proc_t) (void * ctx, uint32_t, EGLenum, GLuint);
 typedef int (renderControl_APIENTRY *rcDestroyClientImage_client_proc_t) (void * ctx, uint32_t);
 typedef void (renderControl_APIENTRY *rcSelectChecksumHelper_client_proc_t) (void * ctx, uint32_t, uint32_t);
+typedef uint32_t (renderControl_APIENTRY *rcCreateColorBufferPid_client_proc_t) (void * ctx, uint32_t, uint32_t, GLenum, uint64_t);
+typedef int (renderControl_APIENTRY *rcOpenColorBuffer2Pid_client_proc_t) (void * ctx, uint32_t, uint64_t);
+typedef void (renderControl_APIENTRY *rcCloseColorBufferPid_client_proc_t) (void * ctx, uint32_t, uint64_t);
 
 
 #endif
diff --git a/system/renderControl_enc/renderControl_enc.cpp b/system/renderControl_enc/renderControl_enc.cpp
index 69dc031..9de8763 100644
--- a/system/renderControl_enc/renderControl_enc.cpp
+++ b/system/renderControl_enc/renderControl_enc.cpp
@@ -1094,6 +1094,116 @@
 
 }
 
+uint32_t rcCreateColorBufferPid_enc(void *self , uint32_t width, uint32_t height, GLenum internalFormat, uint64_t pid)
+{
+
+	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 8;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_rcCreateColorBufferPid;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &width, 4); ptr += 4;
+		memcpy(ptr, &height, 4); ptr += 4;
+		memcpy(ptr, &internalFormat, 4); ptr += 4;
+		memcpy(ptr, &pid, 8); ptr += 8;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+
+	uint32_t retval;
+	stream->readback(&retval, 4);
+	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
+	if (useChecksum) {
+		unsigned char *checksumBufPtr = NULL;
+		std::vector<unsigned char> checksumBuf(checksumSize);
+		if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+		stream->readback(checksumBufPtr, checksumSize);
+		if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+			ALOGE("rcCreateColorBufferPid: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+	return retval;
+}
+
+int rcOpenColorBuffer2Pid_enc(void *self , uint32_t colorbuffer, uint64_t pid)
+{
+
+	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 8;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_rcOpenColorBuffer2Pid;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &colorbuffer, 4); ptr += 4;
+		memcpy(ptr, &pid, 8); ptr += 8;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+
+	int retval;
+	stream->readback(&retval, 4);
+	if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
+	if (useChecksum) {
+		unsigned char *checksumBufPtr = NULL;
+		std::vector<unsigned char> checksumBuf(checksumSize);
+		if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+		stream->readback(checksumBufPtr, checksumSize);
+		if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+			ALOGE("rcOpenColorBuffer2Pid: GL communication error, please report this issue to b.android.com.\n");
+			abort();
+		}
+	}
+	return retval;
+}
+
+void rcCloseColorBufferPid_enc(void *self , uint32_t colorbuffer, uint64_t pid)
+{
+
+	renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+	IOStream *stream = ctx->m_stream;
+	ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+	bool useChecksum = checksumCalculator->getVersion() > 0;
+
+	 unsigned char *ptr;
+	 unsigned char *buf;
+	 const size_t sizeWithoutChecksum = 8 + 4 + 8;
+	 const size_t checksumSize = checksumCalculator->checksumByteSize();
+	 const size_t totalSize = sizeWithoutChecksum + checksumSize;
+	buf = stream->alloc(totalSize);
+	ptr = buf;
+	int tmp = OP_rcCloseColorBufferPid;memcpy(ptr, &tmp, 4); ptr += 4;
+	memcpy(ptr, &totalSize, 4);  ptr += 4;
+
+		memcpy(ptr, &colorbuffer, 4); ptr += 4;
+		memcpy(ptr, &pid, 8); ptr += 8;
+
+	if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+	if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+}
+
 }  // namespace
 
 renderControl_encoder_context_t::renderControl_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
@@ -1130,5 +1240,8 @@
 	this->rcCreateClientImage = &rcCreateClientImage_enc;
 	this->rcDestroyClientImage = &rcDestroyClientImage_enc;
 	this->rcSelectChecksumHelper = &rcSelectChecksumHelper_enc;
+	this->rcCreateColorBufferPid = &rcCreateColorBufferPid_enc;
+	this->rcOpenColorBuffer2Pid = &rcOpenColorBuffer2Pid_enc;
+	this->rcCloseColorBufferPid = &rcCloseColorBufferPid_enc;
 }
 
diff --git a/system/renderControl_enc/renderControl_entry.cpp b/system/renderControl_enc/renderControl_entry.cpp
index 6a51108..122f0bb 100644
--- a/system/renderControl_enc/renderControl_entry.cpp
+++ b/system/renderControl_enc/renderControl_entry.cpp
@@ -35,6 +35,9 @@
 	uint32_t rcCreateClientImage(uint32_t context, EGLenum target, GLuint buffer);
 	int rcDestroyClientImage(uint32_t image);
 	void rcSelectChecksumHelper(uint32_t newProtocol, uint32_t reserved);
+	uint32_t rcCreateColorBufferPid(uint32_t width, uint32_t height, GLenum internalFormat, uint64_t pid);
+	int rcOpenColorBuffer2Pid(uint32_t colorbuffer, uint64_t pid);
+	void rcCloseColorBufferPid(uint32_t colorbuffer, uint64_t pid);
 };
 
 #endif
@@ -218,3 +221,21 @@
 	ctx->rcSelectChecksumHelper(ctx, newProtocol, reserved);
 }
 
+uint32_t rcCreateColorBufferPid(uint32_t width, uint32_t height, GLenum internalFormat, uint64_t pid)
+{
+	GET_CONTEXT;
+	return ctx->rcCreateColorBufferPid(ctx, width, height, internalFormat, pid);
+}
+
+int rcOpenColorBuffer2Pid(uint32_t colorbuffer, uint64_t pid)
+{
+	GET_CONTEXT;
+	return ctx->rcOpenColorBuffer2Pid(ctx, colorbuffer, pid);
+}
+
+void rcCloseColorBufferPid(uint32_t colorbuffer, uint64_t pid)
+{
+	GET_CONTEXT;
+	ctx->rcCloseColorBufferPid(ctx, colorbuffer, pid);
+}
+
diff --git a/system/renderControl_enc/renderControl_ftable.h b/system/renderControl_enc/renderControl_ftable.h
index ac772e6..8690352 100644
--- a/system/renderControl_enc/renderControl_ftable.h
+++ b/system/renderControl_enc/renderControl_ftable.h
@@ -37,6 +37,9 @@
 	{"rcCreateClientImage", (void*)rcCreateClientImage},
 	{"rcDestroyClientImage", (void*)rcDestroyClientImage},
 	{"rcSelectChecksumHelper", (void*)rcSelectChecksumHelper},
+	{"rcCreateColorBufferPid", (void*)rcCreateColorBufferPid},
+	{"rcOpenColorBuffer2Pid", (void*)rcOpenColorBuffer2Pid},
+	{"rcCloseColorBufferPid", (void*)rcCloseColorBufferPid},
 };
 static const int renderControl_num_funcs = sizeof(renderControl_funcs_by_name) / sizeof(struct _renderControl_funcs_by_name);
 
diff --git a/system/renderControl_enc/renderControl_opcodes.h b/system/renderControl_enc/renderControl_opcodes.h
index 4861c9c..fc9edef 100644
--- a/system/renderControl_enc/renderControl_opcodes.h
+++ b/system/renderControl_enc/renderControl_opcodes.h
@@ -32,7 +32,10 @@
 #define OP_rcCreateClientImage 					10026
 #define OP_rcDestroyClientImage 					10027
 #define OP_rcSelectChecksumHelper 					10028
-#define OP_last 					10029
+#define OP_rcCreateColorBufferPid 					10029
+#define OP_rcOpenColorBuffer2Pid 					10030
+#define OP_rcCloseColorBufferPid 					10031
+#define OP_last 					10032
 
 
 #endif