1 /*
2  * Copyright (C) 2020 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 <fcntl.h>
18 #include <filesystem>
19 #include <fstream>
20 #include <iomanip>
21 #include <iostream>
22 #include <iterator>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include <android-base/file.h>
28 #include <android-base/logging.h>
29 #include <android-base/properties.h>
30 #include <android-base/scopeguard.h>
31 #include <logwrap/logwrap.h>
32 #include <odrefresh/odrefresh.h>
33 
34 #include "CertUtils.h"
35 #include "KeystoreKey.h"
36 #include "StatsReporter.h"
37 #include "VerityUtils.h"
38 #include "statslog_odsign.h"
39 
40 #include "odsign_info.pb.h"
41 
42 using android::base::ErrnoError;
43 using android::base::Error;
44 using android::base::Result;
45 using android::base::SetProperty;
46 
47 using OdsignInfo = ::odsign::proto::OdsignInfo;
48 
49 // Keystore boot level that the odsign key uses
50 const int kKeyBootLevel = 30;
51 const std::string kPublicKeySignature = "/data/misc/odsign/publickey.signature";
52 const android::String16 kKeyAlias{"ondevice-signing"};
53 constexpr int kKeyNspace = 101;  // odsign_key
54 
55 const std::string kSigningKeyCert = "/data/misc/odsign/key.cert";
56 const std::string kOdsignInfo = "/data/misc/odsign/odsign.info";
57 const std::string kOdsignInfoSignature = "/data/misc/odsign/odsign.info.signature";
58 
59 const std::string kArtArtifactsDir = "/data/misc/apexdata/com.android.art/dalvik-cache";
60 
61 constexpr const char* kOdrefreshPath = "/apex/com.android.art/bin/odrefresh";
62 constexpr const char* kCompOsVerifyPath = "/apex/com.android.compos/bin/compos_verify";
63 
64 constexpr bool kForceCompilation = false;
65 constexpr bool kUseCompOs = true;
66 
67 const std::string kCompOsPendingArtifactsDir = "/data/misc/apexdata/com.android.art/compos-pending";
68 const std::string kCompOsInfo = kArtArtifactsDir + "/compos.info";
69 const std::string kCompOsInfoSignature = kCompOsInfo + ".signature";
70 
71 constexpr const char* kCompOsPendingInfoPath =
72     "/data/misc/apexdata/com.android.art/compos-pending/compos.info";
73 constexpr const char* kCompOsPendingInfoSignaturePath =
74     "/data/misc/apexdata/com.android.art/compos-pending/compos.info.signature";
75 
76 constexpr const char* kOdsignVerificationDoneProp = "odsign.verification.done";
77 constexpr const char* kOdsignKeyDoneProp = "odsign.key.done";
78 
79 constexpr const char* kOdsignVerificationStatusProp = "odsign.verification.success";
80 constexpr const char* kOdsignVerificationStatusValid = "1";
81 constexpr const char* kOdsignVerificationStatusError = "0";
82 
83 constexpr const char* kStopServiceProp = "ctl.stop";
84 
85 enum class CompOsInstance { kCurrent, kPending };
86 
87 namespace {
88 
rename(const std::string & from,const std::string & to)89 bool rename(const std::string& from, const std::string& to) {
90     std::error_code ec;
91     std::filesystem::rename(from, to, ec);
92     if (ec) {
93         LOG(ERROR) << "Can't rename " << from << " to " << to << ": " << ec.message();
94         return false;
95     }
96     return true;
97 }
98 
removeDirectory(const std::string & directory)99 int removeDirectory(const std::string& directory) {
100     std::error_code ec;
101     auto num_removed = std::filesystem::remove_all(directory, ec);
102     if (ec) {
103         LOG(ERROR) << "Can't remove " << directory << ": " << ec.message();
104         return 0;
105     } else {
106         if (num_removed > 0) {
107             LOG(INFO) << "Removed " << num_removed << " entries from " << directory;
108         }
109         return num_removed;
110     }
111 }
112 
directoryHasContent(const std::string & directory)113 bool directoryHasContent(const std::string& directory) {
114     std::error_code ec;
115     return std::filesystem::is_directory(directory, ec) &&
116            !std::filesystem::is_empty(directory, ec);
117 }
118 
compileArtifacts(bool force)119 art::odrefresh::ExitCode compileArtifacts(bool force) {
120     const char* const argv[] = {kOdrefreshPath, force ? "--force-compile" : "--compile"};
121     const int exit_code =
122         logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
123     return static_cast<art::odrefresh::ExitCode>(exit_code);
124 }
125 
checkArtifacts()126 art::odrefresh::ExitCode checkArtifacts() {
127     const char* const argv[] = {kOdrefreshPath, "--check"};
128     const int exit_code =
129         logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
130     return static_cast<art::odrefresh::ExitCode>(exit_code);
131 }
132 
toHex(const std::vector<uint8_t> & digest)133 std::string toHex(const std::vector<uint8_t>& digest) {
134     std::stringstream ss;
135     for (auto it = digest.begin(); it != digest.end(); ++it) {
136         ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned>(*it);
137     }
138     return ss.str();
139 }
140 
compOsPresent()141 bool compOsPresent() {
142     // We must have the CompOS APEX
143     return access(kCompOsVerifyPath, X_OK) == 0;
144 }
145 
verifyExistingRootCert(const SigningKey & key)146 Result<void> verifyExistingRootCert(const SigningKey& key) {
147     if (access(kSigningKeyCert.c_str(), F_OK) < 0) {
148         return ErrnoError() << "Key certificate not found: " << kSigningKeyCert;
149     }
150     auto trustedPublicKey = key.getPublicKey();
151     if (!trustedPublicKey.ok()) {
152         return Error() << "Failed to retrieve signing public key: " << trustedPublicKey.error();
153     }
154 
155     auto publicKeyFromExistingCert = extractPublicKeyFromX509(kSigningKeyCert);
156     if (!publicKeyFromExistingCert.ok()) {
157         return publicKeyFromExistingCert.error();
158     }
159     if (publicKeyFromExistingCert.value() != trustedPublicKey.value()) {
160         return Error() << "Public key of existing certificate at " << kSigningKeyCert
161                        << " does not match signing public key.";
162     }
163 
164     // At this point, we know the cert is for our key; it's unimportant whether it's
165     // actually self-signed.
166     return {};
167 }
168 
createX509RootCert(const SigningKey & key,const std::string & outPath)169 Result<void> createX509RootCert(const SigningKey& key, const std::string& outPath) {
170     auto publicKey = key.getPublicKey();
171 
172     if (!publicKey.ok()) {
173         return publicKey.error();
174     }
175 
176     auto keySignFunction = [&](const std::string& to_be_signed) { return key.sign(to_be_signed); };
177     return createSelfSignedCertificate(*publicKey, keySignFunction, outPath);
178 }
179 
computeDigests(const std::string & path)180 Result<std::map<std::string, std::string>> computeDigests(const std::string& path) {
181     std::error_code ec;
182     std::map<std::string, std::string> digests;
183 
184     auto it = std::filesystem::recursive_directory_iterator(path, ec);
185     auto end = std::filesystem::recursive_directory_iterator();
186 
187     while (!ec && it != end) {
188         if (it->is_regular_file()) {
189             auto digest = createDigest(it->path());
190             if (!digest.ok()) {
191                 return Error() << "Failed to compute digest for " << it->path() << ": "
192                                << digest.error();
193             }
194             digests[it->path()] = toHex(*digest);
195         }
196         ++it;
197     }
198     if (ec) {
199         return Error() << "Failed to iterate " << path << ": " << ec;
200     }
201 
202     return digests;
203 }
204 
verifyDigests(const std::map<std::string,std::string> & digests,const std::map<std::string,std::string> & trusted_digests)205 Result<void> verifyDigests(const std::map<std::string, std::string>& digests,
206                            const std::map<std::string, std::string>& trusted_digests) {
207     for (const auto& path_digest : digests) {
208         auto path = path_digest.first;
209         auto digest = path_digest.second;
210         if (trusted_digests.count(path) == 0) {
211             return Error() << "Couldn't find digest for " << path;
212         }
213         if (trusted_digests.at(path) != digest) {
214             return Error() << "Digest mismatch for " << path;
215         }
216     }
217 
218     // All digests matched!
219     if (digests.size() > 0) {
220         LOG(INFO) << "All root hashes match.";
221     }
222     return {};
223 }
224 
verifyIntegrityFsVerity(const std::map<std::string,std::string> & trusted_digests)225 Result<void> verifyIntegrityFsVerity(const std::map<std::string, std::string>& trusted_digests) {
226     // Just verify that the files are in verity, and get their digests
227     auto result = verifyAllFilesInVerity(kArtArtifactsDir);
228     if (!result.ok()) {
229         return result.error();
230     }
231 
232     return verifyDigests(*result, trusted_digests);
233 }
234 
verifyIntegrityNoFsVerity(const std::map<std::string,std::string> & trusted_digests)235 Result<void> verifyIntegrityNoFsVerity(const std::map<std::string, std::string>& trusted_digests) {
236     // On these devices, just compute the digests, and verify they match the ones we trust
237     auto result = computeDigests(kArtArtifactsDir);
238     if (!result.ok()) {
239         return result.error();
240     }
241 
242     return verifyDigests(*result, trusted_digests);
243 }
244 
getAndVerifyOdsignInfo(const SigningKey & key)245 Result<OdsignInfo> getAndVerifyOdsignInfo(const SigningKey& key) {
246     std::string persistedSignature;
247     OdsignInfo odsignInfo;
248 
249     if (!android::base::ReadFileToString(kOdsignInfoSignature, &persistedSignature)) {
250         return ErrnoError() << "Failed to read " << kOdsignInfoSignature;
251     }
252 
253     std::fstream odsign_info(kOdsignInfo, std::ios::in | std::ios::binary);
254     if (!odsign_info) {
255         return Error() << "Failed to open " << kOdsignInfo;
256     }
257     odsign_info.seekg(0);
258     // Verify the hash
259     std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
260                                 std::istreambuf_iterator<char>());
261 
262     auto publicKey = key.getPublicKey();
263     auto signResult = verifySignature(odsign_info_str, persistedSignature, *publicKey);
264     if (!signResult.ok()) {
265         return Error() << kOdsignInfoSignature << " does not match.";
266     } else {
267         LOG(INFO) << kOdsignInfoSignature << " matches.";
268     }
269 
270     odsign_info.seekg(0);
271     if (!odsignInfo.ParseFromIstream(&odsign_info)) {
272         return Error() << "Failed to parse " << kOdsignInfo;
273     }
274 
275     LOG(INFO) << "Loaded " << kOdsignInfo;
276     return odsignInfo;
277 }
278 
getTrustedDigests(const SigningKey & key)279 std::map<std::string, std::string> getTrustedDigests(const SigningKey& key) {
280     std::map<std::string, std::string> trusted_digests;
281 
282     if (access(kOdsignInfo.c_str(), F_OK) != 0) {
283         // no odsign info file, which is not necessarily an error - just return
284         // an empty list of digests.
285         LOG(INFO) << kOdsignInfo << " not found.";
286         return trusted_digests;
287     }
288     auto signInfo = getAndVerifyOdsignInfo(key);
289 
290     if (signInfo.ok()) {
291         trusted_digests.insert(signInfo->file_hashes().begin(), signInfo->file_hashes().end());
292     } else {
293         // This is not expected, since the file did exist. Log an error and
294         // return an empty list of digests.
295         LOG(ERROR) << "Couldn't load trusted digests: " << signInfo.error();
296     }
297 
298     return trusted_digests;
299 }
300 
persistDigests(const std::map<std::string,std::string> & digests,const SigningKey & key)301 Result<void> persistDigests(const std::map<std::string, std::string>& digests,
302                             const SigningKey& key) {
303     OdsignInfo signInfo;
304     google::protobuf::Map<std::string, std::string> proto_hashes(digests.begin(), digests.end());
305     auto map = signInfo.mutable_file_hashes();
306     *map = proto_hashes;
307 
308     std::fstream odsign_info(kOdsignInfo,
309                              std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
310     if (!signInfo.SerializeToOstream(&odsign_info)) {
311         return Error() << "Failed to persist root hashes in " << kOdsignInfo;
312     }
313 
314     // Sign the signatures with our key itself, and write that to storage
315     odsign_info.seekg(0, std::ios::beg);
316     std::string odsign_info_str((std::istreambuf_iterator<char>(odsign_info)),
317                                 std::istreambuf_iterator<char>());
318     auto signResult = key.sign(odsign_info_str);
319     if (!signResult.ok()) {
320         return Error() << "Failed to sign " << kOdsignInfo;
321     }
322     android::base::WriteStringToFile(*signResult, kOdsignInfoSignature);
323     return {};
324 }
325 
verifyArtifactsIntegrity(const std::map<std::string,std::string> & trusted_digests,bool supportsFsVerity)326 Result<void> verifyArtifactsIntegrity(const std::map<std::string, std::string>& trusted_digests,
327                                       bool supportsFsVerity) {
328     Result<void> integrityStatus;
329 
330     if (supportsFsVerity) {
331         integrityStatus = verifyIntegrityFsVerity(trusted_digests);
332     } else {
333         integrityStatus = verifyIntegrityNoFsVerity(trusted_digests);
334     }
335     if (!integrityStatus.ok()) {
336         return integrityStatus.error();
337     }
338 
339     return {};
340 }
341 
getComposInfo()342 Result<OdsignInfo> getComposInfo() {
343     const char* const argv[] = {kCompOsVerifyPath, "--instance", "current"};
344     int result =
345         logwrap_fork_execvp(arraysize(argv), argv, nullptr, false, LOG_ALOG, false, nullptr);
346     if (result != 0) {
347         return Error() << kCompOsVerifyPath << " returned " << result;
348     }
349 
350     std::string compos_info_str;
351     if (!android::base::ReadFileToString(kCompOsInfo, &compos_info_str)) {
352         return ErrnoError() << "Failed to read " << kCompOsInfo;
353     }
354 
355     // Delete the files - we don't need them any more, and they'd confuse
356     // artifact verification
357     if (unlink(kCompOsInfo.c_str()) != 0 || unlink(kCompOsInfoSignature.c_str()) != 0) {
358         return ErrnoError() << "Unable to delete CompOS info/signature file";
359     }
360 
361     OdsignInfo compos_info;
362     if (!compos_info.ParseFromString(compos_info_str)) {
363         return Error() << "Failed to parse " << kCompOsInfo;
364     }
365 
366     LOG(INFO) << "Loaded " << kCompOsInfo;
367     return compos_info;
368 }
369 
CheckCompOsPendingArtifacts(const SigningKey & signing_key,bool * digests_verified,StatsReporter * stats_reporter)370 art::odrefresh::ExitCode CheckCompOsPendingArtifacts(const SigningKey& signing_key,
371                                                      bool* digests_verified,
372                                                      StatsReporter* stats_reporter) {
373     StatsReporter::CompOsArtifactsCheckRecord* compos_check_record =
374         stats_reporter->GetOrCreateComposArtifactsCheckRecord();
375 
376     if (!directoryHasContent(kCompOsPendingArtifactsDir)) {
377         // No pending CompOS artifacts, all that matters is the current ones.
378         art::odrefresh::ExitCode odrefresh_status = checkArtifacts();
379         if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
380             compos_check_record->current_artifacts_ok = true;
381         }
382         return odrefresh_status;
383     }
384 
385     compos_check_record->comp_os_pending_artifacts_exists = true;
386 
387     // CompOS has generated some artifacts that may, or may not, match the
388     // current state.  But if there are already valid artifacts present the
389     // CompOS ones are redundant.
390     art::odrefresh::ExitCode odrefresh_status = checkArtifacts();
391     if (odrefresh_status != art::odrefresh::ExitCode::kCompilationRequired) {
392         if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
393             compos_check_record->current_artifacts_ok = true;
394             LOG(INFO) << "Current artifacts are OK, deleting pending artifacts";
395             removeDirectory(kCompOsPendingArtifactsDir);
396         }
397         return odrefresh_status;
398     }
399 
400     // No useful current artifacts, lets see if the CompOS ones are ok
401     if (access(kCompOsPendingInfoPath, R_OK) != 0 ||
402         access(kCompOsPendingInfoSignaturePath, R_OK) != 0) {
403         LOG(INFO) << "Missing CompOS info/signature, deleting pending artifacts";
404         removeDirectory(kCompOsPendingArtifactsDir);
405         return art::odrefresh::ExitCode::kCompilationRequired;
406     }
407 
408     LOG(INFO) << "Current artifacts are out of date, switching to pending artifacts";
409     removeDirectory(kArtArtifactsDir);
410     if (!rename(kCompOsPendingArtifactsDir, kArtArtifactsDir)) {
411         removeDirectory(kCompOsPendingArtifactsDir);
412         return art::odrefresh::ExitCode::kCompilationRequired;
413     }
414 
415     // Make sure the artifacts we have are genuinely produced by the current
416     // instance of CompOS.
417     auto compos_info = getComposInfo();
418     if (!compos_info.ok()) {
419         LOG(WARNING) << compos_info.error();
420     } else {
421         std::map<std::string, std::string> compos_digests(compos_info->file_hashes().begin(),
422                                                           compos_info->file_hashes().end());
423 
424         auto status = verifyAllFilesUsingCompOs(kArtArtifactsDir, compos_digests);
425         if (!status.ok()) {
426             LOG(WARNING) << "Faild to verify CompOS artifacts: " << status.error();
427         } else {
428             LOG(INFO) << "CompOS artifacts successfully verified.";
429             odrefresh_status = checkArtifacts();
430             switch (odrefresh_status) {
431             case art::odrefresh::ExitCode::kCompilationRequired:
432                 // We have verified all the files, and we need to make sure
433                 // we don't check them against odsign.info which will be out
434                 // of date.
435                 *digests_verified = true;
436                 return odrefresh_status;
437             case art::odrefresh::ExitCode::kOkay: {
438                 // We have digests of all the files, so we can just sign them & save them now.
439                 // We need to make sure we don't check them against odsign.info which will
440                 // be out of date.
441                 auto persisted = persistDigests(compos_digests, signing_key);
442                 if (!persisted.ok()) {
443                     LOG(ERROR) << persisted.error();
444                     // Don't try to compile again - if we can't write the digests, things
445                     // are pretty bad.
446                     return art::odrefresh::ExitCode::kCleanupFailed;
447                 }
448                 compos_check_record->use_comp_os_generated_artifacts = true;
449                 LOG(INFO) << "Persisted CompOS digests.";
450                 *digests_verified = true;
451                 return odrefresh_status;
452             }
453             default:
454                 return odrefresh_status;
455             }
456         }
457     }
458 
459     // We can't use the existing artifacts, so we will need to generate new
460     // ones.
461     if (removeDirectory(kArtArtifactsDir) == 0) {
462         // We have unsigned artifacts that we can't delete, so it's not safe to continue.
463         LOG(ERROR) << "Unable to delete invalid CompOS artifacts";
464         return art::odrefresh::ExitCode::kCleanupFailed;
465     }
466 
467     return art::odrefresh::ExitCode::kCompilationRequired;
468 }
469 }  // namespace
470 
main(int,char ** argv)471 int main(int /* argc */, char** argv) {
472     android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
473 
474     auto scope_guard = android::base::make_scope_guard([]() {
475         // In case we hit any error, remove the artifacts and tell Zygote not to use
476         // anything
477         removeDirectory(kArtArtifactsDir);
478         removeDirectory(kCompOsPendingArtifactsDir);
479         // Tell init we don't need to use our key anymore
480         SetProperty(kOdsignKeyDoneProp, "1");
481         // Tell init we're done with verification, and that it was an error
482         SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusError);
483         SetProperty(kOdsignVerificationDoneProp, "1");
484         // Tell init it shouldn't try to restart us - see odsign.rc
485         SetProperty(kStopServiceProp, "odsign");
486     });
487 
488     // `stats_reporter` must come after `scope_guard` so that its destructor is called before
489     // `scope_guard`.
490     auto stats_reporter = std::make_unique<StatsReporter>();
491     StatsReporter::OdsignRecord* odsign_record = stats_reporter->GetOdsignRecord();
492 
493     if (!android::base::GetBoolProperty("ro.apex.updatable", false)) {
494         LOG(INFO) << "Device doesn't support updatable APEX, exiting.";
495         stats_reporter->SetOdsignRecordEnabled(false);
496         return 0;
497     }
498     auto keystoreResult =
499         KeystoreKey::getInstance(kPublicKeySignature, kKeyAlias, kKeyNspace, kKeyBootLevel);
500     if (!keystoreResult.ok()) {
501         LOG(ERROR) << "Could not create keystore key: " << keystoreResult.error();
502         odsign_record->status =
503             art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_KEYSTORE_FAILED;
504         return -1;
505     }
506     SigningKey* key = keystoreResult.value();
507 
508     bool supportsFsVerity = SupportsFsVerity();
509     if (!supportsFsVerity) {
510         LOG(INFO) << "Device doesn't support fsverity. Falling back to full verification.";
511     }
512 
513     bool useCompOs = kUseCompOs && supportsFsVerity && compOsPresent();
514 
515     if (supportsFsVerity) {
516         auto existing_cert = verifyExistingRootCert(*key);
517         if (!existing_cert.ok()) {
518             LOG(WARNING) << existing_cert.error();
519 
520             // Try to create a new cert
521             auto new_cert = createX509RootCert(*key, kSigningKeyCert);
522             if (!new_cert.ok()) {
523                 LOG(ERROR) << "Failed to create X509 certificate: " << new_cert.error();
524                 // TODO apparently the key become invalid - delete the blob / cert
525                 odsign_record->status =
526                     art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_CERT_FAILED;
527                 return -1;
528             }
529         } else {
530             LOG(INFO) << "Found and verified existing public key certificate: " << kSigningKeyCert;
531         }
532     }
533 
534     bool digests_verified = false;
535     art::odrefresh::ExitCode odrefresh_status =
536         useCompOs ? CheckCompOsPendingArtifacts(*key, &digests_verified, stats_reporter.get())
537                   : checkArtifacts();
538 
539     // The artifacts dir doesn't necessarily need to exist; if the existing
540     // artifacts on the system partition are valid, those can be used.
541     int err = access(kArtArtifactsDir.c_str(), F_OK);
542     // If we receive any error other than ENOENT, be suspicious
543     bool artifactsPresent = (err == 0) || (err < 0 && errno != ENOENT);
544 
545     if (artifactsPresent && !digests_verified &&
546         (odrefresh_status == art::odrefresh::ExitCode::kOkay ||
547          odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired)) {
548         // If we haven't verified the digests yet, we need to validate them. We
549         // need to do this both in case the existing artifacts are okay, but
550         // also if odrefresh said that a recompile is required. In the latter
551         // case, odrefresh may use partial compilation, and leave some
552         // artifacts unchanged.
553         auto trusted_digests = getTrustedDigests(*key);
554 
555         if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
556             // Tell init we're done with the key; this is a boot time optimization
557             // in particular for the no fs-verity case, where we need to do a
558             // costly verification. If the files haven't been tampered with, which
559             // should be the common path, the verification will succeed, and we won't
560             // need the key anymore. If it turns out the artifacts are invalid (eg not
561             // in fs-verity) or the hash doesn't match, we won't be able to generate
562             // new artifacts without the key, so in those cases, remove the artifacts,
563             // and use JIT zygote for the current boot. We should recover automatically
564             // by the next boot.
565             SetProperty(kOdsignKeyDoneProp, "1");
566         }
567 
568         auto verificationResult = verifyArtifactsIntegrity(trusted_digests, supportsFsVerity);
569         if (!verificationResult.ok()) {
570             int num_removed = removeDirectory(kArtArtifactsDir);
571             if (num_removed == 0) {
572                 // If we can't remove the bad artifacts, we shouldn't continue, and
573                 // instead prevent Zygote from using them (which is taken care of
574                 // in the exit handler).
575                 LOG(ERROR) << "Failed to remove unknown artifacts.";
576                 odsign_record->status =
577                     art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_CLEANUP_FAILED;
578                 return -1;
579             }
580         }
581     }
582 
583     // Now that we verified existing artifacts, compile if we need to.
584     if (odrefresh_status == art::odrefresh::ExitCode::kCompilationRequired) {
585         odrefresh_status = compileArtifacts(kForceCompilation);
586     }
587 
588     if (odrefresh_status == art::odrefresh::ExitCode::kOkay) {
589         // No new artifacts generated, and we verified existing ones above, nothing left to do.
590         LOG(INFO) << "odrefresh said artifacts are VALID";
591         stats_reporter->SetOdsignRecordEnabled(false);
592     } else if (odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess ||
593                odrefresh_status == art::odrefresh::ExitCode::kCompilationFailed) {
594         const bool compiled_all = odrefresh_status == art::odrefresh::ExitCode::kCompilationSuccess;
595         LOG(INFO) << "odrefresh compiled " << (compiled_all ? "all" : "partial")
596                   << " artifacts, returned " << odrefresh_status;
597         // This value may be overwritten later.
598         odsign_record->status =
599             compiled_all ? art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_ALL_OK
600                          : art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_PARTIAL_OK;
601         Result<std::map<std::string, std::string>> digests;
602         if (supportsFsVerity) {
603             digests = addFilesToVerityRecursive(kArtArtifactsDir);
604         } else {
605             // If we can't use verity, just compute the root hashes and store
606             // those, so we can reverify them at the next boot.
607             digests = computeDigests(kArtArtifactsDir);
608         }
609         if (!digests.ok()) {
610             LOG(ERROR) << digests.error();
611             odsign_record->status =
612                 art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_SIGNING_FAILED;
613             return -1;
614         }
615         auto persistStatus = persistDigests(*digests, *key);
616         if (!persistStatus.ok()) {
617             LOG(ERROR) << persistStatus.error();
618             odsign_record->status =
619                 art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_SIGNING_FAILED;
620             return -1;
621         }
622     } else if (odrefresh_status == art::odrefresh::ExitCode::kCleanupFailed) {
623         LOG(ERROR) << "odrefresh failed cleaning up existing artifacts";
624         odsign_record->status =
625             art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_ODREFRESH_FAILED;
626         return -1;
627     } else {
628         LOG(ERROR) << "odrefresh exited unexpectedly, returned " << odrefresh_status;
629         odsign_record->status =
630             art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_ODREFRESH_FAILED;
631         return -1;
632     }
633 
634     LOG(INFO) << "On-device signing done.";
635 
636     scope_guard.Disable();
637 
638     // Explicitly reset the pointer - We rely on stats_reporter's
639     // destructor for actually writing the buffered metrics. This will otherwise not be called
640     // if the program doesn't exit normally (for ex, killed by init, which actually happens
641     // because odsign (after it finishes) sets kStopServiceProp instructing init to kill it).
642     stats_reporter.reset();
643 
644     // At this point, we're done with the key for sure
645     SetProperty(kOdsignKeyDoneProp, "1");
646     // And we did a successful verification
647     SetProperty(kOdsignVerificationStatusProp, kOdsignVerificationStatusValid);
648     SetProperty(kOdsignVerificationDoneProp, "1");
649 
650     // Tell init it shouldn't try to restart us - see odsign.rc
651     SetProperty(kStopServiceProp, "odsign");
652     return 0;
653 }
654