• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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