1096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger/*
2096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * Copyright 2013 Google Inc.
3096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger *
4096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
5096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * found in the LICENSE file.
6096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger */
7096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
8096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkPurgeableMemoryBlock.h"
9096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
10096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "android/ashmem.h"
11096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include <sys/mman.h>
12096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include <unistd.h>
13096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
14096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerbool SkPurgeableMemoryBlock::IsSupported() {
15096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return true;
16096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
17096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
18096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#ifdef SK_DEBUG
19096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerbool SkPurgeableMemoryBlock::PlatformSupportsPurgingAllUnpinnedBlocks() {
20096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return false;
21096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
22096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
23096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerbool SkPurgeableMemoryBlock::PurgeAllUnpinnedBlocks() {
24096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return false;
25096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
26096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
27096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerbool SkPurgeableMemoryBlock::purge() {
28096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(!fPinned);
29096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (-1 != fFD) {
30096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        ashmem_purge_all_caches(fFD);
31096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return true;
32096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    } else {
33096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return false;
34096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
35096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
36096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#endif
37096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
38096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger// ashmem likes lengths on page boundaries.
39096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstatic size_t round_to_page_size(size_t size) {
40096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    const size_t mask = getpagesize() - 1;
41096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    size_t newSize = (size + mask) & ~mask;
42096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return newSize;
43096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
44096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
45096defe64d408e54474fe19f418c95bf1a554fc7Derek SollenbergerSkPurgeableMemoryBlock::SkPurgeableMemoryBlock(size_t size)
46096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    : fAddr(NULL)
47096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    , fSize(round_to_page_size(size))
48096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    , fPinned(false)
49096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    , fFD(-1) {
50096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
51096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
52096defe64d408e54474fe19f418c95bf1a554fc7Derek SollenbergerSkPurgeableMemoryBlock::~SkPurgeableMemoryBlock() {
53096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (-1 != fFD) {
54096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        munmap(fAddr, fSize);
55096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        close(fFD);
56096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
57096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
58096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
59096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergervoid* SkPurgeableMemoryBlock::pin(SkPurgeableMemoryBlock::PinResult* pinResult) {
60096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(!fPinned);
61096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (-1 == fFD) {
62096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        int fd = ashmem_create_region(NULL, fSize);
63096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (-1 == fd) {
64096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            SkDebugf("ashmem_create_region failed\n");
65096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return NULL;
66096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
67096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
68096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
69096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (err != 0) {
70096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            SkDebugf("ashmem_set_prot_region failed\n");
71096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            close(fd);
72096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return NULL;
73096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
74096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
75096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        void* addr = mmap(NULL, fSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
76096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (-1 == (long) addr) {
77096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            SkDebugf("mmap failed\n");
78096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            close(fd);
79096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return NULL;
80096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
81096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fAddr = addr;
82096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fFD = fd;
83096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        (void) ashmem_pin_region(fd, 0, 0);
84096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        *pinResult = kUninitialized_PinResult;
85096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fPinned = true;
86096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    } else {
87096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        int pin = ashmem_pin_region(fFD, 0, 0);
88096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (ASHMEM_NOT_PURGED == pin) {
89096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            fPinned = true;
90096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            *pinResult = kRetained_PinResult;
91096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        } else if (ASHMEM_WAS_PURGED == pin) {
92096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            fPinned = true;
93096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            *pinResult = kUninitialized_PinResult;
94096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        } else {
95096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            // Failed.
96096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            munmap(fAddr, fSize);
97096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            close(fFD);
98096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            fFD = -1;
99096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            fAddr = NULL;
100096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
101096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
102096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return fAddr;
103096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
104096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
105096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergervoid SkPurgeableMemoryBlock::unpin() {
106096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (-1 != fFD) {
107096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        ashmem_unpin_region(fFD, 0, 0);
108096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fPinned = false;
109096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
110096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
111