從SurfaceFlinger中獲取各layer圖片的試驗可以加深對GraphicBuffer和Layer的理解。
dumpsys SurfaceFlinger中打印的Slot信息中有GraphicBuffer的指針,可以幫助我們瞭解QueueBufferCore.
這個試驗最初的出發點是根據圖像的存儲內存,再獲取到這個數據,通過保存爲圖片的直觀形式展現出來。
其實系統截圖命令screencap也是類似的原理和實現(當然,我這裏的保存圖片就是從screencap裏copy出來的方法)
frameworks/base/cmds/screencap/screencap.cpp
裏面從surfaceflinger裏面獲取到了合成完成的GraphicBuffer,即屏幕截圖畫面
201 sp<GraphicBuffer> outBuffer; 202 status_t result = ScreenshotClient::capture(display, Rect(), 0 /* reqWidth */, 203 0 /* reqHeight */, INT32_MIN, INT32_MAX, /* all layers */ false, captureOrientation, 204 &outBuffer); 205 if (result != NO_ERROR) { 206 close(fd); 207 _exit(1); 208 }
再通過lock方法獲取到存儲地址base
result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
我們的試驗中,顯示出了GraphicBuffer的binder傳送過程,
通過lockAsync方法獲取到地址base
status_t res = buf->lockAsync(0x00000003U | 0x00000030U,
newDirtyRegion.bounds(), &vaddr, fenceFd);
有了地址base,就可以使用screencap裏面的方法來保存爲圖片了
217 w = outBuffer->getWidth(); 218 h = outBuffer->getHeight(); 219 s = outBuffer->getStride(); 220 f = outBuffer->getPixelFormat(); 221 d = HAL_DATASPACE_UNKNOWN; 222 size = s * h * bytesPerPixel(f); 223 224 if (png) { 225 const SkImageInfo info = 226 SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType, dataSpaceToColorSpace(d)); 227 SkPixmap pixmap(info, base, s * bytesPerPixel(f)); 228 struct FDWStream final : public SkWStream { 229 size_t fBytesWritten = 0; 230 int fFd; 231 FDWStream(int f) : fFd(f) {} 232 size_t bytesWritten() const override { return fBytesWritten; } 233 bool write(const void* buffer, size_t size) override { 234 fBytesWritten += size; 235 return size == 0 || ::write(fFd, buffer, size) > 0; 236 } 237 } fdStream(fd); 238 (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100); 239 if (fn != NULL) { 240 notifyMediaScanner(fn); 241 } 242 } else { 243 uint32_t c = dataSpaceToInt(d); 244 write(fd, &w, 4); 245 write(fd, &h, 4); 246 write(fd, &f, 4); 247 write(fd, &c, 4); 248 size_t Bpp = bytesPerPixel(f); 249 for (size_t y=0 ; y<h ; y++) { 250 write(fd, base, w*Bpp); 251 base = (void *)((char *)base + s*Bpp); 252 } 253 } 254 close(fd);