• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 package com.android.server.art;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.os.Build;
23 
24 import androidx.annotation.RequiresApi;
25 
26 import com.android.art.flags.Flags;
27 
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.util.List;
31 import java.util.Set;
32 import java.util.stream.Collectors;
33 import java.util.stream.Stream;
34 
35 /**
36  * Helper class for <i>ART-managed install files</i> (files installed by Package Manager
37  * and managed by ART).
38  *
39  * @hide
40  */
41 @FlaggedApi(Flags.FLAG_ART_SERVICE_V3)
42 @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
43 @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
44 public final class ArtManagedInstallFileHelper {
45     private static final List<String> FILE_TYPES = List.of(ArtConstants.DEX_METADATA_FILE_EXT,
46             ArtConstants.PROFILE_FILE_EXT, ArtConstants.SECURE_DEX_METADATA_FILE_EXT);
47     private static final List<String> SDM_SUFFIXES =
48             Utils.getNativeIsas()
49                     .stream()
50                     .map(isa -> "." + isa + ArtConstants.SECURE_DEX_METADATA_FILE_EXT)
51                     .toList();
52 
ArtManagedInstallFileHelper()53     private ArtManagedInstallFileHelper() {}
54 
55     /**
56      * Returns whether the file at the given path is an <i>ART-managed install file</i>. This
57      * is a pure string operation on the input and does not involve any I/O.
58      */
59     @FlaggedApi(Flags.FLAG_ART_SERVICE_V3)
isArtManaged(@onNull String path)60     public static boolean isArtManaged(@NonNull String path) {
61         return FILE_TYPES.stream().anyMatch(ext -> path.endsWith(ext));
62     }
63 
64     /**
65      * Returns the subset of the given paths that are paths to the <i>ART-managed install files</i>
66      * corresponding to the given APK path. This is a pure string operation on the inputs and does
67      * not involve any I/O.
68      *
69      * Note that the files in different directories than the APK are not considered corresponding to
70      * the APK.
71      */
72     @FlaggedApi(Flags.FLAG_ART_SERVICE_V3)
filterPathsForApk( @onNull List<String> paths, @NonNull String apkPath)73     public static @NonNull List<String> filterPathsForApk(
74             @NonNull List<String> paths, @NonNull String apkPath) {
75         Set<String> candidates =
76                 FILE_TYPES.stream()
77                         .flatMap(ext
78                                 -> ext.equals(ArtConstants.SECURE_DEX_METADATA_FILE_EXT)
79                                         ? SDM_SUFFIXES.stream().map(suffix
80                                                   -> Utils.replaceFileExtension(apkPath, suffix))
81                                         : Stream.of(Utils.replaceFileExtension(apkPath, ext)))
82                         .collect(Collectors.toSet());
83         return paths.stream().filter(path -> candidates.contains(path)).toList();
84     }
85 
86     /**
87      * Rewrites the path to the <i>ART-managed install file</i> so that it corresponds to the given
88      * APK path. This is a pure string operation on the inputs and does not involve any I/O.
89      *
90      * Note that the result path is always in the same directory as the APK, in order to correspond
91      * to the APK.
92      *
93      * @throws IllegalArgumentException if {@code originalPath} does not represent an <i>ART-managed
94      *         install file</i>
95      */
96     @FlaggedApi(Flags.FLAG_ART_SERVICE_V3)
getTargetPathForApk( @onNull String originalPath, @NonNull String apkPath)97     public static @NonNull String getTargetPathForApk(
98             @NonNull String originalPath, @NonNull String apkPath) {
99         for (String ext : FILE_TYPES) {
100             if (!ext.equals(ArtConstants.SECURE_DEX_METADATA_FILE_EXT)
101                     && originalPath.endsWith(ext)) {
102                 return Utils.replaceFileExtension(apkPath, ext);
103             }
104         }
105         if (originalPath.endsWith(ArtConstants.SECURE_DEX_METADATA_FILE_EXT)) {
106             for (String suffix : SDM_SUFFIXES) {
107                 if (originalPath.endsWith(suffix)) {
108                     return Utils.replaceFileExtension(apkPath, suffix);
109                 }
110             }
111             AsLog.w("SDM filename '" + originalPath
112                     + "' does not contain a valid instruction set name");
113             Path dirname = Paths.get(apkPath).getParent();
114             Path basename = Paths.get(originalPath).getFileName();
115             return (dirname != null ? dirname.resolve(basename) : basename).toString();
116         }
117         throw new IllegalArgumentException(
118                 "Illegal ART managed install file path '" + originalPath + "'");
119     }
120 }
121