• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 
16 #include "zip_file.h"
17 
18 #include <cassert>
19 #include <cstring>
20 #include <ostream>
21 
22 #include "file_path_utils.h"
23 #include "hilog_wrapper.h"
24 #include "securec.h"
25 #include "zlib.h"
26 
27 namespace OHOS {
28 namespace AbilityRuntime {
29 namespace {
30 constexpr uint32_t MAX_FILE_NAME = 256;
31 constexpr uint32_t UNZIP_BUFFER_SIZE = 1024;
32 constexpr uint32_t UNZIP_BUF_IN_LEN = 160 * UNZIP_BUFFER_SIZE;   // in  buffer length: 160KB
33 constexpr uint32_t UNZIP_BUF_OUT_LEN = 320 * UNZIP_BUFFER_SIZE;  // out buffer length: 320KB
34 constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50;
35 constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50;
36 constexpr uint32_t EOCD_SIGNATURE = 0x06054b50;
37 constexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50;
38 constexpr uint32_t FLAG_DATA_DESC = 0x8;
39 constexpr size_t FILE_READ_COUNT = 1;
40 constexpr uint8_t INFLATE_ERROR_TIMES = 5;
41 const char FILE_SEPARATOR_CHAR = '/';
42 constexpr char EXT_NAME_ABC[] = ".abc";
43 }  // namespace
44 
ZipEntry(const CentralDirEntry & centralEntry)45 ZipEntry::ZipEntry(const CentralDirEntry &centralEntry)
46 {
47     compressionMethod = centralEntry.compressionMethod;
48     uncompressedSize = centralEntry.uncompressedSize;
49     compressedSize = centralEntry.compressedSize;
50     localHeaderOffset = centralEntry.localHeaderOffset;
51     crc = centralEntry.crc;
52     flags = centralEntry.flags;
53 }
54 
ZipFile(const std::string & pathName)55 ZipFile::ZipFile(const std::string &pathName) : pathName_(pathName)
56 {}
57 
~ZipFile()58 ZipFile::~ZipFile()
59 {
60     Close();
61 }
62 
SetContentLocation(const ZipPos start,const size_t length)63 void ZipFile::SetContentLocation(const ZipPos start, const size_t length)
64 {
65     fileStartPos_ = start;
66     fileLength_ = length;
67 }
68 
CheckEndDir(const EndDir & endDir) const69 bool ZipFile::CheckEndDir(const EndDir &endDir) const
70 {
71     size_t lenEndDir = sizeof(EndDir);
72     if ((endDir.numDisk != 0) || (endDir.signature != EOCD_SIGNATURE) || (endDir.startDiskOfCentralDir != 0) ||
73         (endDir.offset >= fileLength_) || (endDir.totalEntriesInThisDisk != endDir.totalEntries) ||
74         (endDir.commentLen != 0) ||
75         // central dir can't overlap end of central dir
76         ((endDir.offset + endDir.sizeOfCentralDir + lenEndDir) > fileLength_)) {
77         HILOG_ERROR("end dir format error");
78         return false;
79     }
80     return true;
81 }
82 
ParseEndDirectory()83 bool ZipFile::ParseEndDirectory()
84 {
85     size_t endDirLen = sizeof(EndDir);
86     size_t endFilePos = fileStartPos_ + fileLength_;
87 
88     if (fileLength_ <= endDirLen) {
89         HILOG_ERROR("parse EOCD file length(%{public}llu) <= end dir length(%{public}llu)", fileStartPos_, fileLength_);
90         return false;
91     }
92 
93     size_t eocdPos = endFilePos - endDirLen;
94     if (fseek(file_, eocdPos, SEEK_SET) != 0) {
95         HILOG_ERROR("locate EOCD seek failed, error: %{public}d", errno);
96         return false;
97     }
98 
99     if (fread(&endDir_, sizeof(EndDir), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
100         HILOG_ERROR("read EOCD struct failed, error: %{public}d", errno);
101         return false;
102     }
103 
104     centralDirPos_ = endDir_.offset + fileStartPos_;
105 
106     return CheckEndDir(endDir_);
107 }
108 
ParseAllEntries()109 bool ZipFile::ParseAllEntries()
110 {
111     bool ret = true;
112     ZipPos currentPos = centralDirPos_;
113     CentralDirEntry directoryEntry = {0};
114     size_t fileLength = 0;
115 
116     for (uint16_t i = 0; i < endDir_.totalEntries; i++) {
117         std::string fileName;
118         fileName.reserve(MAX_FILE_NAME);
119         fileName.resize(MAX_FILE_NAME - 1);
120 
121         if (fseek(file_, currentPos, SEEK_SET) != 0) {
122             HILOG_ERROR("parse entry(%{public}d) seek zipEntry failed, error: %{public}d", i, errno);
123             ret = false;
124             break;
125         }
126 
127         if (fread(&directoryEntry, sizeof(CentralDirEntry), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
128             HILOG_ERROR("parse entry(%{public}d) read ZipEntry failed, error: %{public}d", i, errno);
129             ret = false;
130             break;
131         }
132 
133         if (directoryEntry.signature != CENTRAL_SIGNATURE) {
134             HILOG_ERROR("parse entry(%{public}d) check signature(0x%08x) at pos(0x%08llx) failed",
135                 i,
136                 directoryEntry.signature,
137                 currentPos);
138             ret = false;
139             break;
140         }
141 
142         fileLength = (directoryEntry.nameSize >= MAX_FILE_NAME) ? (MAX_FILE_NAME - 1) : directoryEntry.nameSize;
143         if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
144             HILOG_ERROR("parse entry(%{public}d) read file name failed, error: %{public}d", i, errno);
145             ret = false;
146             break;
147         }
148         fileName.resize(fileLength);
149 
150         if (isRuntime_ && !StringEndWith(fileName, EXT_NAME_ABC, sizeof(EXT_NAME_ABC) - 1)) {
151             currentPos += sizeof(directoryEntry);
152             currentPos += directoryEntry.nameSize + directoryEntry.extraSize + directoryEntry.commentSize;
153             continue;
154         }
155 
156         ZipEntry currentEntry(directoryEntry);
157         currentEntry.fileName = fileName;
158         entriesMap_[fileName] = currentEntry;
159 
160         currentPos += sizeof(directoryEntry);
161         currentPos += directoryEntry.nameSize + directoryEntry.extraSize + directoryEntry.commentSize;
162     }
163     return ret;
164 }
165 
Open()166 bool ZipFile::Open()
167 {
168     if (isOpen_) {
169         HILOG_ERROR("has already opened");
170         return true;
171     }
172 
173     if (pathName_.length() > PATH_MAX) {
174         HILOG_ERROR("path length(%{public}u) longer than max path length(%{public}d)",
175             static_cast<unsigned int>(pathName_.length()),
176             PATH_MAX);
177         return false;
178     }
179     std::string realPath;
180     realPath.reserve(PATH_MAX);
181     realPath.resize(PATH_MAX - 1);
182     if (realpath(pathName_.c_str(), &(realPath[0])) == nullptr) {
183         HILOG_ERROR("transform real path error: %{public}d", errno);
184         return false;
185     }
186 
187     FILE *tmpFile = fopen(realPath.c_str(), "rb");
188     if (tmpFile == nullptr) {
189         HILOG_ERROR("open file(%{private}s) failed, error: %{public}d", pathName_.c_str(), errno);
190         return false;
191     }
192 
193     if (fileLength_ == 0) {
194         if (fseek(tmpFile, 0, SEEK_END) != 0) {
195             HILOG_ERROR("file seek failed, error: %{public}d", errno);
196             fclose(tmpFile);
197             return false;
198         }
199         int64_t fileLength = ftell(tmpFile);
200         if (fileLength == -1) {
201             HILOG_ERROR("open file %{private}s failed", pathName_.c_str());
202             fclose(tmpFile);
203             return false;
204         }
205         fileLength_ = static_cast<ZipPos>(fileLength);
206         if (fileStartPos_ >= fileLength_) {
207             HILOG_ERROR("open start pos > length failed");
208             fclose(tmpFile);
209             return false;
210         }
211 
212         fileLength_ -= fileStartPos_;
213     }
214 
215     file_ = tmpFile;
216     bool result = ParseEndDirectory();
217     if (result) {
218         result = ParseAllEntries();
219     }
220     // it means open file success.
221     isOpen_ = true;
222     return result;
223 }
224 
Close()225 void ZipFile::Close()
226 {
227     if (!isOpen_ || file_ == nullptr) {
228         HILOG_WARN("file is not opened");
229         return;
230     }
231 
232     entriesMap_.clear();
233     pathName_ = "";
234     isOpen_ = false;
235 
236     if (fclose(file_) != 0) {
237         HILOG_WARN("close failed, error: %{public}d", errno);
238     }
239     file_ = nullptr;
240 }
241 
242 // Get all file zipEntry in this file
GetAllEntries() const243 const ZipEntryMap &ZipFile::GetAllEntries() const
244 {
245     return entriesMap_;
246 }
247 
HasEntry(const std::string & entryName) const248 bool ZipFile::HasEntry(const std::string &entryName) const
249 {
250     return entriesMap_.find(entryName) != entriesMap_.end();
251 }
252 
IsDirExist(const std::string & dir) const253 bool ZipFile::IsDirExist(const std::string &dir) const
254 {
255     if (dir.empty()) {
256         HILOG_ERROR("target dir is empty");
257         return false;
258     }
259 
260     auto tempDir = dir;
261     if (tempDir.back() != FILE_SEPARATOR_CHAR) {
262         tempDir.push_back(FILE_SEPARATOR_CHAR);
263     }
264 
265     for (const auto &item : entriesMap_) {
266         if (item.first.find(tempDir) == 0) {
267             return true;
268         }
269     }
270     HILOG_WARN("target dir not found, dir : %{private}s", dir.c_str());
271     return false;
272 }
273 
GetEntry(const std::string & entryName,ZipEntry & resultEntry) const274 bool ZipFile::GetEntry(const std::string &entryName, ZipEntry &resultEntry) const
275 {
276     auto iter = entriesMap_.find(entryName);
277     if (iter != entriesMap_.end()) {
278         resultEntry = iter->second;
279         return true;
280     }
281     HILOG_ERROR("get entry %{public}s failed", entryName.c_str());
282     return false;
283 }
284 
GetLocalHeaderSize(const uint16_t nameSize,const uint16_t extraSize) const285 size_t ZipFile::GetLocalHeaderSize(const uint16_t nameSize, const uint16_t extraSize) const
286 {
287     return sizeof(LocalHeader) + nameSize + extraSize;
288 }
289 
CheckDataDesc(const ZipEntry & zipEntry,const LocalHeader & localHeader) const290 bool ZipFile::CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const
291 {
292     uint32_t crcLocal = 0;
293     uint32_t compressedLocal = 0;
294     uint32_t uncompressedLocal = 0;
295 
296     if (localHeader.flags & FLAG_DATA_DESC) {  // use data desc
297         DataDesc dataDesc;
298         auto descPos = zipEntry.localHeaderOffset + GetLocalHeaderSize(localHeader.nameSize, localHeader.extraSize);
299         descPos += fileStartPos_ + zipEntry.compressedSize;
300 
301         if (fseek(file_, descPos, SEEK_SET) != 0) {
302             HILOG_ERROR("check local header seek datadesc failed, error: %{public}d", errno);
303             return false;
304         }
305 
306         if (fread(&dataDesc, sizeof(DataDesc), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
307             HILOG_ERROR("check local header read datadesc failed, error: %{public}d", errno);
308             return false;
309         }
310 
311         if (dataDesc.signature != DATA_DESC_SIGNATURE) {
312             HILOG_ERROR("check local header check datadesc signature failed");
313             return false;
314         }
315 
316         crcLocal = dataDesc.crc;
317         compressedLocal = dataDesc.compressedSize;
318         uncompressedLocal = dataDesc.uncompressedSize;
319     } else {
320         crcLocal = localHeader.crc;
321         compressedLocal = localHeader.compressedSize;
322         uncompressedLocal = localHeader.uncompressedSize;
323     }
324 
325     if ((zipEntry.crc != crcLocal) || (zipEntry.compressedSize != compressedLocal) ||
326         (zipEntry.uncompressedSize != uncompressedLocal)) {
327         HILOG_ERROR("check local header compressed size corrupted");
328         return false;
329     }
330 
331     return true;
332 }
333 
CheckCoherencyLocalHeader(const ZipEntry & zipEntry,uint16_t & extraSize) const334 bool ZipFile::CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const
335 {
336     LocalHeader localHeader = {0};
337 
338     if (zipEntry.localHeaderOffset >= fileLength_) {
339         HILOG_ERROR("check local file header offset is overflow %{public}d", zipEntry.localHeaderOffset);
340         return false;
341     }
342 
343     if (fseek(file_, fileStartPos_ + zipEntry.localHeaderOffset, SEEK_SET) != 0) {
344         HILOG_ERROR("check local header seek failed, error: %{public}d", errno);
345         return false;
346     }
347 
348     if (fread(&localHeader, sizeof(LocalHeader), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
349         HILOG_ERROR("check local header read localheader failed, error: %{public}d", errno);
350         return false;
351     }
352 
353     if ((localHeader.signature != LOCAL_HEADER_SIGNATURE) ||
354         (zipEntry.compressionMethod != localHeader.compressionMethod)) {
355         HILOG_ERROR("check local header signature or compressionMethod failed");
356         return false;
357     }
358 
359     // current only support store and Z_DEFLATED method
360     if ((zipEntry.compressionMethod != Z_DEFLATED) && (zipEntry.compressionMethod != 0)) {
361         HILOG_ERROR("check local header compressionMethod(%{public}d) not support", zipEntry.compressionMethod);
362         return false;
363     }
364 
365     std::string fileName;
366     fileName.reserve(MAX_FILE_NAME);
367     fileName.resize(MAX_FILE_NAME - 1);
368     size_t fileLength = (localHeader.nameSize >= MAX_FILE_NAME) ? (MAX_FILE_NAME - 1) : localHeader.nameSize;
369     if (fileLength != zipEntry.fileName.length()) {
370         HILOG_ERROR("check local header file name size failed");
371         return false;
372     }
373     if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
374         HILOG_ERROR("check local header read file name failed, error: %{public}d", errno);
375         return false;
376     }
377     fileName.resize(fileLength);
378     if (zipEntry.fileName != fileName) {
379         HILOG_ERROR("check local header file name corrupted");
380         return false;
381     }
382 
383     if (!CheckDataDesc(zipEntry, localHeader)) {
384         HILOG_ERROR("check data desc failed");
385         return false;
386     }
387 
388     extraSize = localHeader.extraSize;
389     return true;
390 }
391 
SeekToEntryStart(const ZipEntry & zipEntry,const uint16_t extraSize) const392 bool ZipFile::SeekToEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const
393 {
394     ZipPos startOffset = zipEntry.localHeaderOffset;
395     // get data offset, add signature+localheader+namesize+extrasize
396     startOffset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize);
397     if (startOffset + zipEntry.compressedSize > fileLength_) {
398         HILOG_ERROR("startOffset(%{public}lld)+entryCompressedSize(%{public}ud) > fileLength(%{public}llu)",
399             startOffset,
400             zipEntry.compressedSize,
401             fileLength_);
402         return false;
403     }
404     startOffset += fileStartPos_;  // add file start relative to file stream
405 
406     if (fseek(file_, startOffset, SEEK_SET) != 0) {
407         HILOG_ERROR("seek failed, error: %{public}d", errno);
408         return false;
409     }
410     return true;
411 }
412 
UnzipWithStore(const ZipEntry & zipEntry,const uint16_t extraSize,std::ostream & dest) const413 bool ZipFile::UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const
414 {
415     if (!SeekToEntryStart(zipEntry, extraSize)) {
416         HILOG_ERROR("seek to entry start failed");
417         return false;
418     }
419 
420     uint32_t remainSize = zipEntry.compressedSize;
421     std::string readBuffer;
422     readBuffer.reserve(UNZIP_BUF_OUT_LEN);
423     readBuffer.resize(UNZIP_BUF_OUT_LEN - 1);
424     while (remainSize > 0) {
425         size_t readBytes;
426         size_t readLen = (remainSize > UNZIP_BUF_OUT_LEN) ? UNZIP_BUF_OUT_LEN : remainSize;
427         readBytes = fread(&(readBuffer[0]), sizeof(Byte), readLen, file_);
428         if (readBytes != readLen) {
429             HILOG_ERROR("unzip store read failed, error: %{public}d", ferror(file_));
430             return false;
431         }
432         remainSize -= readBytes;
433         dest.write(&(readBuffer[0]), readBytes);
434     }
435 
436     return true;
437 }
438 
InitZStream(z_stream & zstream) const439 bool ZipFile::InitZStream(z_stream &zstream) const
440 {
441     // init zlib stream
442     if (memset_s(&zstream, sizeof(z_stream), 0, sizeof(z_stream))) {
443         HILOG_ERROR("unzip stream buffer init failed");
444         return false;
445     }
446     int32_t zlibErr = inflateInit2(&zstream, -MAX_WBITS);
447     if (zlibErr != Z_OK) {
448         HILOG_ERROR("unzip inflated init failed");
449         return false;
450     }
451 
452     BytePtr bufOut = new (std::nothrow) Byte[UNZIP_BUF_OUT_LEN];
453     if (bufOut == nullptr) {
454         HILOG_ERROR("unzip inflated new out buffer failed");
455         return false;
456     }
457 
458     BytePtr bufIn = new (std::nothrow) Byte[UNZIP_BUF_IN_LEN];
459     if (bufIn == nullptr) {
460         HILOG_ERROR("unzip inflated new in buffer failed");
461         delete[] bufOut;
462         return false;
463     }
464     zstream.next_out = bufOut;
465     zstream.next_in = bufIn;
466     zstream.avail_out = UNZIP_BUF_OUT_LEN;
467     return true;
468 }
469 
ReadZStream(const BytePtr & buffer,z_stream & zstream,uint32_t & remainCompressedSize) const470 bool ZipFile::ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize) const
471 {
472     if (zstream.avail_in == 0) {
473         size_t readBytes;
474         size_t remainBytes = (remainCompressedSize > UNZIP_BUF_IN_LEN) ? UNZIP_BUF_IN_LEN : remainCompressedSize;
475         readBytes = fread(buffer, sizeof(Byte), remainBytes, file_);
476         if (readBytes != remainBytes) {
477             HILOG_ERROR("unzip inflated read failed, error: %{public}d", ferror(file_));
478             return false;
479         }
480 
481         remainCompressedSize -= readBytes;
482         zstream.avail_in = readBytes;
483         zstream.next_in = buffer;
484     }
485     return true;
486 }
487 
UnzipWithInflated(const ZipEntry & zipEntry,const uint16_t extraSize,std::ostream & dest) const488 bool ZipFile::UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const
489 {
490     z_stream zstream;
491     if (!SeekToEntryStart(zipEntry, extraSize) || !InitZStream(zstream)) {
492         return false;
493     }
494 
495     BytePtr bufIn = zstream.next_in;
496     BytePtr bufOut = zstream.next_out;
497 
498     bool ret = true;
499     int32_t zlibErr = Z_OK;
500     uint32_t remainCompressedSize = zipEntry.compressedSize;
501     size_t inflateLen = 0;
502     uint8_t errorTimes = 0;
503     while ((remainCompressedSize > 0) || (zstream.avail_in > 0)) {
504         if (!ReadZStream(bufIn, zstream, remainCompressedSize)) {
505             ret = false;
506             break;
507         }
508 
509         zlibErr = inflate(&zstream, Z_SYNC_FLUSH);
510         if ((zlibErr >= Z_OK) && (zstream.msg != nullptr)) {
511             HILOG_ERROR("unzip inflated inflate, error: %{public}d, err msg: %{public}s", zlibErr, zstream.msg);
512             ret = false;
513             break;
514         }
515 
516         inflateLen = UNZIP_BUF_OUT_LEN - zstream.avail_out;
517         if (inflateLen > 0) {
518             dest.write((const char *)bufOut, inflateLen);
519             zstream.next_out = bufOut;
520             zstream.avail_out = UNZIP_BUF_OUT_LEN;
521             errorTimes = 0;
522         } else {
523             errorTimes++;
524         }
525         if (errorTimes >= INFLATE_ERROR_TIMES) {
526             HILOG_ERROR("unzip inflated data is abnormal!");
527             ret = false;
528             break;
529         }
530     }
531 
532     // free all dynamically allocated data structures except the next_in and next_out for this stream.
533     zlibErr = inflateEnd(&zstream);
534     if (zlibErr != Z_OK) {
535         HILOG_ERROR("unzip inflateEnd error, error: %{public}d", zlibErr);
536         ret = false;
537     }
538 
539     delete[] bufOut;
540     delete[] bufIn;
541     return ret;
542 }
543 
GetEntryDataOffset(const ZipEntry & zipEntry,const uint16_t extraSize) const544 ZipPos ZipFile::GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const
545 {
546     // get entry data offset relative file
547     ZipPos offset = zipEntry.localHeaderOffset;
548 
549     offset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize);
550     offset += fileStartPos_;
551 
552     return offset;
553 }
554 
GetDataOffsetRelative(const std::string & file,ZipPos & offset,uint32_t & length) const555 bool ZipFile::GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const
556 {
557     ZipEntry zipEntry;
558     if (!GetEntry(file, zipEntry)) {
559         HILOG_ERROR("extract file: not find file");
560         return false;
561     }
562 
563     uint16_t extraSize = 0;
564     if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) {
565         HILOG_ERROR("check coherency local header failed");
566         return false;
567     }
568 
569     offset = GetEntryDataOffset(zipEntry, extraSize);
570     length = zipEntry.compressedSize;
571     return true;
572 }
573 
ExtractFile(const std::string & file,std::ostream & dest) const574 bool ZipFile::ExtractFile(const std::string &file, std::ostream &dest) const
575 {
576     ZipEntry zipEntry;
577     if (!GetEntry(file, zipEntry)) {
578         HILOG_ERROR("extract file: not find file");
579         return false;
580     }
581 
582     uint16_t extraSize = 0;
583     if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) {
584         HILOG_ERROR("check coherency local header failed");
585         return false;
586     }
587 
588     bool ret = true;
589     if (zipEntry.compressionMethod == 0) {
590         ret = UnzipWithStore(zipEntry, extraSize, dest);
591     } else {
592         ret = UnzipWithInflated(zipEntry, extraSize, dest);
593     }
594 
595     return ret;
596 }
597 
SetIsRuntime(const bool isRuntime)598 void ZipFile::SetIsRuntime(const bool isRuntime)
599 {
600     isRuntime_ = isRuntime;
601 }
602 }  // namespace AbilityRuntime
603 }  // namespace OHOS
604