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