1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "startup_completed_task.h"
18 
19 #include "base/systrace.h"
20 #include "class_linker.h"
21 #include "gc/heap.h"
22 #include "gc/scoped_gc_critical_section.h"
23 #include "gc/space/image_space.h"
24 #include "gc/space/space-inl.h"
25 #include "handle_scope-inl.h"
26 #include "linear_alloc-inl.h"
27 #include "mirror/dex_cache.h"
28 #include "mirror/object-inl.h"
29 #include "obj_ptr.h"
30 #include "runtime_image.h"
31 #include "scoped_thread_state_change-inl.h"
32 #include "thread.h"
33 #include "thread_list.h"
34 
35 namespace art HIDDEN {
36 
37 class UnlinkStartupDexCacheVisitor : public DexCacheVisitor {
38  public:
UnlinkStartupDexCacheVisitor()39   UnlinkStartupDexCacheVisitor() {}
40 
Visit(ObjPtr<mirror::DexCache> dex_cache)41   void Visit(ObjPtr<mirror::DexCache> dex_cache)
42       REQUIRES_SHARED(Locks::dex_lock_, Locks::mutator_lock_) override {
43     dex_cache->UnlinkStartupCaches();
44   }
45 };
46 
Run(Thread * self)47 void StartupCompletedTask::Run(Thread* self) {
48   Runtime* const runtime = Runtime::Current();
49   if (runtime->NotifyStartupCompleted()) {
50     // Maybe generate a runtime app image. If the runtime is debuggable, boot
51     // classpath classes can be dynamically changed, so don't bother generating an
52     // image.
53     if (!runtime->IsJavaDebuggable()) {
54       std::string compiler_filter;
55       std::string compilation_reason;
56       std::string primary_apk_path = runtime->GetAppInfo()->GetPrimaryApkPath();
57       runtime->GetAppInfo()->GetPrimaryApkOptimizationStatus(&compiler_filter, &compilation_reason);
58       CompilerFilter::Filter filter;
59       if (CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter) &&
60           !CompilerFilter::IsAotCompilationEnabled(filter) &&
61           !runtime->GetHeap()->HasAppImageSpaceFor(primary_apk_path)) {
62         std::string error_msg;
63         if (!RuntimeImage::WriteImageToDisk(&error_msg)) {
64           LOG(DEBUG) << "Could not write temporary image to disk " << error_msg;
65         }
66       }
67     }
68 
69     ScopedObjectAccess soa(self);
70     DeleteStartupDexCaches(self, /* called_by_gc= */ false);
71   }
72 
73   // Delete the thread pool used for app image loading since startup is assumed to be completed.
74   ScopedTrace trace2("Delete thread pool");
75   Runtime::Current()->DeleteThreadPool();
76 }
77 
DeleteStartupDexCaches(Thread * self,bool called_by_gc)78 void StartupCompletedTask::DeleteStartupDexCaches(Thread* self, bool called_by_gc) {
79   VLOG(startup) << "StartupCompletedTask running";
80   Runtime* const runtime = Runtime::Current();
81 
82   ScopedTrace trace("Releasing dex caches and app image spaces metadata");
83 
84   static struct EmptyClosure : Closure {
85     void Run([[maybe_unused]] Thread* thread) override {}
86   } closure;
87 
88   // Fetch the startup linear alloc so no other thread tries to allocate there.
89   std::unique_ptr<LinearAlloc> startup_linear_alloc(runtime->ReleaseStartupLinearAlloc());
90   // No thread could be allocating arrays or accessing dex caches when this
91   // thread has mutator-lock held exclusively.
92   bool run_checkpoints = !Locks::mutator_lock_->IsExclusiveHeld(self);
93 
94   // Request a checkpoint to make sure all threads see we have started up and
95   // won't allocate in the startup linear alloc. Without this checkpoint what
96   // could happen is (T0 == self):
97   // 1) T1 fetches startup alloc, allocates an array there.
98   // 2) T0 goes over the dex caches, clear dex cache arrays in the startup alloc.
99   // 3) T1 sets the dex cache array from startup alloc in a dex cache.
100   // 4) T0 releases startup alloc.
101   //
102   // With this checkpoint, 3) cannot happen as T0 waits for T1 to reach the
103   // checkpoint.
104   if (run_checkpoints) {
105     runtime->GetThreadList()->RunCheckpoint(&closure);
106   }
107 
108   {
109     UnlinkStartupDexCacheVisitor visitor;
110     ReaderMutexLock mu(self, *Locks::dex_lock_);
111     runtime->GetClassLinker()->VisitDexCaches(&visitor);
112   }
113 
114 
115   // Request a checkpoint to make sure no threads are:
116   // - accessing the image space metadata section when we madvise it
117   // - accessing dex caches when we free them
118   if (run_checkpoints) {
119     runtime->GetThreadList()->RunCheckpoint(&closure);
120   }
121 
122   // If this isn't the GC calling `DeleteStartupDexCaches` and a GC may be
123   // running, wait for it to be complete. We don't want it to see these dex
124   // caches.
125   if (!called_by_gc) {
126     runtime->GetHeap()->WaitForGcToComplete(gc::kGcCauseDeletingDexCacheArrays, self);
127   }
128 
129   // At this point, we know no other thread can see the arrays, nor the GC. So
130   // we can safely release them.
131   for (gc::space::ContinuousSpace* space : runtime->GetHeap()->GetContinuousSpaces()) {
132     if (space->IsImageSpace()) {
133       gc::space::ImageSpace* image_space = space->AsImageSpace();
134       if (image_space->GetImageHeader().IsAppImage()) {
135         image_space->ReleaseMetadata();
136       }
137     }
138   }
139 
140   if (startup_linear_alloc != nullptr) {
141     ScopedTrace trace2("Delete startup linear alloc");
142     ArenaPool* arena_pool = startup_linear_alloc->GetArenaPool();
143     startup_linear_alloc.reset();
144     arena_pool->TrimMaps();
145   }
146 }
147 
148 }  // namespace art
149