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 {
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 runtime->GetAppInfo()->GetPrimaryApkOptimizationStatus(&compiler_filter, &compilation_reason);
57 CompilerFilter::Filter filter;
58 if (CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter) &&
59 !CompilerFilter::IsAotCompilationEnabled(filter)) {
60 std::string error_msg;
61 if (!RuntimeImage::WriteImageToDisk(&error_msg)) {
62 LOG(DEBUG) << "Could not write temporary image to disk " << error_msg;
63 }
64 }
65 }
66
67 ScopedObjectAccess soa(self);
68 DeleteStartupDexCaches(self, /* called_by_gc= */ false);
69 }
70
71 // Delete the thread pool used for app image loading since startup is assumed to be completed.
72 ScopedTrace trace2("Delete thread pool");
73 Runtime::Current()->DeleteThreadPool();
74 }
75
DeleteStartupDexCaches(Thread * self,bool called_by_gc)76 void StartupCompletedTask::DeleteStartupDexCaches(Thread* self, bool called_by_gc) {
77 VLOG(startup) << "StartupCompletedTask running";
78 Runtime* const runtime = Runtime::Current();
79
80 ScopedTrace trace("Releasing dex caches and app image spaces metadata");
81
82 static struct EmptyClosure : Closure {
83 void Run([[maybe_unused]] Thread* thread) override {}
84 } closure;
85
86 // Fetch the startup linear alloc so no other thread tries to allocate there.
87 std::unique_ptr<LinearAlloc> startup_linear_alloc(runtime->ReleaseStartupLinearAlloc());
88 // No thread could be allocating arrays or accessing dex caches when this
89 // thread has mutator-lock held exclusively.
90 bool run_checkpoints = !Locks::mutator_lock_->IsExclusiveHeld(self);
91
92 // Request a checkpoint to make sure all threads see we have started up and
93 // won't allocate in the startup linear alloc. Without this checkpoint what
94 // could happen is (T0 == self):
95 // 1) T1 fetches startup alloc, allocates an array there.
96 // 2) T0 goes over the dex caches, clear dex cache arrays in the startup alloc.
97 // 3) T1 sets the dex cache array from startup alloc in a dex cache.
98 // 4) T0 releases startup alloc.
99 //
100 // With this checkpoint, 3) cannot happen as T0 waits for T1 to reach the
101 // checkpoint.
102 if (run_checkpoints) {
103 runtime->GetThreadList()->RunCheckpoint(&closure);
104 }
105
106 {
107 UnlinkStartupDexCacheVisitor visitor;
108 ReaderMutexLock mu(self, *Locks::dex_lock_);
109 runtime->GetClassLinker()->VisitDexCaches(&visitor);
110 }
111
112
113 // Request a checkpoint to make sure no threads are:
114 // - accessing the image space metadata section when we madvise it
115 // - accessing dex caches when we free them
116 if (run_checkpoints) {
117 runtime->GetThreadList()->RunCheckpoint(&closure);
118 }
119
120 // If this isn't the GC calling `DeleteStartupDexCaches` and a GC may be
121 // running, wait for it to be complete. We don't want it to see these dex
122 // caches.
123 if (!called_by_gc) {
124 runtime->GetHeap()->WaitForGcToComplete(gc::kGcCauseDeletingDexCacheArrays, self);
125 }
126
127 // At this point, we know no other thread can see the arrays, nor the GC. So
128 // we can safely release them.
129 for (gc::space::ContinuousSpace* space : runtime->GetHeap()->GetContinuousSpaces()) {
130 if (space->IsImageSpace()) {
131 gc::space::ImageSpace* image_space = space->AsImageSpace();
132 if (image_space->GetImageHeader().IsAppImage()) {
133 image_space->ReleaseMetadata();
134 }
135 }
136 }
137
138 if (startup_linear_alloc != nullptr) {
139 ScopedTrace trace2("Delete startup linear alloc");
140 ArenaPool* arena_pool = startup_linear_alloc->GetArenaPool();
141 startup_linear_alloc.reset();
142 arena_pool->TrimMaps();
143 }
144 }
145
146 } // namespace art
147