158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate/*
258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * Copyright (C) 2013 The Android Open Source Project
358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate *
458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * Licensed under the Apache License, Version 2.0 (the "License");
558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * you may not use this file except in compliance with the License.
658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * You may obtain a copy of the License at
758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate *
858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate *      http://www.apache.org/licenses/LICENSE-2.0
958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate *
1058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * Unless required by applicable law or agreed to in writing, software
1158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * distributed under the License is distributed on an "AS IS" BASIS,
1258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * See the License for the specific language governing permissions and
1458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * limitations under the License.
1558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate */
1658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
1758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tatepackage com.android.server.am;
1858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
1958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tateimport android.app.ApplicationErrorReport.CrashInfo;
20cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughesimport android.system.ErrnoException;
21cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughesimport android.system.Os;
22cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughesimport android.system.StructTimeval;
23e9d537506bf19375fb932ac7d25ac9a9e3aef61dNeil Fullerimport android.system.UnixSocketAddress;
2458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tateimport android.util.Slog;
2558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
26cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughesimport static android.system.OsConstants.*;
2758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
2858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tateimport java.io.ByteArrayOutputStream;
2958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tateimport java.io.File;
3058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tateimport java.io.FileDescriptor;
3143582df3dbcad1b1734b570c74246f5ff2f58027Neil Fullerimport java.io.InterruptedIOException;
3258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tateimport java.net.InetSocketAddress;
3358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
3458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate/**
3558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * Set up a Unix domain socket that debuggerd will connect() to in
3658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * order to write a description of a native crash.  The crash info is
3758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * then parsed and forwarded to the ActivityManagerService's normal
3858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * crash handling code.
3958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate *
4058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate * Note that this component runs in a separate thread.
4158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate */
42be4e6aaa0252dd7da28b7aa85beba982538efa46Dianne Hackbornfinal class NativeCrashListener extends Thread {
4358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    static final String TAG = "NativeCrashListener";
4458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    static final boolean DEBUG = false;
451b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate    static final boolean MORE_DEBUG = DEBUG && false;
4658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
4758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    // Must match the path defined in debuggerd.c.
4858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    static final String DEBUGGERD_SOCKET_PATH = "/data/system/ndebugsocket";
4958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
5058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    // Use a short timeout on socket operations and abandon the connection
51404fd65e436df7600bbb1b495720f8d1288b0d9dChristopher Tate    // on hard errors, just in case debuggerd goes out to lunch.
52404fd65e436df7600bbb1b495720f8d1288b0d9dChristopher Tate    static final long SOCKET_TIMEOUT_MILLIS = 10000;  // 10 seconds
5358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
5458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    final ActivityManagerService mAm;
5558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
5658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    /*
5758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate     * Spin the actual work of handling a debuggerd crash report into a
5858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate     * separate thread so that the listener can go immediately back to
5958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate     * accepting incoming connections.
6058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate     */
6158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    class NativeCrashReporter extends Thread {
6258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        ProcessRecord mApp;
6358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        int mSignal;
6458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        String mCrashReport;
6558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
6658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        NativeCrashReporter(ProcessRecord app, int signal, String report) {
6758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            super("NativeCrashReport");
6858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            mApp = app;
6958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            mSignal = signal;
7058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            mCrashReport = report;
7158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        }
7258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
7358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        @Override
7458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        public void run() {
7558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            try {
7658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                CrashInfo ci = new CrashInfo();
7758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                ci.exceptionClassName = "Native crash";
78cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughes                ci.exceptionMessage = Os.strsignal(mSignal);
7958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                ci.throwFileName = "unknown";
8058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                ci.throwClassName = "unknown";
8158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                ci.throwMethodName = "unknown";
8258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                ci.stackTrace = mCrashReport;
8358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
8458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                if (DEBUG) Slog.v(TAG, "Calling handleApplicationCrash()");
8588d842cf8a3adcae5cd2d243dcc182c96f40db29Eric Rowe                mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);
8658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                if (DEBUG) Slog.v(TAG, "<-- handleApplicationCrash() returned");
8758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            } catch (Exception e) {
8858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                Slog.e(TAG, "Unable to report native crash", e);
8958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            }
9058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        }
9158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    }
9258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
9358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    /*
9458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate     * Daemon thread that accept()s incoming domain socket connections from debuggerd
9558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate     * and processes the crash dump that is passed through.
9658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate     */
974ccb823a9f62e57f9d221f83a97e82967e79a9e5Jeff Brown    NativeCrashListener(ActivityManagerService am) {
984ccb823a9f62e57f9d221f83a97e82967e79a9e5Jeff Brown        mAm = am;
9958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    }
10058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
10158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    @Override
10258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    public void run() {
10358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        final byte[] ackSignal = new byte[1];
10458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
10558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        if (DEBUG) Slog.i(TAG, "Starting up");
10658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
107b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao        // The file system entity for this socket is created with 0777 perms, owned
108b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao        // by system:system. selinux restricts things so that only crash_dump can
109b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao        // access it.
11058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        {
11158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            File socketFile = new File(DEBUGGERD_SOCKET_PATH);
11258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            if (socketFile.exists()) {
11358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                socketFile.delete();
11458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            }
11558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        }
11658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
11758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        try {
118cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughes            FileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
119e9d537506bf19375fb932ac7d25ac9a9e3aef61dNeil Fuller            final UnixSocketAddress sockAddr = UnixSocketAddress.createFileSystem(
120e9d537506bf19375fb932ac7d25ac9a9e3aef61dNeil Fuller                    DEBUGGERD_SOCKET_PATH);
121e9d537506bf19375fb932ac7d25ac9a9e3aef61dNeil Fuller            Os.bind(serverFd, sockAddr);
122cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughes            Os.listen(serverFd, 1);
123b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao            Os.chmod(DEBUGGERD_SOCKET_PATH, 0777);
12458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
12558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            while (true) {
12658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                FileDescriptor peerFd = null;
12758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                try {
1281b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate                    if (MORE_DEBUG) Slog.v(TAG, "Waiting for debuggerd connection");
129e64f3e3fee8933f2703f616f656583b3923d1b8fNeil Fuller                    peerFd = Os.accept(serverFd, null /* peerAddress */);
1301b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate                    if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
13158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    if (peerFd != null) {
132b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao                        // the reporting thread may take responsibility for
133b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao                        // acking the debugger; make sure we play along.
134b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao                        consumeNativeCrashData(peerFd);
13558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    }
13658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                } catch (Exception e) {
13758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    Slog.w(TAG, "Error handling connection", e);
13858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                } finally {
139b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao                    // Always ack crash_dump's connection to us.  The actual
14058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    // byte written is irrelevant.
14158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    if (peerFd != null) {
14258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                        try {
143cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughes                            Os.write(peerFd, ackSignal, 0, 1);
1441b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate                        } catch (Exception e) {
1451b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate                            /* we don't care about failures here */
1461b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate                            if (MORE_DEBUG) {
1471b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate                                Slog.d(TAG, "Exception writing ack: " + e.getMessage());
1481b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate                            }
1491b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate                        }
1501b2d59500a8c066dec413f906c480ee46f004df5Nick Kralevich                        try {
151cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughes                            Os.close(peerFd);
1521b2d59500a8c066dec413f906c480ee46f004df5Nick Kralevich                        } catch (ErrnoException e) {
1531b2d59500a8c066dec413f906c480ee46f004df5Nick Kralevich                            if (MORE_DEBUG) {
1541b2d59500a8c066dec413f906c480ee46f004df5Nick Kralevich                                Slog.d(TAG, "Exception closing socket: " + e.getMessage());
1551b2d59500a8c066dec413f906c480ee46f004df5Nick Kralevich                            }
1561b2d59500a8c066dec413f906c480ee46f004df5Nick Kralevich                        }
15758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    }
15858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                }
15958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            }
16058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        } catch (Exception e) {
16158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            Slog.e(TAG, "Unable to init native debug socket!", e);
16258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        }
16358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    }
16458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
16558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    static int unpackInt(byte[] buf, int offset) {
16658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        int b0, b1, b2, b3;
16758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
16858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        b0 = ((int) buf[offset]) & 0xFF; // mask against sign extension
16958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        b1 = ((int) buf[offset+1]) & 0xFF;
17058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        b2 = ((int) buf[offset+2]) & 0xFF;
17158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        b3 = ((int) buf[offset+3]) & 0xFF;
17258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
17358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    }
17458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
17558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    static int readExactly(FileDescriptor fd, byte[] buffer, int offset, int numBytes)
17643582df3dbcad1b1734b570c74246f5ff2f58027Neil Fuller            throws ErrnoException, InterruptedIOException {
17758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        int totalRead = 0;
17858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        while (numBytes > 0) {
179cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughes            int n = Os.read(fd, buffer, offset + totalRead, numBytes);
18058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            if (n <= 0) {
18158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                if (DEBUG) {
18258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    Slog.w(TAG, "Needed " + numBytes + " but saw " + n);
18358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                }
18458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                return -1;  // premature EOF or timeout
18558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            }
18658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            numBytes -= n;
18758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            totalRead += n;
18858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        }
18958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        return totalRead;
19058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    }
19158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
192b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao    // Read a crash report from the connection
19358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    void consumeNativeCrashData(FileDescriptor fd) {
1941b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate        if (MORE_DEBUG) Slog.i(TAG, "debuggerd connected");
19558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        final byte[] buf = new byte[4096];
19658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        final ByteArrayOutputStream os = new ByteArrayOutputStream(4096);
19758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
19858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        try {
19958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            StructTimeval timeout = StructTimeval.fromMillis(SOCKET_TIMEOUT_MILLIS);
200cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughes            Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
201cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughes            Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);
20258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
203b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao            // The socket is guarded by an selinux neverallow rule that only
204b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao            // permits crash_dump to connect to it. This allows us to trust the
205b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao            // received values.
206b9eb093c3cb49c3ac44823d5a0d818e66b9bbcd3Josh Gao
20758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            // first, the pid and signal number
20858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            int headerBytes = readExactly(fd, buf, 0, 8);
20958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            if (headerBytes != 8) {
21058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                // protocol failure; give up
21158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                Slog.e(TAG, "Unable to read from debuggerd");
21258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                return;
21358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            }
21458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
21558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            int pid = unpackInt(buf, 0);
21658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            int signal = unpackInt(buf, 4);
21758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            if (DEBUG) {
21858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                Slog.v(TAG, "Read pid=" + pid + " signal=" + signal);
21958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            }
22058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
22158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            // now the text of the dump
22258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            if (pid > 0) {
22358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                final ProcessRecord pr;
22458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                synchronized (mAm.mPidsSelfLocked) {
22558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    pr = mAm.mPidsSelfLocked.get(pid);
22658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                }
22758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                if (pr != null) {
228b86d81d3ff1beb46b18795edbbb8850e9cde4c98Christopher Tate                    // Don't attempt crash reporting for persistent apps
229b86d81d3ff1beb46b18795edbbb8850e9cde4c98Christopher Tate                    if (pr.persistent) {
230b86d81d3ff1beb46b18795edbbb8850e9cde4c98Christopher Tate                        if (DEBUG) {
231b86d81d3ff1beb46b18795edbbb8850e9cde4c98Christopher Tate                            Slog.v(TAG, "Skipping report for persistent app " + pr);
232b86d81d3ff1beb46b18795edbbb8850e9cde4c98Christopher Tate                        }
233b86d81d3ff1beb46b18795edbbb8850e9cde4c98Christopher Tate                        return;
234b86d81d3ff1beb46b18795edbbb8850e9cde4c98Christopher Tate                    }
235b86d81d3ff1beb46b18795edbbb8850e9cde4c98Christopher Tate
23658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    int bytes;
23758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    do {
23858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                        // get some data
239cacbe1b1ef01aff8726726edaf43d0b449319afeElliott Hughes                        bytes = Os.read(fd, buf, 0, buf.length);
24058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                        if (bytes > 0) {
2411b645986020a5bd66f6783fa87b9f084c809d801Christopher Tate                            if (MORE_DEBUG) {
24258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                                String s = new String(buf, 0, bytes, "UTF-8");
24358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                                Slog.v(TAG, "READ=" + bytes + "> " + s);
24458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                            }
24558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                            // did we just get the EOD null byte?
24658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                            if (buf[bytes-1] == 0) {
24758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                                os.write(buf, 0, bytes-1);  // exclude the EOD token
24858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                                break;
24958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                            }
25058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                            // no EOD, so collect it and read more
25158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                            os.write(buf, 0, bytes);
25258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                        }
25358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    } while (bytes > 0);
25458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
25558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    // Okay, we've got the report.
25658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    if (DEBUG) Slog.v(TAG, "processing");
25758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
25858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    // Mark the process record as being a native crash so that the
25958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    // cleanup mechanism knows we're still submitting the report
26058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    // even though the process will vanish as soon as we let
26158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    // debuggerd proceed.
26258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    synchronized (mAm) {
26358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                        pr.crashing = true;
26458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                        pr.forceCrashReport = true;
26558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    }
26658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
26758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    // Crash reporting is synchronous but we want to let debuggerd
26858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    // go about it business right away, so we spin off the actual
26958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    // reporting logic on a thread and let it take it's time.
27058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    final String reportString = new String(os.toByteArray(), "UTF-8");
27158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    (new NativeCrashReporter(pr, signal, reportString)).start();
27258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                } else {
27358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                    Slog.w(TAG, "Couldn't find ProcessRecord for pid " + pid);
27458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                }
27558d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            } else {
27658d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate                Slog.e(TAG, "Bogus pid!");
27758d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            }
27858d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        } catch (Exception e) {
27958d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            Slog.e(TAG, "Exception dealing with report", e);
28058d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate            // ugh, fail.
28158d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate        }
28258d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate    }
28358d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate
28458d380d2af8079075e4773a3e5ca6c2820760e3dChristopher Tate}
285