• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "utilities.h"
16 #include <zlib.h>
17 #if defined(is_mingw) && is_mingw
18 #include <io.h>
19 #else
20 #include <cstdio>
21 #include <unistd.h>
22 #endif
23 #if defined(is_ohos) && is_ohos
24 #include "application_info.h"
25 #include "bundle_mgr_proxy.h"
26 #include "iservice_registry.h"
27 #include "system_ability_definition.h"
28 using namespace OHOS;
29 using namespace OHOS::AppExecFwk;
30 #endif
31 
32 namespace OHOS {
33 namespace Developtools {
34 namespace HiPerf {
HoldStringView(std::string_view view)35 const char *MemoryHold::HoldStringView(std::string_view view)
36 {
37     if (view.size() == 0) {
38         return "";
39     }
40     try {
41         // for null end
42         char *p = new (std::nothrow) char[view.size() + 1];
43         if (p == nullptr) {
44             return "";
45         }
46         p[view.size()] = '\0';
47         std::copy(view.data(), view.data() + view.size(), p);
48         holder_.emplace_back(p);
49         return p;
50     } catch (...) {
51         return "";
52     }
53     return "";
54 }
55 
CanonicalizeSpecPath(const char * src)56 std::string CanonicalizeSpecPath(const char* src)
57 {
58     if (src == nullptr) {
59         fprintf(stderr, "Error: CanonicalizeSpecPath failed");
60         return "";
61     } else if (strlen(src) >= PATH_MAX) {
62         fprintf(stderr, "Error: CanonicalizeSpecPath %s failed", src);
63         return "";
64     }
65     char resolvedPath[PATH_MAX] = { 0 };
66 #if defined(_WIN32)
67     if (!_fullpath(resolvedPath, src, PATH_MAX)) {
68         fprintf(stderr, "Error: _fullpath %s failed", src);
69         return "";
70     }
71 #else
72     if (access(src, F_OK) == 0) {
73         if (strstr(src, "/proc/") == src && strstr(src, "/data/storage") != nullptr) { // for sandbox
74             (void)strncpy_s(resolvedPath, sizeof(resolvedPath), src, strlen(src));
75         } else if (realpath(src, resolvedPath) == nullptr) {
76             fprintf(stderr, "Error: realpath %s failed", src);
77             return "";
78         }
79     } else {
80         std::string fileName(src);
81         if (fileName.find("..") == std::string::npos) {
82             if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
83                 fprintf(stderr, "Error: sprintf_s %s failed", src);
84                 return "";
85             }
86         } else {
87             fprintf(stderr, "Error: find .. %s failed", src);
88             return "";
89         }
90     }
91 #endif
92     std::string res(resolvedPath);
93     return res;
94 }
95 
RoundUp(uint32_t x,const int align)96 uint32_t RoundUp(uint32_t x, const int align)
97 {
98     return (((x) + (align)-1) / (align)) * (align);
99 }
100 
StringReplace(std::string source,const std::string & from,const std::string & to)101 std::string StringReplace(std::string source, const std::string &from, const std::string &to)
102 {
103     size_t pos = 0;
104     std::string result;
105     // find
106     while ((pos = source.find(from)) != std::string::npos) {
107         // replace
108         result.append(source.substr(0, pos) + to);
109         source.erase(0, pos + from.length());
110     }
111     // add last token
112     result.append(source);
113     return result;
114 }
115 
SubStringCount(const std::string & source,const std::string & sub)116 size_t SubStringCount(const std::string &source, const std::string &sub)
117 {
118     size_t count(0);
119     size_t pos(0);
120     if (sub.empty()) {
121         return source.size();
122     }
123     while ((pos = source.find(sub, pos)) != std::string::npos) {
124         pos += sub.size();
125         count++;
126     }
127     return count;
128 }
129 
StringSplit(std::string source,std::string split)130 std::vector<std::string> StringSplit(std::string source, std::string split)
131 {
132     std::vector<std::string> result;
133 
134     // find
135     if (!split.empty()) {
136         size_t pos = 0;
137         while ((pos = source.find(split)) != std::string::npos) {
138             // split
139             std::string token = source.substr(0, pos);
140             if (!token.empty()) {
141                 result.push_back(token);
142             }
143             source.erase(0, pos + split.length());
144         }
145     }
146     // add last token
147     if (!source.empty()) {
148         result.push_back(source);
149     }
150     return result;
151 }
StdoutRecord(const std::string & tempFile,const std::string & mode)152 StdoutRecord::StdoutRecord(const std::string &tempFile, const std::string &mode)
153 {
154     if (!tempFile.empty()) {
155         std::string resolvedPath = CanonicalizeSpecPath(tempFile.c_str());
156         recordFile_ = fopen(resolvedPath.c_str(), mode.c_str());
157         if (recordFile_ == nullptr) {
158             HLOGE("tmpfile create failed '%s' with mode '%s'", tempFile.c_str(), mode.c_str());
159         } else {
160             // auto start it
161             Start();
162         }
163     }
164 }
Start()165 bool StdoutRecord::Start()
166 {
167     content_ = EMPTY_STRING;
168     fflush(stdout);
169 
170     // we will save output here
171     if (recordFile_ == nullptr) {
172         recordFile_ = std::tmpfile();
173     }
174     if (recordFile_ == nullptr) {
175         // try second way
176         std::string fileName = "/data/local/tmp/temp.stdout";
177         std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str());
178         recordFile_ = fopen(resolvedPath.c_str(), "w+");
179         if (recordFile_ == nullptr) {
180             HLOGF("tmpfile create failed '%s'", fileName.c_str());
181             return false;
182         }
183     }
184 
185     // we save the stdout
186     stdoutFile_ = OHOS::UniqueFd(dup(STDOUT_FILENO));
187     if (stdoutFile_ == -1) {
188         HLOGF("std dup failed");
189         return false;
190     }
191 
192     // setup temp file as stdout
193     if (dup2(fileno(recordFile_), STDOUT_FILENO) != -1) {
194         stop_ = false;
195         return true;
196     } else {
197         HLOGF("std dup2 failed");
198         return false;
199     }
200 }
201 
Stop()202 std::string StdoutRecord::Stop()
203 {
204     if (stop_)
205         return content_;
206     fflush(stdout);
207     // restore fd
208     dup2(stdoutFile_, STDOUT_FILENO);
209 
210     // return file content
211     if (recordFile_ != nullptr) {
212         const long fileLength = lseek(fileno(recordFile_), 0, SEEK_END);
213         content_.resize(fileLength);
214         lseek(fileno(recordFile_), 0, SEEK_SET);
215         const long len = read(fileno(recordFile_), content_.data(), fileLength);
216         std::fclose(recordFile_);
217         recordFile_ = nullptr;
218         if (len < 0) {
219             HLOGE("tmp file read failed (try read %ld)", fileLength);
220         } else if (len < fileLength) {
221             HLOGE("not all the data is read, lost %ld/%ld bytes", fileLength - len, fileLength);
222         }
223     } else {
224         HLOGE("recordFile_ is nullptr");
225     }
226     stop_ = true;
227     return content_;
228 }
229 
IsDigits(const std::string & str)230 bool IsDigits(const std::string &str)
231 {
232     if (str.empty()) {
233         return false;
234     } else {
235         return std::all_of(str.begin(), str.end(), ::isdigit);
236     }
237 }
238 
IsHexDigits(const std::string & str)239 bool IsHexDigits(const std::string &str)
240 {
241     if (str.empty()) {
242         return false;
243     }
244     const std::string prefix {"0x"};
245     std::string effectStr {str};
246     if (prefix.compare(0, prefix.size(), effectStr.substr(0, prefix.size())) == 0) {
247         effectStr = effectStr.substr(prefix.size(), effectStr.size() - prefix.size());
248     }
249     if (effectStr.empty()) {
250         return false;
251     }
252     std::size_t start {0};
253     for (; start < effectStr.size(); ++start) {
254         if (effectStr[start] == '0') {
255             continue;
256         }
257         break;
258     }
259     if (start == effectStr.size()) {
260         effectStr = "0";
261     }
262     return std::all_of(effectStr.begin(), effectStr.end(), ::isxdigit);
263 }
264 
IsDir(const std::string & path)265 bool IsDir(const std::string &path)
266 {
267     struct stat st;
268     if (stat(path.c_str(), &st) == 0) {
269         return S_ISDIR(st.st_mode);
270     }
271     return false;
272 }
273 
IsPath(const std::string & fileName)274 bool IsPath(const std::string &fileName)
275 {
276     HLOG_ASSERT(!fileName.empty());
277     if (fileName[0] == PATH_SEPARATOR) {
278         return true;
279     }
280     const int prefixPathLen = 2;
281     if (fileName.substr(0, prefixPathLen) == "./") {
282         return true;
283     }
284     return false;
285 }
286 
PlatformPathConvert(const std::string & path)287 std::string PlatformPathConvert(const std::string &path)
288 {
289 #if defined(is_mingw) && is_mingw
290     return StringReplace(path, "/", "\\");
291 #else
292     return path;
293 #endif
294 }
295 
ReadFileToString(const std::string & fileName)296 std::string ReadFileToString(const std::string &fileName)
297 {
298     std::ifstream inputString(fileName, std::ios::in);
299     if (!inputString or !inputString.is_open()) {
300         return EMPTY_STRING;
301     }
302     std::istreambuf_iterator<char> firstIt = {inputString};
303     std::istreambuf_iterator<char> lastIt = {};
304 
305     std::string content(firstIt, lastIt);
306     return content;
307 }
308 
ReadFileToString(const std::string & fileName,std::string & fileData,size_t fileSize)309 bool ReadFileToString(const std::string &fileName, std::string &fileData, size_t fileSize)
310 {
311     fileData.clear();
312     std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str());
313     OHOS::UniqueFd fd(open(resolvedPath.c_str(), O_RDONLY | O_BINARY));
314     if (fileSize == 0) {
315         struct stat fileStat;
316         if (fstat(fd.Get(), &fileStat) != -1 && fileStat.st_size > 0) {
317             fileData.reserve(fileStat.st_size);
318         }
319     } else {
320         fileData.reserve(fileSize);
321     }
322 
323     char buf[BUFSIZ] __attribute__((__uninitialized__));
324     ssize_t readSize;
325     while ((readSize = read(fd.Get(), &buf[0], sizeof(buf))) > 0) {
326         fileData.append(buf, readSize);
327     }
328     return (readSize == 0) ? true : false;
329 }
330 
WriteStringToFile(const std::string & fileName,const std::string & value)331 bool WriteStringToFile(const std::string &fileName, const std::string &value)
332 {
333     std::ofstream output(fileName, std::ios::out);
334     if (!output) {
335         return false;
336     }
337     output << value;
338 
339     return output.good();
340 }
341 
IsRoot()342 bool IsRoot()
343 {
344 #if is_linux || is_ohos
345     static bool isRoot = (getuid() == 0);
346     return isRoot;
347 #else
348     return true;
349 #endif
350 }
351 
PowerOfTwo(uint64_t n)352 bool PowerOfTwo(uint64_t n)
353 {
354     return n && (!(n & (n - 1)));
355 }
356 
ReadIntFromProcFile(const std::string & path,int & value)357 bool ReadIntFromProcFile(const std::string &path, int &value)
358 {
359     std::string s = ReadFileToString(path);
360     if (s.empty()) {
361         return false;
362     }
363     value = std::stoi(s);
364     return true;
365 }
366 
WriteIntToProcFile(const std::string & path,int value)367 bool WriteIntToProcFile(const std::string &path, int value)
368 {
369     std::string s = std::to_string(value);
370 
371     return WriteStringToFile(path, s);
372 }
373 
374 // compress specified dataFile into gzip file
CompressFile(const std::string & dataFile,const std::string & destFile)375 bool CompressFile(const std::string &dataFile, const std::string &destFile)
376 {
377     std::string resolvedPath = CanonicalizeSpecPath(dataFile.c_str());
378     FILE *fp = fopen(resolvedPath.c_str(), "rb");
379     if (fp == nullptr) {
380         HLOGE("Fail to open data file %s", dataFile.c_str());
381         perror("Fail to fopen(rb)");
382         return false;
383     }
384 
385     std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(destFile.c_str(), "wb"), gzclose);
386     if (fgz == nullptr) {
387         HLOGE("Fail to call gzopen(%s)", destFile.c_str());
388         fclose(fp);
389         return false;
390     }
391 
392     std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
393     size_t len = 0;
394     while ((len = fread(buf.data(), sizeof(uint8_t), buf.size(), fp))) {
395         if (gzwrite(fgz.get(), buf.data(), len) == 0) {
396             HLOGE("Fail to call gzwrite for %zu bytes", len);
397             fclose(fp);
398             return false;
399         }
400     }
401     if (!feof(fp)) {
402         if (ferror(fp) != 0) {
403             HLOGE("ferror return err");
404             fclose(fp);
405             return false;
406         }
407     }
408     if (fclose(fp) < 0) {
409         return false;
410     }
411     return true;
412 }
413 
414 // uncompress specified gzip file into dataFile
UncompressFile(const std::string & gzipFile,const std::string & dataFile)415 bool UncompressFile(const std::string &gzipFile, const std::string &dataFile)
416 {
417     std::string resolvedPath = CanonicalizeSpecPath(dataFile.c_str());
418     FILE *fp = fopen(resolvedPath.c_str(), "wb");
419     if (fp == nullptr) {
420         HLOGE("Fail to open data file %s", dataFile.c_str());
421         perror("Fail to fopen(rb)");
422         return false;
423     }
424     std::unique_ptr<gzFile_s, decltype(&gzclose)> fgz(gzopen(gzipFile.c_str(), "rb"), gzclose);
425     if (fgz == nullptr) {
426         HLOGE("Fail to call gzopen(%s)", gzipFile.c_str());
427         fclose(fp);
428         return false;
429     }
430 
431     std::vector<char> buf(COMPRESS_READ_BUF_SIZE);
432     z_size_t len = 0;
433     while ((len = gzfread(buf.data(), sizeof(uint8_t), buf.size(), fgz.get()))) {
434         if (len != fwrite(buf.data(), sizeof(uint8_t), len, fp)) {
435             HLOGE("Fail to call fwrite for %zu bytes", len);
436             fclose(fp);
437             return false;
438         }
439     }
440     if (!gzeof(fgz.get())) {
441         int rc = 0;
442         const char *err = gzerror(fgz.get(), &rc);
443         if (rc != Z_OK) {
444             HLOGE("gzfread return %d:%s", rc, err);
445             fclose(fp);
446             return false;
447         }
448     }
449     if (fclose(fp) < 0) {
450         return false;
451     }
452     return true;
453 }
454 
StringTrim(std::string & string)455 std::string &StringTrim(std::string &string)
456 {
457     if (!string.empty()) {
458         string.erase(0, string.find_first_not_of(" "));
459         string.erase(string.find_last_not_of(" ") + 1);
460     }
461     return string;
462 }
463 
GetEntriesInDir(const std::string & basePath)464 std::vector<std::string> GetEntriesInDir(const std::string &basePath)
465 {
466     std::vector<std::string> result;
467     DIR *dir = opendir(basePath.c_str());
468     if (dir == nullptr) {
469         return result;
470     }
471     dirent *entry;
472     while ((entry = readdir(dir)) != nullptr) {
473         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
474             continue;
475         }
476         result.push_back(entry->d_name);
477     }
478     closedir(dir);
479     return result;
480 }
481 
GetSubDirs(const std::string & basePath)482 std::vector<std::string> GetSubDirs(const std::string &basePath)
483 {
484     std::vector<std::string> entries = GetEntriesInDir(basePath);
485     std::vector<std::string> result = {};
486     for (std::size_t index = 0; index < entries.size(); ++index) {
487         if (IsDir(basePath + "/" + entries[index])) {
488             result.push_back(std::move(entries[index]));
489         }
490     }
491     return result;
492 }
493 
IsSameCommand(const std::string & cmdLine,const std::string & cmdName)494 bool IsSameCommand(const std::string &cmdLine, const std::string &cmdName)
495 {
496     std::vector<std::string> cmdpaths = StringSplit(cmdLine, "/");
497     if (!cmdpaths.empty()) {
498         if (strcmp(cmdpaths.back().c_str(), cmdName.c_str()) == 0) {
499             return true;
500         }
501     }
502     return false;
503 }
504 
GetSubthreadIDs(const pid_t pid)505 std::vector<pid_t> GetSubthreadIDs(const pid_t pid)
506 {
507     std::string path {"/proc/"};
508     path += std::to_string(pid);
509     path += "/task/";
510     auto tids = GetSubDirs(path);
511     std::vector<pid_t> res {};
512     for (auto tidStr : tids) {
513         pid_t tid = static_cast<pid_t>(std::stoul(tidStr, nullptr));
514         if (tid == pid) {
515             continue;
516         }
517         res.push_back(tid);
518     }
519     return res;
520 }
521 
StringStartsWith(const std::string & string,const std::string & with)522 bool StringStartsWith(const std::string &string, const std::string &with)
523 {
524     return string.find(with) == 0;
525 }
526 
StringEndsWith(const std::string & string,const std::string & with)527 bool StringEndsWith(const std::string &string, const std::string &with)
528 {
529     if (string.empty()) {
530         // empty string only end with empty string
531         if (with.empty()) {
532             return true;
533         } else {
534             return false;
535         }
536     }
537     return string.rfind(with) == (string.length() - with.length());
538 }
539 
HexDump(const void * buf,size_t size,size_t maxSize)540 void HexDump(const void *buf, size_t size, size_t maxSize)
541 {
542     const unsigned char *byteBuf = static_cast<const unsigned char *>(buf);
543     const size_t dumpByteEachLine = 8;
544     size_t outputBytes = 0;
545     if (!maxSize) {
546         outputBytes = size;
547     } else {
548         outputBytes = std::min(size, maxSize);
549     }
550 
551     for (size_t i = 0; i <= outputBytes; i += dumpByteEachLine) {
552         HLOGM(" %02zu: %s ", i, BufferToHexString(byteBuf, dumpByteEachLine).c_str());
553         byteBuf += dumpByteEachLine;
554     }
555 }
556 
BufferToHexString(const std::vector<unsigned char> & vec)557 std::string BufferToHexString(const std::vector<unsigned char> &vec)
558 {
559     return BufferToHexString(vec.data(), vec.size());
560 }
561 
BufferToHexString(const unsigned char buf[],size_t size)562 std::string BufferToHexString(const unsigned char buf[], size_t size)
563 {
564     std::stringstream ss;
565     ss << size << ":";
566     for (size_t i = 0; i < size; i++) {
567         ss << " 0x" << std::setfill('0') << std::setw(BYTE_PRINT_WIDTH) << std::hex
568            << (unsigned short)buf[i];
569     }
570     return ss.str();
571 }
572 
573 #if defined(is_mingw) && !is_mingw
574 // parse a str like: 0, 2-4, 6
GetProcessorNumFromString(char * str)575 static int GetProcessorNumFromString(char *str)
576 {
577     int processorNum = 0;
578     int lastNum = -1;
579     char *s = str;
580     while (*s != '\0') {
581         if (isdigit(*s)) {
582             int currentNum = strtol(s, &s, 10);
583             if (lastNum == -1) {
584                 processorNum++;
585             } else {
586                 processorNum += currentNum - lastNum;
587             }
588             lastNum = currentNum;
589         } else {
590             if (*s == ',') {
591                 lastNum = -1;
592             }
593             s++;
594         }
595     }
596     return processorNum;
597 }
598 #endif
599 
GetProcessorNum()600 int GetProcessorNum()
601 {
602 #if defined(is_mingw) && is_mingw
603     return 0;
604 #else
605     FILE *fp = fopen("/sys/devices/system/cpu/online", "r");
606     if (fp == nullptr) {
607         HLOGE("/sys/devices/system/cpu/online not exist, use sysconf()");
608         return sysconf(_SC_NPROCESSORS_CONF);
609     }
610 
611     int processorNum = 0;
612     char *line = nullptr;
613     size_t len = 0;
614     if (getline(&line, &len, fp) != -1) {
615         processorNum = GetProcessorNumFromString(line);
616         free(line);
617     }
618     fclose(fp);
619 
620     if (processorNum <= 0) {
621         HLOGE("parse processor num fail, use sysconf()");
622         return sysconf(_SC_NPROCESSORS_CONF);
623     }
624     return processorNum;
625 #endif
626 }
627 
IsExistDebugByPid(const std::vector<pid_t> pids)628 bool IsExistDebugByPid(const std::vector<pid_t> pids)
629 {
630     if (pids.empty()) {
631         HLOGE("IsExistDebugByPid: pids is empty.");
632         return true;
633     }
634     for (auto pid : pids) {
635         if (pid <= 0) {
636             printf("Invalid -p value '%d', the pid should be larger than 0\n", pid);
637             return false;
638         }
639         std::string bundleName = GetProcessName(pid);
640         if (!IsRoot() && !IsDebugableApp(bundleName)) {
641             HLOGE("-p option only support debug aplication for %s", bundleName.c_str());
642             printf("-p option only support debug aplication\n");
643             return false;
644         }
645     }
646     return true;
647 }
648 
GetProcessName(int pid)649 std::string GetProcessName(int pid)
650 {
651 #if defined(is_ohos) && is_ohos
652     std::string filePath = "/proc/" + std::to_string(pid) + "/cmdline";
653     std::string bundleName = ReadFileToString(filePath);
654     return bundleName.substr(0, strlen(bundleName.c_str()));
655 #else
656     return "";
657 #endif
658 }
659 
IsDebugableApp(const std::string & bundleName)660 bool IsDebugableApp(const std::string& bundleName)
661 {
662 #if defined(is_ohos) && is_ohos
663     if (bundleName.empty()) {
664         printf("bundleName is empty!\n");
665         return false;
666     }
667     sptr<ISystemAbilityManager> sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
668     if (sam == nullptr) {
669         printf("GetSystemAbilityManager failed!\n");
670         return false;
671     }
672     sptr<IRemoteObject> remoteObject = sam->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
673     if (remoteObject == nullptr) {
674         printf("Get BundleMgr SA failed!\n");
675         return false;
676     }
677     sptr<BundleMgrProxy> proxy = iface_cast<BundleMgrProxy>(remoteObject);
678     if (proxy == nullptr) {
679         printf("iface_cast failed!\n");
680         return false;
681     }
682 
683     int uid = proxy->GetUidByDebugBundleName(bundleName, Constants::ANY_USERID);
684     if (uid < 0) {
685         HLOGE("Get application info failed, bundleName:%s, uid is %d.", bundleName.c_str(), uid);
686         return false;
687     }
688     return true;
689 #else
690     return false;
691 #endif
692 }
693 
694 } // namespace HiPerf
695 } // namespace Developtools
696 } // namespace OHOS
697 
698 // this will also used for libunwind head (out of namespace)
699 #if defined(is_mingw) && is_mingw
700 using namespace OHOS::Developtools::HiPerf;
GetLastErrorString()701 std::string GetLastErrorString()
702 {
703     LPVOID lpMsgBuf;
704     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
705                       FORMAT_MESSAGE_IGNORE_INSERTS,
706                   NULL, GetLastError(), 0, (LPTSTR)&lpMsgBuf, 0, NULL);
707     std::string error((LPTSTR)lpMsgBuf);
708     LocalFree(lpMsgBuf);
709     return error;
710 }
711 
mmap(void * addr,size_t length,int prot,int flags,int fd,size_t offset)712 void *mmap(void *addr, size_t length, int prot, int flags, int fd, size_t offset)
713 {
714     HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
715     if (FileHandle == INVALID_HANDLE_VALUE) {
716         return MMAP_FAILED;
717     }
718 
719     HLOGV("fd is %d", fd);
720 
721     HANDLE FileMappingHandle = ::CreateFileMappingW(FileHandle, 0, PAGE_READONLY, 0, 0, 0);
722     if (FileMappingHandle == nullptr) {
723         HLOGE("CreateFileMappingW %zu Failed with %ld:%s", length, GetLastError(),
724               GetLastErrorString().c_str());
725         return MMAP_FAILED;
726     }
727 
728     void *mapAddr = ::MapViewOfFile(FileMappingHandle, FILE_MAP_READ, 0, 0, 0);
729     if (mapAddr == nullptr) {
730         HLOGE("MapViewOfFile %zu Failed with %ld:%s", length, GetLastError(),
731               GetLastErrorString().c_str());
732         return MMAP_FAILED;
733     }
734 
735     // Close all the handles except for the view. It will keep the other handles
736     // alive.
737     ::CloseHandle(FileMappingHandle);
738     return mapAddr;
739 }
740 
munmap(void * addr,size_t)741 int munmap(void *addr, size_t)
742 {
743     /*
744         On success, munmap() returns 0.  On failure, it returns -1, and
745         errno is set to indicate the error (probably to EINVAL).
746 
747         UnmapViewOfFile function (memoryapi.h)
748 
749         If the function succeeds, the return value is nonzero.
750         If the function fails, the return value is zero. To get extended error information, call
751     GetLastError.
752     */
753     return !UnmapViewOfFile(addr);
754 }
755 #endif
756