之前的介绍GraphicBuffer传送的内容中只是贴了几句代码,有小伙伴说要看看全部例子,因为代码写的比较乱,以前没有贴完整,现在还是贴出来吧,给需要的同学参考下,
这个程序是一个binder服务端程序,其中myBinder的case 5 是接收客户端发来的GraphicBuffer,再调用图片保存方法,图片保存的方法是仿照screencap源码的,
这里创建了一个名为screenget的binder服务,是一个最基本的binder服务,
注意,测试的时候需要关闭selinux,不然添加服务会出错
#define LOG_TAG "bindertest"
#include <stdio.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <iostream>
#include <iomanip>
#include <unistd.h>
//for ALOGD
#include <log/log.h>
//test socketpair
#include <sys/types.h>
#include <error.h>
#include <errno.h>
#include <sys/socket.h>
#include <pthread.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <binder/ProcessState.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/ISurfaceComposer.h>
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
// TODO: Fix Skia.
//#pragma GCC diagnostic push
//#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <SkImageEncoder.h>
#include <SkData.h>
#include <SkColorSpace.h>
//#pragma GCC diagnostic pop
using namespace android;
static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
using namespace std;
//
MemoryBase* mem;
int32_t* pdata = NULL;
int fd = -1;
int socket_pair[2];
void* newThread(void *ptr)
{
for (int i = 0; i < 1000; i++)
{
write(socket_pair[1], "12345", 5);
sleep(1);
cout << "new thread " << endl;
}
return NULL;
}
int icode = 0;
static SkColorType flinger2skia(PixelFormat f)
{
switch (f) {
case PIXEL_FORMAT_RGB_565:
return kRGB_565_SkColorType;
default:
return kN32_SkColorType;
}
}
static sk_sp<SkColorSpace> dataSpaceToColorSpace(android_dataspace d)
{
switch (d) {
case HAL_DATASPACE_V0_SRGB:
return SkColorSpace::MakeSRGB();
case HAL_DATASPACE_DISPLAY_P3:
return SkColorSpace::MakeRGB(
SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
default:
return nullptr;
}
}
int writePNG(char* fileName, char*base, int w, int h, int f, int s)
{
// if(h != 700) return 0;
int fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (fd == -1)
{
fprintf(stderr, "Error opening file: %s (%s)\n", fileName, strerror(errno));
return 1;
}
cout << "writePNG called" << endl;
/*
const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f),
kPremul_SkAlphaType);
SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(info, base, s*bytesPerPixel(f),
SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality));
if (data.get())
{
write(fd, data->data(), data->size());
}
*/
const SkImageInfo info =
SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType,
dataSpaceToColorSpace(HAL_DATASPACE_UNKNOWN));
cout << "3" << endl;
SkPixmap pixmap(info, base, s * bytesPerPixel(f));
cout << "4" << endl;
struct FDWStream final : public SkWStream {
size_t fBytesWritten = 0;
int fFd;
FDWStream(int f) : fFd(f) {cout << "4.1" << endl;}
size_t bytesWritten() const override {cout << "4.2" << endl; return fBytesWritten; }
bool write(const void* buffer, size_t size) override {
fBytesWritten += size;
cout << "4.3" << endl;
// cout << "fBytesWritten=" << fBytesWritten << ", size=" << size << endl;
return size == 0 || ::write(fFd, buffer, size) > 0;
}
} fdStream(fd);
cout << "5" << endl;
/*
enum class SkEncodedImageFormat {
#ifdef GOOGLE3
kUnknown,
#endif
kBMP,
kGIF,
kICO,
kJPEG,
kPNG,
kWBMP,
kWEBP,
kPKM,
kKTX,
kASTC,
kDNG,
kHEIF,
};
*/
//so we can save the data as BMP
(void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100);
cout << "6" << endl;
close(fd);
return 0;
}
class myBinder : public BBinder
{
public:
status_t dump(int fd2, const Vector<String16>& args)
{
write(fd2, "myBinder dump called ", 22);
return NO_ERROR;
}
status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code)
{
case 1: {
printf("onTransact called, case 1\n");
int in_data = data.readInt32();
reply->writeInt32(in_data * 2);
return NO_ERROR;
}
case 2:{
printf("onTransact called, case 2\n");
reply->writeFileDescriptor(socket_pair[0]);
// close(socket_pair[0]);
return NO_ERROR;
}
case 3:{
printf("onTransact called, case 3\n");
reply->writeFileDescriptor(fd);
return NO_ERROR;
}
case 4:{
printf("onTransact called, case 4\n");
int fd = data.readFileDescriptor();
int w = data.readInt32();
int h = data.readInt32();
int format = data.readInt32();
if (h != 700) return -1;
android_dataspace d = HAL_DATASPACE_UNKNOWN;
//here we just use width as stride
int s = w;
printf("fd=%d, w=%d, h=%d, format=%d \n", fd, w, h, format);
printf("1\n");
void* mappedAddress= mmap(0, w*h*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
// void* mappedAddress= mmap(0, w*h*4, PROT_READ, MAP_SHARED, fd, 0);
//test read fd
//char* mappedAddress = new char[w*h*4];
//if (read(fd, mappedAddress, w*h*4) == -1)
// {printf("Could not read, %s \n\n", strerror(errno));}
if (mappedAddress == MAP_FAILED) {
printf("Could not mmap %s \n\n", strerror(errno));
//return -errno;
}
char* base = (char*)mappedAddress;
if (base != NULL)
{
cout << "====== base not null" << endl;
cout << "====== base[2]=" << base[2] << endl;
printf("==base[0]=%d, base[1]=%d, base[2]=%d, base[3]=%d, base[4]=%d\n\n",
base[0], base[1], base[2], base[3], base[4]);
}
char* base2 = new char[w*h*4];
//memcpy(base2, base, w*h*4);
char*p = base;
int j=0;
for (int i = 0; i < h; i++)
{
for (j = 0; j < w*4; j++)
{
base2[i*w*4 + j] = *p;//
p++;
}
printf("i=%d, j=%d\n", i, j);
}
printf("2\n");
char pname[32] = {0};
sprintf(pname, "%02d.png", icode++);
writePNG(pname, base2, w, h, format, s);
return NO_ERROR;
}
case 5:{
printf("onTransact called, case 3\n");
int w = data.readInt32();
int h = data.readInt32();
int format = data.readInt32();
int s = w;
sp<GraphicBuffer> buf = new GraphicBuffer();;
data.read(*buf);
Region newDirtyRegion;
const Rect bounds(w, h);
newDirtyRegion.set(bounds);
int fenceFd = -1;
void* vaddr;
//GRALLOC_USAGE_SW_READ_OFTEN 0x00000003U
//GRALLOC_USAGE_SW_WRITE_OFTEN 0x00000030U
status_t res = buf->lockAsync(0x00000003U | 0x00000030U,
newDirtyRegion.bounds(), &vaddr, fenceFd);
printf("==== vaddr=%p\n", vaddr);
char pname[32] = {0};
sprintf(pname, "%02d.png", icode++);
char* base = (char*)vaddr;
writePNG(pname, base, w, h, format, s);
return NO_ERROR;
}
}
return BBinder::onTransact(code, data, reply, flags);
}
};
int main(int argc, char** argv)
{
sp < ProcessState > proc(ProcessState::self());
sp < IServiceManager > sm = defaultServiceManager();
sm->addService(String16("screenget"), new myBinder());
printf("add myService\n");
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
Android.mk
LOCAL_PATH := $(call my-dir)
#for service
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
service.cpp
LOCAL_SHARED_LIBRARIES := \
libbase \
libutils \
liblog \
libbinder \
libskia \
libui \
libgui
ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
#LOCAL_SHARED_LIBRARIES += librt
endif
LOCAL_MODULE:= screenget
include $(BUILD_EXECUTABLE)