您的位置:首页 > 移动开发 > Android开发

ActivityManagerService native crash处理流程

2017-03-06 17:51 232 查看
在@AMS中会注册接收native crash的监听器, 以便在native进程crash时清理恢复app的生命周期等事项。

开机AMS在启动时注册监听:

mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
Slog.i(TAG, "Making services ready");
try {
mActivityManagerService.startObservingNativeCrashes();
} catch (Throwable e) {
reportWtf("observing native crashes", e);
}
...
public void startObservingNativeCrashes() {
final NativeCrashListener ncl = new NativeCrashListener(this);
ncl.start();
}


NativeCrashListener 线程开始不断监听debugger的socket:/data/system/ndebugsocket

// Must match the path defined in debuggerd.c.-->tombstones.cpp
static final String DEBUGGERD_SOCKET_PATH = "/data/system/ndebugsocket";
final class NativeCrashListener extends Thread:
public void run() {
final byte[] ackSignal = new byte[1];

if (DEBUG) Slog.i(TAG, "Starting up");

// The file system entity for this socket is created with 0700 perms, owned
// by system:system.  debuggerd runs as root, so is capable of connecting to
// it, but 3rd party apps cannot.
{
File socketFile = new File(DEBUGGERD_SOCKET_PATH);
if (socketFile.exists()) {
socketFile.delete();
}
}

try {
FileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
final InetUnixAddress sockAddr = new InetUnixAddress(DEBUGGERD_SOCKET_PATH);
Os.bind(serverFd, sockAddr, 0);
Os.listen(serverFd, 1);

while (true) {
InetSocketAddress peer = new InetSocketAddress();
FileDescriptor peerFd = null;
try {
if (MORE_DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
peerFd = Os.accept(serverFd, peer);
if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
if (peerFd != null) {
// Only the superuser is allowed to talk to us over this socket
StructUcred credentials =
Os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);
if (credentials.uid == 0) {
// the reporting thread may take responsibility for
// acking the debugger; make sure we play along.
consumeNativeCrashData(peerFd);
}
}
} catch (Exception e) {
Slog.w(TAG, "Error handling connection", e);
} finally {
// Always ack debuggerd's connection to us.  The actual
// byte written is irrelevant.
if (peerFd != null) {
try {
Os.write(peerFd, ackSignal, 0, 1);
} catch (Exception e) {
/* we don't care about failures here */
if (MORE_DEBUG) {
Slog.d(TAG, "Exception writing ack: " + e.getMessage());
}
}
try {
Os.close(peerFd);
} catch (ErrnoException e) {
if (MORE_DEBUG) {
Slog.d(TAG, "Exception closing socket: " + e.getMessage());
}
}
}
}
}
} catch (Exception e) {
Slog.e(TAG, "Unable to init native debug socket!", e);
}
}


有从debuggerd收到socket数据时,处理crash数据:

// Read the crash report from the debuggerd connection
void consumeNativeCrashData(FileDescriptor fd) {
if (MORE_DEBUG) Slog.i(TAG, "debuggerd connected");
final byte[] buf = new byte[4096];
final ByteArrayOutputStream os = new ByteArrayOutputStream(4096);

try {
StructTimeval timeout = StructTimeval.fromMillis(SOCKET_TIMEOUT_MILLIS);
Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);

// first, the pid and signal number
int headerBytes = readExactly(fd, buf, 0, 8);
if (headerBytes != 8) {
// protocol failure; give up
Slog.e(TAG, "Unable to read from debuggerd");
return;
}

int pid = unpackInt(buf, 0);
int signal = unpackInt(buf, 4);
if (DEBUG) {
Slog.v(TAG, "Read pid=" + pid + " signal=" + signal);
}

// now the text of the dump
if (pid > 0) {
final ProcessRecord pr;
synchronized (mAm.mPidsSelfLocked) {
pr = mAm.mPidsSelfLocked.get(pid);
}
if (pr != null) {
// Don't attempt crash reporting for persistent apps
if (pr.persistent) {
if (DEBUG) {
Slog.v(TAG, "Skipping report for persistent app " + pr);
}
return;
}

int bytes;
do {
// get some data
bytes = Os.read(fd, buf, 0, buf.length);
if (bytes > 0) {
if (MORE_DEBUG) {
String s = new String(buf, 0, bytes, "UTF-8");
Slog.v(TAG, "READ=" + bytes + "> " + s);
}
// did we just get the EOD null byte?
if (buf[bytes-1] == 0) {
os.write(buf, 0, bytes-1);  // exclude the EOD token
break;
}
// no EOD, so collect it and read more
os.write(buf, 0, bytes);
}
} while (bytes > 0);

// Okay, we've got the report.
if (DEBUG) Slog.v(TAG, "processing");

// Mark the process record as being a native crash so that the
// cleanup mechanism knows we're still submitting the report
// even though the process will vanish as soon as we let
// debuggerd proceed.
synchronized (mAm) {
pr.crashing = true;
pr.forceCrashReport = true;
}

// Crash reporting is synchronous but we want to let debuggerd
// go about it business right away, so we spin off the actual
// reporting logic on a thread and let it take it's time.
final String reportString = new String(os.toByteArray(), "UTF-8");
(new NativeCrashReporter(pr, signal, reportString)).start();
} else {
Slog.w(TAG, "Couldn't find ProcessRecord for pid " + pid);
}
} else {
Slog.e(TAG, "Bogus pid!");
}
} catch (Exception e) {
Slog.e(TAG, "Exception dealing with report", e);
// ugh, fail.
}


新开thread处理crash具体数据,让AMS作对应处理:

class NativeCrashReporter extends Thread :

public void run() {
try {
CrashInfo ci = new CrashInfo();
ci.exceptionClassName = "Native crash";
ci.exceptionMessage = Os.strsignal(mSignal);
ci.throwFileName = "unknown";
ci.throwClassName = "unknown";
ci.throwMethodName = "unknown";
ci.stackTrace = mCrashReport;

if (DEBUG) Slog.v(TAG, "Calling handleApplicationCrash()");
mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);
if (DEBUG) Slog.v(TAG, "<-- handleApplicationCrash() returned");
} catch (Exception e) {
Slog.e(TAG, "Unable to report native crash", e);
}
}


@AMS处理,

/* Native crash reporting uses this inner version because it needs to be somewhat
* decoupled from the AM-managed cleanup lifecycle
*/
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
UserHandle.getUserId(Binder.getCallingUid()), processName,
r == null ? -1 : r.info.flags,
crashInfo.exceptionClassName,
crashInfo.exceptionMessage,
crashInfo.throwFileName,
crashInfo.throwLineNumber);

addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);

crashApplication(r, crashInfo);
}


native 部分:

开机启动时会开启debuggerd监控进程接收native进程异常信号量,如SIGSTOP,SIGABRT,SIGSEGV等,native处理完成后,即会往上面AMS里介绍的final InetUnixAddress sockAddr = new InetUnixAddress(DEBUGGERD_SOCKET_PATH)这个socket通知,native详细流程可以参考,

http://www.2cto.com/kf/201408/323895.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android native crash