1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2013 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOSFile.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkString.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTFitsIn.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTemplates.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTypes.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <dirent.h>
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <stdio.h>
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <string.h>
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <sys/mman.h>
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <sys/stat.h>
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <sys/types.h>
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <unistd.h>
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_BUILD_FOR_IOS
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOSFile_ios.h"
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool sk_exists(const char *path, SkFILE_Flags flags) {
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int mode = F_OK;
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (flags & kRead_SkFILE_Flag) {
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mode |= R_OK;
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (flags & kWrite_SkFILE_Flag) {
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mode |= W_OK;
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_BUILD_FOR_IOS
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // if the default path fails, check the bundle (but only if read-only)
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 == access(path, mode)) {
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return (kRead_SkFILE_Flag == flags && ios_get_path_in_bundle(path, nullptr));
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return (0 == access(path, mode));
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottypedef struct {
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    dev_t dev;
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ino_t ino;
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} SkFILEID;
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool sk_ino(FILE* a, SkFILEID* id) {
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int fd = fileno(a);
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fd < 0) {
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return 0;
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    struct stat status;
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 != fstat(fd, &status)) {
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return 0;
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    id->dev = status.st_dev;
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    id->ino = status.st_ino;
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool sk_fidentical(FILE* a, FILE* b) {
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkFILEID aID, bID;
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return sk_ino(a, &aID) && sk_ino(b, &bID)
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot           && aID.ino == bID.ino
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot           && aID.dev == bID.dev;
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid sk_fmunmap(const void* addr, size_t length) {
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    munmap(const_cast<void*>(addr), length);
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid* sk_fdmmap(int fd, size_t* size) {
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    struct stat status;
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 != fstat(fd, &status)) {
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return nullptr;
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!S_ISREG(status.st_mode)) {
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return nullptr;
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!SkTFitsIn<size_t>(status.st_size)) {
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return nullptr;
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t fileSize = static_cast<size_t>(status.st_size);
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void* addr = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0);
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (MAP_FAILED == addr) {
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return nullptr;
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *size = fileSize;
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return addr;
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint sk_fileno(FILE* f) {
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fileno(f);
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid* sk_fmmap(FILE* f, size_t* size) {
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int fd = sk_fileno(f);
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fd < 0) {
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return nullptr;
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return sk_fdmmap(fd, size);
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsize_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) {
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int fd = sk_fileno(file);
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fd < 0) {
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return SIZE_MAX;
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ssize_t bytesRead = pread(fd, buffer, count, offset);
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (bytesRead < 0) {
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return SIZE_MAX;
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return bytesRead;
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot////////////////////////////////////////////////////////////////////////////
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct SkOSFileIterData {
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOSFileIterData() : fDIR(nullptr) { }
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DIR* fDIR;
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkString fPath, fSuffix;
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic_assert(sizeof(SkOSFileIterData) <= SkOSFile::Iter::kStorageSize, "not_enough_space");
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOSFile::Iter::Iter() { new (fSelf.get()) SkOSFileIterData; }
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOSFile::Iter::Iter(const char path[], const char suffix[]) {
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    new (fSelf.get()) SkOSFileIterData;
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->reset(path, suffix);
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOSFile::Iter::~Iter() {
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (self.fDIR) {
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ::closedir(self.fDIR);
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    self.~SkOSFileIterData();
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOSFile::Iter::reset(const char path[], const char suffix[]) {
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (self.fDIR) {
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ::closedir(self.fDIR);
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        self.fDIR = nullptr;
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    self.fPath.set(path);
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (path) {
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        self.fDIR = ::opendir(path);
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_BUILD_FOR_IOS
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // check bundle for directory
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!self.fDIR && ios_get_path_in_bundle(path, &self.fPath)) {
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            self.fDIR = ::opendir(self.fPath.c_str());
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        self.fSuffix.set(suffix);
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        self.fSuffix.reset();
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// returns true if suffix is empty, or if str ends with suffix
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool issuffixfor(const SkString& suffix, const char str[]) {
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t  suffixLen = suffix.size();
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t  strLen = strlen(str);
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return  strLen >= suffixLen &&
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memcmp(suffix.c_str(), str + strLen - suffixLen, suffixLen) == 0;
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOSFile::Iter::next(SkString* name, bool getDir) {
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get());
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (self.fDIR) {
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        dirent* entry;
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((entry = ::readdir(self.fDIR)) != nullptr) {
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            struct stat s;
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkString str(self.fPath);
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!str.endsWith("/") && !str.endsWith("\\")) {
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                str.append("/");
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str.append(entry->d_name);
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (0 == stat(str.c_str(), &s)) {
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (getDir) {
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (s.st_mode & S_IFDIR) {
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        break;
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (!(s.st_mode & S_IFDIR) && issuffixfor(self.fSuffix, entry->d_name)) {
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        break;
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (entry) { // we broke out with a file
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (name) {
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                name->set(entry->d_name);
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
213