1c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood/*
2c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
3c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood *
4c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
5c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * you may not use this file except in compliance with the License.
6c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * You may obtain a copy of the License at
7c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood *
8c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
9c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood *
10c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * Unless required by applicable law or agreed to in writing, software
11c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
12c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * See the License for the specific language governing permissions and
14c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood * limitations under the License.
15c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood */
16c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
17c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <errno.h>
18c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <unistd.h>
19c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <stdio.h>
20c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <fcntl.h>
21cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan#include <stdlib.h>
22cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan#include <string.h>
23c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
24c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <linux/fb.h>
25c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <sys/ioctl.h>
26c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <sys/mman.h>
27c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
280678a8c250832a5549703f533f6afea9d8729e43Mathias Agopian#include <binder/ProcessState.h>
290678a8c250832a5549703f533f6afea9d8729e43Mathias Agopian
30c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <gui/SurfaceComposerClient.h>
31c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <gui/ISurfaceComposer.h>
32c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
33cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza#include <ui/DisplayInfo.h>
340137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian#include <ui/PixelFormat.h>
350137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian
36cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe// TODO: Fix Skia.
37cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic push
38cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic ignored "-Wunused-parameter"
39c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <SkImageEncoder.h>
40c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood#include <SkData.h>
41cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe#pragma GCC diagnostic pop
42c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
43c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwoodusing namespace android;
44c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
45c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwoodstatic uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
46c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
47c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwoodstatic void usage(const char* pname)
48c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood{
49c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    fprintf(stderr,
50c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "usage: %s [-hp] [-d display-id] [FILENAME]\n"
51c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "   -h: this message\n"
52c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "   -p: save the file as a png.\n"
53c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "   -d: specify the display id to capture, default %d.\n"
54c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "If FILENAME ends with .png it will be saved as a png.\n"
55c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            "If FILENAME is not given, the results will be printed to stdout.\n",
56c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            pname, DEFAULT_DISPLAY_ID
57c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    );
58c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood}
59c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
60b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reedstatic SkColorType flinger2skia(PixelFormat f)
61c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood{
62c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    switch (f) {
63c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        case PIXEL_FORMAT_RGB_565:
64b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reed            return kRGB_565_SkColorType;
65c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        default:
66b933055cf3f7f8ea89bfd3bc9c37a3891ff7310aMike Reed            return kN32_SkColorType;
67c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
68c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood}
69c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
70cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khanstatic status_t notifyMediaScanner(const char* fileName) {
71cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    String8 cmd("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
72cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    String8 fileUrl("\"");
73cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    fileUrl.append(fileName);
74cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    fileUrl.append("\"");
75cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    cmd.append(fileName);
76cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    cmd.append(" > /dev/null");
77cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    int result = system(cmd.string());
78cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    if (result < 0) {
79cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan        fprintf(stderr, "Unable to broadcast intent for media scanner.\n");
80cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan        return UNKNOWN_ERROR;
81cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    }
82cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan    return NO_ERROR;
83cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan}
84cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan
85c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwoodint main(int argc, char** argv)
86c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood{
873b53fc5a84c4db40830d1810dee309accce66f09Martijn Coenen    // setThreadPoolMaxThreadCount(0) actually tells the kernel it's
883b53fc5a84c4db40830d1810dee309accce66f09Martijn Coenen    // not allowed to spawn any additional threads, but we still spawn
893b53fc5a84c4db40830d1810dee309accce66f09Martijn Coenen    // a binder thread from userspace when we call startThreadPool().
903b53fc5a84c4db40830d1810dee309accce66f09Martijn Coenen    // See b/36066697 for rationale
913b53fc5a84c4db40830d1810dee309accce66f09Martijn Coenen    ProcessState::self()->setThreadPoolMaxThreadCount(0);
920678a8c250832a5549703f533f6afea9d8729e43Mathias Agopian    ProcessState::self()->startThreadPool();
930678a8c250832a5549703f533f6afea9d8729e43Mathias Agopian
94c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    const char* pname = argv[0];
95c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    bool png = false;
96c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    int32_t displayId = DEFAULT_DISPLAY_ID;
97c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    int c;
98c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    while ((c = getopt(argc, argv, "phd:")) != -1) {
99c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        switch (c) {
100c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            case 'p':
101c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                png = true;
102c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                break;
103c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            case 'd':
104c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                displayId = atoi(optarg);
105c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                break;
106c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            case '?':
107c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            case 'h':
108c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                usage(pname);
109c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood                return 1;
110c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        }
111c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
112c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    argc -= optind;
113c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    argv += optind;
114c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
115c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    int fd = -1;
116cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    const char* fn = NULL;
117c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    if (argc == 0) {
118c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        fd = dup(STDOUT_FILENO);
119c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    } else if (argc == 1) {
120cfed2326c7e77602fa6278ddf99203d9aaaf8df7Umair Khan        fn = argv[0];
121c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
122c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        if (fd == -1) {
123c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
124c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            return 1;
125c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        }
126c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        const int len = strlen(fn);
127c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) {
128c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            png = true;
129c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        }
130c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
131bf89ae53c3d74365be4bf794283ca26f7d6d3fe1Prathmesh Prabhu
132c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    if (fd == -1) {
133c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        usage(pname);
134c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        return 1;
135c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
136c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
137c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    void const* mapbase = MAP_FAILED;
138c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    ssize_t mapsize = -1;
139c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
140cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    void const* base = NULL;
1410137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian    uint32_t w, s, h, f;
142c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    size_t size = 0;
143c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
144cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    // Maps orientations from DisplayInfo to ISurfaceComposer
145cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    static const uint32_t ORIENTATION_MAP[] = {
146cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza        ISurfaceComposer::eRotateNone, // 0 == DISPLAY_ORIENTATION_0
147cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza        ISurfaceComposer::eRotate270, // 1 == DISPLAY_ORIENTATION_90
148cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza        ISurfaceComposer::eRotate180, // 2 == DISPLAY_ORIENTATION_180
149cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza        ISurfaceComposer::eRotate90, // 3 == DISPLAY_ORIENTATION_270
150cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    };
151cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza
152c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    ScreenshotClient screenshot;
153c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
154cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    if (display == NULL) {
155cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza        fprintf(stderr, "Unable to get handle for display %d\n", displayId);
156cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza        return 1;
157cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    }
158cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza
159cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    Vector<DisplayInfo> configs;
160cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    SurfaceComposerClient::getDisplayConfigs(display, &configs);
161cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    int activeConfig = SurfaceComposerClient::getActiveConfig(display);
162cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    if (static_cast<size_t>(activeConfig) >= configs.size()) {
163cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza        fprintf(stderr, "Active config %d not inside configs (size %zu)\n",
164cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza                activeConfig, configs.size());
165cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza        return 1;
166cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    }
167cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    uint8_t displayOrientation = configs[activeConfig].orientation;
168cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation];
169cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza
170db7ecbe6994c5ec2cc46a6468300c927ebf7db37Robert Carr    status_t result = screenshot.update(display, Rect(),
171db7ecbe6994c5ec2cc46a6468300c927ebf7db37Robert Carr            0 /* reqWidth */, 0 /* reqHeight */,
172db7ecbe6994c5ec2cc46a6468300c927ebf7db37Robert Carr            INT32_MIN, INT32_MAX, /* all layers */
173cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza            false, captureOrientation);
174cf70d71781a40d197c3ecde89351976b27eb9a8aDan Stoza    if (result == NO_ERROR) {
175c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        base = screenshot.getPixels();
176c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        w = screenshot.getWidth();
177c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        h = screenshot.getHeight();
1780137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian        s = screenshot.getStride();
179c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        f = screenshot.getFormat();
180c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        size = screenshot.getSize();
181c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
182c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood
183cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe    if (base != NULL) {
184c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        if (png) {
18510219fb261606fcc71c607167b28295b4578a10dHal Canary            const SkImageInfo info =
18610219fb261606fcc71c607167b28295b4578a10dHal Canary                SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType);
18710219fb261606fcc71c607167b28295b4578a10dHal Canary            SkPixmap pixmap(info, base, s * bytesPerPixel(f));
18810219fb261606fcc71c607167b28295b4578a10dHal Canary            struct FDWStream final : public SkWStream {
18910219fb261606fcc71c607167b28295b4578a10dHal Canary              size_t fBytesWritten = 0;
19010219fb261606fcc71c607167b28295b4578a10dHal Canary              int fFd;
19110219fb261606fcc71c607167b28295b4578a10dHal Canary              FDWStream(int f) : fFd(f) {}
19210219fb261606fcc71c607167b28295b4578a10dHal Canary              size_t bytesWritten() const override { return fBytesWritten; }
19310219fb261606fcc71c607167b28295b4578a10dHal Canary              bool write(const void* buffer, size_t size) override {
19410219fb261606fcc71c607167b28295b4578a10dHal Canary                fBytesWritten += size;
19510219fb261606fcc71c607167b28295b4578a10dHal Canary                return size == 0 || ::write(fFd, buffer, size) > 0;
19610219fb261606fcc71c607167b28295b4578a10dHal Canary              }
19710219fb261606fcc71c607167b28295b4578a10dHal Canary            } fdStream(fd);
19810219fb261606fcc71c607167b28295b4578a10dHal Canary            (void)SkEncodeImage(&fdStream, pixmap, SkEncodedImageFormat::kPNG, 100);
199cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe            if (fn != NULL) {
200cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe                notifyMediaScanner(fn);
201cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe            }
202c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        } else {
203c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            write(fd, &w, 4);
204c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            write(fd, &h, 4);
205c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood            write(fd, &f, 4);
2060137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian            size_t Bpp = bytesPerPixel(f);
2070137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian            for (size_t y=0 ; y<h ; y++) {
2080137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian                write(fd, base, w*Bpp);
2090137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian                base = (void *)((char *)base + s*Bpp);
2100137fb8937e69ed41cff3bf8cb0c1fea43daa3b5Mathias Agopian            }
211c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        }
212c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
213c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    close(fd);
214c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    if (mapbase != MAP_FAILED) {
215c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood        munmap((void *)mapbase, mapsize);
216c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood    }
217909825886c58c7f9eeafb6223b6de91e29c97232Josh Gao
218909825886c58c7f9eeafb6223b6de91e29c97232Josh Gao    // b/36066697: Avoid running static destructors.
2199377ce67a834c8c04fde555111fe44d0f728ed81Brian Carlstrom    _exit(0);
220c59b2f9a774c024fe8c893d956cd2749a6bd2673Mike Lockwood}
221