1bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe/*
2bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe * Copyright (C) 2016 The Android Open Source Project
3bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe *
4bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe * Licensed under the Apache License, Version 2.0 (the "License");
5bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe * you may not use this file except in compliance with the License.
6bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe * You may obtain a copy of the License at
7bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe *
8bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe *      http://www.apache.org/licenses/LICENSE-2.0
9bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe *
10bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe * Unless required by applicable law or agreed to in writing, software
11bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe * distributed under the License is distributed on an "AS IS" BASIS,
12bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe * See the License for the specific language governing permissions and
14bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe * limitations under the License.
15bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe */
16bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
17bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#ifndef ART_RUNTIME_GC_SPACE_IMAGE_SPACE_FS_H_
18bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#define ART_RUNTIME_GC_SPACE_IMAGE_SPACE_FS_H_
19bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
20bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#include <dirent.h>
21bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#include <dlfcn.h>
22bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
23bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#include "base/logging.h"
24bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#include "base/macros.h"
25bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#include "base/stringprintf.h"
26bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#include "base/unix_file/fd_file.h"
27bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#include "globals.h"
28bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#include "os.h"
29a1425a1c9c98ae3fc772834933a5d55566fb5699Andreas Gampe#include "runtime.h"
30bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#include "utils.h"
31bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
32bec635813789a7365900d3db01c16e12a20c2815Andreas Gampenamespace art {
33bec635813789a7365900d3db01c16e12a20c2815Andreas Gampenamespace gc {
34bec635813789a7365900d3db01c16e12a20c2815Andreas Gampenamespace space {
35bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
36bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// This file contains helper code for ImageSpace. It has most of the file-system
37bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// related code, including handling A/B OTA.
38bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
39bec635813789a7365900d3db01c16e12a20c2815Andreas Gampenamespace impl {
40bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
41bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// Delete the directory and its (regular or link) contents. If the recurse flag is true, delete
42bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// sub-directories recursively.
43bec635813789a7365900d3db01c16e12a20c2815Andreas Gampestatic void DeleteDirectoryContents(const std::string& dir, bool recurse) {
44bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  if (!OS::DirectoryExists(dir.c_str())) {
45bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    return;
46bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  }
47bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  DIR* c_dir = opendir(dir.c_str());
48bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  if (c_dir == nullptr) {
49bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    PLOG(WARNING) << "Unable to open " << dir << " to delete it's contents";
50bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    return;
51bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  }
52bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
53bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  for (struct dirent* de = readdir(c_dir); de != nullptr; de = readdir(c_dir)) {
54bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    const char* name = de->d_name;
55bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
56bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      continue;
57bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    }
58bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    // We only want to delete regular files and symbolic links.
59bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    std::string file = StringPrintf("%s/%s", dir.c_str(), name);
60bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    if (de->d_type != DT_REG && de->d_type != DT_LNK) {
61bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      if (de->d_type == DT_DIR) {
62bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe        if (recurse) {
63bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe          DeleteDirectoryContents(file, recurse);
64bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe          // Try to rmdir the directory.
6566fdcbdb1fde4bf65da5e801ba76a8e65391635bVladimir Marko          if (rmdir(file.c_str()) != 0) {
66bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe            PLOG(ERROR) << "Unable to rmdir " << file;
67bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe          }
68bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe        }
69bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      } else {
70bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe        LOG(WARNING) << "Unexpected file type of " << std::hex << de->d_type << " encountered.";
71bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      }
72bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    } else {
73bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      // Try to unlink the file.
7466fdcbdb1fde4bf65da5e801ba76a8e65391635bVladimir Marko      if (unlink(file.c_str()) != 0) {
75bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe        PLOG(ERROR) << "Unable to unlink " << file;
76bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      }
77bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    }
78bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  }
7966fdcbdb1fde4bf65da5e801ba76a8e65391635bVladimir Marko  CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory.";
80bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe}
81bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
82bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe}  // namespace impl
83bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
84bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
85bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// We are relocating or generating the core image. We should get rid of everything. It is all
86bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// out-of-date. We also don't really care if this fails since it is just a convenience.
87bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// Adapted from prune_dex_cache(const char* subdir) in frameworks/native/cmds/installd/commands.c
88bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// Note this should only be used during first boot.
89bec635813789a7365900d3db01c16e12a20c2815Andreas Gampestatic void PruneDalvikCache(InstructionSet isa) {
90bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  CHECK_NE(isa, kNone);
91bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  // Prune the base /data/dalvik-cache.
92bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  impl::DeleteDirectoryContents(GetDalvikCacheOrDie(".", false), false);
93bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  // Prune /data/dalvik-cache/<isa>.
94bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  impl::DeleteDirectoryContents(GetDalvikCacheOrDie(GetInstructionSetString(isa), false), false);
95a1425a1c9c98ae3fc772834933a5d55566fb5699Andreas Gampe
96a1425a1c9c98ae3fc772834933a5d55566fb5699Andreas Gampe  // Be defensive. There should be a runtime created here, but this may be called in a test.
97a1425a1c9c98ae3fc772834933a5d55566fb5699Andreas Gampe  if (Runtime::Current() != nullptr) {
98a1425a1c9c98ae3fc772834933a5d55566fb5699Andreas Gampe    Runtime::Current()->SetPrunedDalvikCache(true);
99a1425a1c9c98ae3fc772834933a5d55566fb5699Andreas Gampe  }
100bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe}
101bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
102bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// We write out an empty file to the zygote's ISA specific cache dir at the start of
103bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// every zygote boot and delete it when the boot completes. If we find a file already
104bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// present, it usually means the boot didn't complete. We wipe the entire dalvik
105bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe// cache if that's the case.
106bec635813789a7365900d3db01c16e12a20c2815Andreas Gampestatic void MarkZygoteStart(const InstructionSet isa, const uint32_t max_failed_boots) {
107bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  const std::string isa_subdir = GetDalvikCacheOrDie(GetInstructionSetString(isa), false);
108bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  const std::string boot_marker = isa_subdir + "/.booting";
109bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  const char* file_name = boot_marker.c_str();
110bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
111bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  uint32_t num_failed_boots = 0;
112bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  std::unique_ptr<File> file(OS::OpenFileReadWrite(file_name));
113bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  if (file.get() == nullptr) {
114bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    file.reset(OS::CreateEmptyFile(file_name));
115bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
116bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    if (file.get() == nullptr) {
117f242f66cf7137ef681e44a494758976e11579260Andreas Gampe      int saved_errno = errno;
118bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      PLOG(WARNING) << "Failed to create boot marker.";
119f242f66cf7137ef681e44a494758976e11579260Andreas Gampe      if (saved_errno != ENOSPC) {
120f242f66cf7137ef681e44a494758976e11579260Andreas Gampe        return;
121f242f66cf7137ef681e44a494758976e11579260Andreas Gampe      }
122f242f66cf7137ef681e44a494758976e11579260Andreas Gampe
123f242f66cf7137ef681e44a494758976e11579260Andreas Gampe      LOG(WARNING) << "Pruning dalvik cache because of low-memory situation.";
124f242f66cf7137ef681e44a494758976e11579260Andreas Gampe      impl::DeleteDirectoryContents(isa_subdir, false);
125f242f66cf7137ef681e44a494758976e11579260Andreas Gampe
126f242f66cf7137ef681e44a494758976e11579260Andreas Gampe      // Try once more.
127f242f66cf7137ef681e44a494758976e11579260Andreas Gampe      file.reset(OS::OpenFileReadWrite(file_name));
128f242f66cf7137ef681e44a494758976e11579260Andreas Gampe      if (file == nullptr) {
129f242f66cf7137ef681e44a494758976e11579260Andreas Gampe        PLOG(WARNING) << "Failed to create boot marker.";
130f242f66cf7137ef681e44a494758976e11579260Andreas Gampe        return;
131f242f66cf7137ef681e44a494758976e11579260Andreas Gampe      }
132bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    }
133bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  } else {
134bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    if (!file->ReadFully(&num_failed_boots, sizeof(num_failed_boots))) {
135bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      PLOG(WARNING) << "Failed to read boot marker.";
136bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      file->Erase();
137bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe      return;
138bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    }
139bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  }
140bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
141bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  if (max_failed_boots != 0 && num_failed_boots > max_failed_boots) {
142bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    LOG(WARNING) << "Incomplete boot detected. Pruning dalvik cache";
143bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    impl::DeleteDirectoryContents(isa_subdir, false);
144bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  }
145bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
146bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  ++num_failed_boots;
147bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  VLOG(startup) << "Number of failed boots on : " << boot_marker << " = " << num_failed_boots;
148bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
149bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  if (lseek(file->Fd(), 0, SEEK_SET) == -1) {
150bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    PLOG(WARNING) << "Failed to write boot marker.";
151bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    file->Erase();
152bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    return;
153bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  }
154bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
155bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  if (!file->WriteFully(&num_failed_boots, sizeof(num_failed_boots))) {
156bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    PLOG(WARNING) << "Failed to write boot marker.";
157bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    file->Erase();
158bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    return;
159bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  }
160bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
161bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  if (file->FlushCloseOrErase() != 0) {
162bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe    PLOG(WARNING) << "Failed to flush boot marker.";
163bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe  }
164bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe}
165bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
166bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe}  // namespace space
167bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe}  // namespace gc
168bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe}  // namespace art
169bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe
170bec635813789a7365900d3db01c16e12a20c2815Andreas Gampe#endif  // ART_RUNTIME_GC_SPACE_IMAGE_SPACE_FS_H_
171