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