以Android Pie为例
1.surfaceflinger 是一个独立的CPP应用程序,手机中存放在/system/bin/surfaceflinger
可以看一下surfaceflinger调用的库:
<----------------------------------------------------------------------------
$adb shell
$adb su
#ps -A | grep surfaceflinger
system 1234 1 220351 19868 SyS_epool_wait 0 S surfaceflinger
假设Surfaceflinger的进程号是1234
#pmap 1234
---------------------------------------------------------------------------------->
SurfaceComposerClient 是一个CPP类,
定义在:
androidSourceDir/frameworks/native/libs/gui/include/gui/SurfaceComposerClient.h
成员函数实现在:
androidSourceDir/framework/native/libs/gui/SurfaceComposerClient.cpp
我们先到androidSourceDir/framework$ grep -rn SurfaceComposerClient (核心技术机密外泄^^)
Android中有很多可以入手的点:选screencap吧,最简示例。
先从androidSourceDir/frameworks/base/cmds/screencap/screencap.cpp这个应用程序开始说去,这样会让我们比较感性的接触Android。
攻关目标:将且仅将screencap.cpp的每行代码了然于胸,不留死角。总共261行。其实没必要,还是一招鲜,数据流法:谁的数据?数据从哪里来?数据到哪里去?
阅码方法:静态运行,逐句法。No,数据,数据,数据。
只解读如下用法 $screencap -p helloscreen.png
数据是即将推送到显示器上去的一帧图像;who?
揪出这个数据从哪里来,会给我们带来很多知识。
从main()第一行开始:
int main(int argc, char** argv)
{
const char* pname = argv[0];
bool png = false;
int32_t displayId = DEFAULT_DISPLAY_ID;
int c;
while ((c = getopt(argc, argv, "phd:")) != -1) {
switch (c) {
case 'p':
png = true;//LL:存储为png的标识变量。
break;
...
}
}
argc -= optind;
argv += optind;
int fd = -1;
const char* fn = NULL;
...
fn = argv[0];
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);//LL:准备存储图片到手机
...
}
....
void const* mapbase = MAP_FAILED;
ssize_t mapsize = -1;
void* base = NULL;
uint32_t w, s, h, f;
android_dataspace d;
size_t size = 0;
// Maps orientations from DisplayInfo to ISurfaceComposer
static const uint32_t ORIENTATION_MAP[] = {
ISurfaceComposer::eRotateNone, // 0 == DISPLAY_ORIENTATION_0
ISurfaceComposer::eRotate270, // 1 == DISPLAY_ORIENTATION_90
ISurfaceComposer::eRotate180, // 2 == DISPLAY_ORIENTATION_180
ISurfaceComposer::eRotate90, // 3 == DISPLAY_ORIENTATION_270
};
// setThreadPoolMaxThreadCount(0) actually tells the kernel it's
// not allowed to spawn any additional threads, but we still spawn
// a binder thread from userspace when we call startThreadPool().
// See b/36066697 for rationale
ProcessState::self()->setThreadPoolMaxThreadCount(0);
ProcessState::self()->startThreadPool();
sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
....
Vector<DisplayInfo> configs;
SurfaceComposerClient::getDisplayConfigs(display, &configs);
int activeConfig = SurfaceComposerClient::getActiveConfig(display);
...
uint8_t displayOrientation = configs[activeConfig].orientation;
uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation];
sp<GraphicBuffer> outBuffer;
status_t result = ScreenshotClient::capture(display, Rect(), 0 /* reqWidth */,
0 /* reqHeight */, INT32_MIN, INT32_MAX, /* all layers */ false, captureOrientation,
&outBuffer);
if (result != NO_ERROR) {
close(fd);
_exit(1);
}
result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
if (base == NULL) {
close(fd);
_exit(1);
}
w = outBuffer->getWidth();
h = outBuffer->getHeight();
s = outBuffer->getStride();
f = outBuffer->getPixelFormat();
d = HAL_DATASPACE_UNKNOWN;
size = s * h * bytesPerPixel(f);
if (png) {
const SkImageInfo info =
SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType, dataSpaceToColorSpace(d));
SkPixmap pixmap(info, base, s * bytesPerPixel(f));
struct FDWStream final : public SkWStream {
size_t fBytesWritten = 0;
int fFd;
FDWStream(int f) : fFd(f) {}
size_t bytesWritten() const override { return fBytesWritten; }
bool write(const void* buffer, size_t size) override {
fBytesWritten += size;
return size == 0 || ::write(fFd, buffer, size) > 0;
}
} fdStream(fd);
(void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100);
if (fn != NULL) {
notifyMediaScanner(fn);
}
} else {
uint32_t c = dataSpaceToInt(d);
write(fd, &w, 4);
write(fd, &h, 4);
write(fd, &f, 4);
write(fd, &c, 4);
size_t Bpp = bytesPerPixel(f);
for (size_t y=0 ; y<h ; y++) {
write(fd, base, w*Bpp);
base = (void *)((char *)base + s*Bpp);
}
}
close(fd);
if (mapbase != MAP_FAILED) {
munmap((void *)mapbase, mapsize);
}
// b/36066697: Avoid running static destructors.
_exit(0);
}