启动的位置是在/frameworks/native/cmds/dumpsys/main.cpp:
int main(int argc, char* const argv[]) {
signal(SIGPIPE, SIG_IGN);
sp sm = defaultServiceManager(); //1
fflush(stdout);
if (sm == nullptr) {
ALOGE("Unable to get default service manager!");
aerr << "dumpsys: Unable to get default service manager!" << endl;
return 20;
}
Dumpsys dumpsys(sm.get());//2
return dumpsys.main(argc, argv);//3
}
注释1:通过Binder获取ServiceManager对象,这块知识点可以参考大神的博客Binder系列4—获取ServiceManager,Binder系列6—获取服务(getService)。
注释2:创建Dumpsys对象,sm.get()是获取IServiceManager数组第一个元素的地址,传给Dumpsys对象
注释3:调用Dumpsys的main方法:
int Dumpsys::main(int argc, char* const argv[]) {
...
for (size_t i = 0; i < N; i++) {
String16 service_name = std::move(services[i]);
if (IsSkipped(skippedServices, service_name)) continue;
sp service = sm_->checkService(service_name);//1
...
// dump blocks until completion, so spawn a thread..
std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
int err = service->dump(remote_end.get(), args);//2
// It'd be nice to be able to close the remote end of the socketpair before the dump
// call returns, to terminate our reads if the other end closes their copy of the
// file descriptor, but then hangs for some reason. There doesn't seem to be a good
// way to do this, though.
remote_end.reset();
if (err != 0) {
aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
<< endl;
}
});
...
}
}
注释1:sm->checkService(),获取系统中指定的Service;
注释2:service->dump(),dumpsys命令的核心还是调用远程服务中的dump()方法来获取相应的dump信息。
因此需要查找gfxinfo对应的Service和dump方法:
/frameworks/base/services/java/com/android/server/SystemServer.java:
private void startBootstrapServices() {
...
// Set up the Application instance for the system process and get started.
traceBeginAndSlog("SetSystemProcess");
mActivityManagerService.setSystemProcess();//1
traceEnd();
...
}
注释1:设置系统进程:
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java:
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this));
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));//1
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(this));
}
ServiceManager.addService("permission", new PermissionController(this));
ServiceManager.addService("processinfo", new ProcessInfoService(this));
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
synchronized (this) {
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
app.persistent = true;
app.pid = MY_PID;
app.maxAdj = ProcessList.SYSTEM_ADJ;
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.put(app.pid, app);
}
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
"Unable to find android system package", e);
}
}
注释1:可以看到里面就有我们熟悉的dumpsys命令的第一个可选项的字段,已经对应的Service类,其中gfxinfo对应GraphicsBinder类,GraphicsBinder是ActivityManagerService的内部类。
继续接着上面的native代码,执行GraphicsBinder的dump方法: /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService#GraphicsBinder.java:
static class GraphicsBinder extends Binder {
ActivityManagerService mActivityManagerService;
GraphicsBinder(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"gfxinfo", pw)) return;
mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);//1
}
}
注释1:调用ActivityManagerService的dumpGraphicsHardwareUsag方法:
final void dumpGraphicsHardwareUsage(FileDescriptor fd,
PrintWriter pw, String[] args) {
ArrayList procs = collectProcesses(pw, 0, false, args);
if (procs == null) {
pw.println("No process found for: " + args[0]);
return;
}
long uptime = SystemClock.uptimeMillis();
long realtime = SystemClock.elapsedRealtime();
pw.println("Applications Graphics Acceleration Info:");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
pw.println("\n** Graphics info for pid " + r.pid + " [" + r.processName + "] **");
pw.flush();
try {
TransferPipe tp = new TransferPipe();
try {
r.thread.dumpGfxInfo(tp.getWriteFd(), args);//1
tp.go(fd);
} finally {
tp.kill();
}
} catch (IOException e) {
pw.println("Failure while dumping the app: " + r);
pw.flush();
} catch (RemoteException e) {
pw.println("Got a RemoteException while dumping the app " + r);
pw.flush();
}
}
}
}
注释1:其中r.thread是IApplicationThread类,对应ActivityThread的内部类ApplicationThread类,其中有各种dump信息对应的方法:
/frameworks/base/core/java/android/app/ActivityThread#ApplicationThread.java:
private class ApplicationThread extends IApplicationThread.Stub {
...
@Override
public void dumpGfxInfo(ParcelFileDescriptor pfd, String[] args) {
nDumpGraphicsInfo(pfd.getFileDescriptor());//1
WindowManagerGlobal.getInstance().dumpGfxInfo(pfd.getFileDescriptor(), args);//2
IoUtils.closeQuietly(pfd);
}
...
}
注释2:这里我们看到非常熟悉的WindowManagerGlobal,跟Window息息相关,dumpGfxInfo方法里,会遍历所有的ViewRootImpl,然后层层遍历每个ViewRootImpl的子View,获取RenderNode相关信息,并打印。
注释1:这里nDumpGraphicsInfo是一个native方法,跳到native层:
/frameworks/base/core/jni/android_view_DisplayListCanvas.cpp:
这里采用动态注册:
static JNINativeMethod gActivityThreadMethods[] = {
// ------------ Regular JNI ------------------
{ "nDumpGraphicsInfo", "(Ljava/io/FileDescriptor;)V",
(void*) android_app_ActivityThread_dumpGraphics }
};
static void
android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);//1
}
注释1:调用RenderProxy的静态方法dumpGraphicsMemory:
/frameworks/base/libs/hwui/renderthread/RenderProxy.cpp:
void RenderProxy::dumpGraphicsMemory(int fd) {
if (!RenderThread::hasInstance()) return;
SETUP_TASK(dumpGraphicsMemory);//1
args->fd = fd;
args->thread = &RenderThread::getInstance();
staticPostAndWait(task);
}
注释1:这里使用了函数指针,创建一个任务,执行dumpGraphicsMemory方法:
CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) {
args->thread->jankTracker().dump(args->fd);//1
FILE *file = fdopen(args->fd, "a");
if (Caches::hasInstance()) {
String8 cachesLog;
Caches::getInstance().dumpMemoryUsage(cachesLog);//2
fprintf(file, "\nCaches:\n%s\n", cachesLog.string());
} else {
fprintf(file, "\nNo caches instance.\n");
}
fprintf(file, "\nPipeline=FrameBuilder\n");
fflush(file);
return nullptr;
}
注释1:dump,这里将打印出dump命令最开始的那一串信息:
void JankTracker::dumpData(int fd, const ProfileDataDescription* description, const ProfileData* data) {
if (description) {
switch (description->type) {
case JankTrackerType::Generic:
break;
case JankTrackerType::Package:
dprintf(fd, "\nPackage: %s", description->name.c_str());
break;
case JankTrackerType::Window:
dprintf(fd, "\nWindow: %s", description->name.c_str());
break;
}
}
if (sFrameStart != FrameInfoIndex::IntendedVsync) {
dprintf(fd, "\nNote: Data has been filtered!");
}
dprintf(fd, "\nStats since: %" PRIu64 "ns", data->statStartTime);
dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
(float) data->jankFrameCount / (float) data->totalFrameCount * 100.0f);
dprintf(fd, "\n50th percentile: %ums", findPercentile(data, 50));
dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
for (int i = 0; i < NUM_BUCKETS; i++) {
dprintf(fd, "\nNumber %s: %u", JANK_TYPE_NAMES[i], data->jankTypeCounts[i]);
}
dprintf(fd, "\nHISTOGRAM:");
for (size_t i = 0; i < data->frameCounts.size(); i++) {
dprintf(fd, " %ums=%u", frameTimeForFrameCountIndex(i),
data->frameCounts[i]);
}
for (size_t i = 0; i < data->slowFrameCounts.size(); i++) {
dprintf(fd, " %ums=%u", frameTimeForSlowFrameCountIndex(i),
data->slowFrameCounts[i]);
}
dprintf(fd, "\n");
}
注释2:dumpMemoryUsage:
void Caches::dumpMemoryUsage(String8 &log) {
uint32_t total = 0;
log.appendFormat("Current memory usage / total memory usage (bytes):\n");
log.appendFormat(" TextureCache %8d / %8d\n",
textureCache.getSize(), textureCache.getMaxSize());
if (mRenderState) {
int memused = 0;
for (std::set::iterator it = mRenderState->mActiveLayers.begin();
it != mRenderState->mActiveLayers.end(); it++) {
const Layer* layer = *it;
LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL);
const GlLayer* glLayer = static_cast(layer);
log.appendFormat(" GlLayer size %dx%d; texid=%u refs=%d\n",
layer->getWidth(), layer->getHeight(),
glLayer->getTextureId(),
layer->getStrongCount());
memused += layer->getWidth() * layer->getHeight() * 4;
}
log.appendFormat(" Layers total %8d (numLayers = %zu)\n",
memused, mRenderState->mActiveLayers.size());
total += memused;
}
log.appendFormat(" RenderBufferCache %8d / %8d\n",
renderBufferCache.getSize(), renderBufferCache.getMaxSize());
log.appendFormat(" GradientCache %8d / %8d\n",
gradientCache.getSize(), gradientCache.getMaxSize());
log.appendFormat(" PathCache %8d / %8d\n",
pathCache.getSize(), pathCache.getMaxSize());
log.appendFormat(" TessellationCache %8d / %8d\n",
tessellationCache.getSize(), tessellationCache.getMaxSize());
log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(),
dropShadowCache.getMaxSize());
log.appendFormat(" PatchCache %8d / %8d\n",
patchCache.getSize(), patchCache.getMaxSize());
fontRenderer.dumpMemoryUsage(log);
log.appendFormat("Other:\n");
log.appendFormat(" FboCache %8d / %8d\n",
fboCache.getSize(), fboCache.getMaxSize());
total += textureCache.getSize();
total += renderBufferCache.getSize();
total += gradientCache.getSize();
total += pathCache.getSize();
total += tessellationCache.getSize();
total += dropShadowCache.getSize();
total += patchCache.getSize();
total += fontRenderer.getSize();
log.appendFormat("Total memory usage:\n");
log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f);
#ifdef BUGREPORT_FONT_CACHE_USAGE
fontRenderer.getFontRenderer().historyTracker().dump(log);
#endif
}
至此,dumpsys的调用流程就分析完了,如果想知道dump出的信息具体是怎么来的,可以参考该流程,去分析数据的来源。
dumpsys gfxinfo的信息详解: