• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.pm;
18 
19 import static android.content.pm.PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
20 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
21 import static android.content.pm.parsing.ApkLiteParseUtils.isApkFile;
22 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
23 import static android.os.incremental.IncrementalManager.isIncrementalPath;
24 
25 import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
26 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
27 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
28 import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
29 
30 import android.annotation.NonNull;
31 import android.annotation.Nullable;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.Flags;
34 import android.content.pm.PackageManager;
35 import android.os.Build;
36 import android.os.Environment;
37 import android.os.FileUtils;
38 import android.os.SystemProperties;
39 import android.os.Trace;
40 import android.text.TextUtils;
41 import android.util.ArraySet;
42 import android.util.Pair;
43 import android.util.Slog;
44 
45 import com.android.internal.content.NativeLibraryHelper;
46 import com.android.internal.util.ArrayUtils;
47 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
48 import com.android.server.pm.pkg.AndroidPackage;
49 import com.android.server.pm.pkg.PackageStateInternal;
50 
51 import dalvik.system.VMRuntime;
52 
53 import libcore.io.IoUtils;
54 
55 import java.io.File;
56 import java.io.IOException;
57 import java.util.ArrayList;
58 import java.util.List;
59 
60 final class PackageAbiHelperImpl implements PackageAbiHelper {
61 
62     @Nullable
63     private static String[] sNativelySupported32BitAbis = null;
64     @Nullable
65     private static String[] sNativelySupported64BitAbis = null;
66 
calculateBundledApkRoot(final String codePathString)67     private static String calculateBundledApkRoot(final String codePathString) {
68         final File codePath = new File(codePathString);
69         final File codeRoot;
70         if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {
71             codeRoot = Environment.getRootDirectory();
72         } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {
73             codeRoot = Environment.getOemDirectory();
74         } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
75             codeRoot = Environment.getVendorDirectory();
76         } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
77             codeRoot = Environment.getOdmDirectory();
78         } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
79             codeRoot = Environment.getProductDirectory();
80         } else if (FileUtils.contains(Environment.getSystemExtDirectory(), codePath)) {
81             codeRoot = Environment.getSystemExtDirectory();
82         } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
83             codeRoot = Environment.getOdmDirectory();
84         } else if (FileUtils.contains(Environment.getApexDirectory(), codePath)) {
85             String fullPath = codePath.getAbsolutePath();
86             String[] parts = fullPath.split(File.separator);
87             if (parts.length > 2) {
88                 codeRoot = new File(parts[1] + File.separator + parts[2]);
89             } else {
90                 Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
91                 codeRoot = Environment.getApexDirectory();
92             }
93         } else {
94             // Unrecognized code path; take its top real segment as the apk root:
95             // e.g. /something/app/blah.apk => /something
96             try {
97                 File f = codePath.getCanonicalFile();
98                 File parent = f.getParentFile();    // non-null because codePath is a file
99                 File tmp;
100                 while ((tmp = parent.getParentFile()) != null) {
101                     f = parent;
102                     parent = tmp;
103                 }
104                 codeRoot = f;
105                 Slog.w(PackageManagerService.TAG, "Unrecognized code path "
106                         + codePath + " - using " + codeRoot);
107             } catch (IOException e) {
108                 // Can't canonicalize the code path -- shenanigans?
109                 Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
110                 return Environment.getRootDirectory().getPath();
111             }
112         }
113         return codeRoot.getPath();
114     }
115 
116     // Utility method that returns the relative package path with respect
117     // to the installation directory. Like say for /data/data/com.test-1.apk
118     // string com.test-1 is returned.
deriveCodePathName(String codePath)119     private static String deriveCodePathName(String codePath) {
120         if (codePath == null) {
121             return null;
122         }
123         final File codeFile = new File(codePath);
124         final String name = codeFile.getName();
125         if (codeFile.isDirectory()) {
126             return name;
127         } else if (name.endsWith(".apk") || name.endsWith(".tmp")) {
128             final int lastDot = name.lastIndexOf('.');
129             return name.substring(0, lastDot);
130         } else {
131             Slog.w(PackageManagerService.TAG, "Odd, " + codePath + " doesn't look like an APK");
132             return null;
133         }
134     }
135 
maybeThrowExceptionForMultiArchCopy(String message, int copyRet, boolean forceMatch)136     private static void maybeThrowExceptionForMultiArchCopy(String message, int copyRet,
137             boolean forceMatch) throws PackageManagerException {
138         if (copyRet < 0) {
139             if (copyRet != PackageManager.NO_NATIVE_LIBRARIES
140                     && copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
141                 throw new PackageManagerException(copyRet, message);
142             }
143 
144             if (forceMatch && copyRet == PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
145                 throw new PackageManagerException(
146                         PackageManager.INSTALL_FAILED_MULTI_ARCH_NOT_MATCH_ALL_NATIVE_ABIS,
147                         "The multiArch app's native libs don't support all the natively"
148                                 + " supported ABIs of the device.");
149             }
150         }
151     }
152 
153     @Override
deriveNativeLibraryPaths(AndroidPackage pkg, boolean isSystemApp, boolean isUpdatedSystemApp, File appLib32InstallDir)154     public NativeLibraryPaths deriveNativeLibraryPaths(AndroidPackage pkg, boolean isSystemApp,
155             boolean isUpdatedSystemApp, File appLib32InstallDir) {
156         // Trying to derive the paths, thus need the raw ABI info from the parsed package, and the
157         // current state in PackageSetting is irrelevant.
158         return deriveNativeLibraryPaths(new Abis(AndroidPackageUtils.getRawPrimaryCpuAbi(pkg),
159                 AndroidPackageUtils.getRawSecondaryCpuAbi(pkg)), appLib32InstallDir, pkg.getPath(),
160                 pkg.getBaseApkPath(), isSystemApp, isUpdatedSystemApp);
161     }
162 
deriveNativeLibraryPaths(final Abis abis, final File appLib32InstallDir, final String codePath, final String sourceDir, final boolean isSystemApp, final boolean isUpdatedSystemApp)163     private static NativeLibraryPaths deriveNativeLibraryPaths(final Abis abis,
164             final File appLib32InstallDir, final String codePath, final String sourceDir,
165             final boolean isSystemApp, final boolean isUpdatedSystemApp) {
166         final File codeFile = new File(codePath);
167         final boolean bundledApp = isSystemApp && !isUpdatedSystemApp;
168 
169         final String nativeLibraryRootDir;
170         final boolean nativeLibraryRootRequiresIsa;
171         final String nativeLibraryDir;
172         final String secondaryNativeLibraryDir;
173 
174         if (isApkFile(codeFile)) {
175             // Monolithic install
176             if (bundledApp) {
177                 // If "/system/lib64/apkname" exists, assume that is the per-package
178                 // native library directory to use; otherwise use "/system/lib/apkname".
179                 final String apkRoot = calculateBundledApkRoot(sourceDir);
180                 final boolean is64Bit = VMRuntime.is64BitInstructionSet(
181                         getPrimaryInstructionSet(abis));
182 
183                 // This is a bundled system app so choose the path based on the ABI.
184                 // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this
185                 // is just the default path.
186                 final String apkName = deriveCodePathName(codePath);
187                 final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;
188                 nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,
189                         apkName).getAbsolutePath();
190 
191                 if (abis.secondary != null) {
192                     final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;
193                     secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),
194                             secondaryLibDir, apkName).getAbsolutePath();
195                 } else {
196                     secondaryNativeLibraryDir = null;
197                 }
198             } else {
199                 final String apkName = deriveCodePathName(codePath);
200                 nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
201                         .getAbsolutePath();
202                 secondaryNativeLibraryDir = null;
203             }
204 
205             nativeLibraryRootRequiresIsa = false;
206             nativeLibraryDir = nativeLibraryRootDir;
207         } else {
208             // Cluster install
209             nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();
210             nativeLibraryRootRequiresIsa = true;
211 
212             nativeLibraryDir = new File(nativeLibraryRootDir,
213                     getPrimaryInstructionSet(abis)).getAbsolutePath();
214 
215             if (abis.secondary != null) {
216                 secondaryNativeLibraryDir = new File(nativeLibraryRootDir,
217                         VMRuntime.getInstructionSet(abis.secondary)).getAbsolutePath();
218             } else {
219                 secondaryNativeLibraryDir = null;
220             }
221         }
222         return new NativeLibraryPaths(nativeLibraryRootDir, nativeLibraryRootRequiresIsa,
223                 nativeLibraryDir, secondaryNativeLibraryDir);
224     }
225 
226     @Override
getBundledAppAbis(AndroidPackage pkg)227     public Abis getBundledAppAbis(AndroidPackage pkg) {
228         final String apkName = deriveCodePathName(pkg.getPath());
229 
230         // If "/system/lib64/apkname" exists, assume that is the per-package
231         // native library directory to use; otherwise use "/system/lib/apkname".
232         final String apkRoot = calculateBundledApkRoot(pkg.getBaseApkPath());
233         final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
234         return abis;
235     }
236 
237     /**
238      * Deduces the ABI of a bundled app and sets the relevant fields on the
239      * parsed pkg object.
240      *
241      * @param apkRoot the root of the installed apk, something like {@code /system} or
242      *                {@code /oem} under which system libraries are installed.
243      * @param apkName the name of the installed package.
244      */
getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName)245     private Abis getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName) {
246         final File codeFile = new File(pkg.getPath());
247 
248         final boolean has64BitLibs;
249         final boolean has32BitLibs;
250 
251         final String primaryCpuAbi;
252         final String secondaryCpuAbi;
253         if (isApkFile(codeFile)) {
254             // Monolithic install
255             has64BitLibs =
256                     (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();
257             has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();
258         } else {
259             // Cluster install
260             final File rootDir = new File(codeFile, LIB_DIR_NAME);
261             if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)
262                     && !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {
263                 final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);
264                 has64BitLibs = (new File(rootDir, isa)).exists();
265             } else {
266                 has64BitLibs = false;
267             }
268             if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)
269                     && !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {
270                 final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);
271                 has32BitLibs = (new File(rootDir, isa)).exists();
272             } else {
273                 has32BitLibs = false;
274             }
275         }
276 
277         if (has64BitLibs && !has32BitLibs) {
278             // The package has 64 bit libs, but not 32 bit libs. Its primary
279             // ABI should be 64 bit. We can safely assume here that the bundled
280             // native libraries correspond to the most preferred ABI in the list.
281 
282             primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
283             secondaryCpuAbi = null;
284         } else if (has32BitLibs && !has64BitLibs) {
285             // The package has 32 bit libs but not 64 bit libs. Its primary
286             // ABI should be 32 bit.
287 
288             primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
289             secondaryCpuAbi = null;
290         } else if (has32BitLibs && has64BitLibs) {
291             // The application has both 64 and 32 bit bundled libraries. We check
292             // here that the app declares multiArch support, and warn if it doesn't.
293             //
294             // We will be lenient here and record both ABIs. The primary will be the
295             // ABI that's higher on the list, i.e, a device that's configured to prefer
296             // 64 bit apps will see a 64 bit primary ABI,
297 
298             if (!pkg.isMultiArch()) {
299                 Slog.e(PackageManagerService.TAG,
300                         "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
301             }
302 
303             if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
304                 primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
305                 secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
306             } else {
307                 primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];
308                 secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];
309             }
310         } else {
311             primaryCpuAbi = null;
312             secondaryCpuAbi = null;
313         }
314         return new Abis(primaryCpuAbi, secondaryCpuAbi);
315     }
316 
317     @NonNull
getNativelySupportedAbis(@onNull String[] supportedAbis)318     private static String[] getNativelySupportedAbis(@NonNull String[] supportedAbis) {
319         List<String> nativelySupportedAbis = new ArrayList<>();
320         for (int i = 0; i < supportedAbis.length; i++) {
321             final String currentAbi = supportedAbis[i];
322             // In presence of a native bridge this means the Abi is emulated.
323             final String currentIsa = VMRuntime.getInstructionSet(currentAbi);
324             if (TextUtils.isEmpty(SystemProperties.get("ro.dalvik.vm.isa." + currentIsa))) {
325                 nativelySupportedAbis.add(currentAbi);
326             }
327         }
328         return nativelySupportedAbis.toArray(new String[0]);
329     }
330 
getNativelySupported32BitAbis()331     private static String[] getNativelySupported32BitAbis() {
332         if (sNativelySupported32BitAbis != null) {
333             return sNativelySupported32BitAbis;
334         }
335 
336         sNativelySupported32BitAbis = getNativelySupportedAbis(Build.SUPPORTED_32_BIT_ABIS);
337         return sNativelySupported32BitAbis;
338     }
339 
getNativelySupported64BitAbis()340     private static String[] getNativelySupported64BitAbis() {
341         if (sNativelySupported64BitAbis != null) {
342             return sNativelySupported64BitAbis;
343         }
344 
345         sNativelySupported64BitAbis = getNativelySupportedAbis(Build.SUPPORTED_64_BIT_ABIS);
346         return sNativelySupported64BitAbis;
347     }
348 
349     @Override
350     @SuppressWarnings("AndroidFrameworkCompatChange") // the check is before the apk is installed
derivePackageAbi(AndroidPackage pkg, boolean isSystemApp, boolean isUpdatedSystemApp, String cpuAbiOverride, File appLib32InstallDir)351     public Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, boolean isSystemApp,
352             boolean isUpdatedSystemApp, String cpuAbiOverride, File appLib32InstallDir)
353             throws PackageManagerException {
354         // Give ourselves some initial paths; we'll come back for another
355         // pass once we've determined ABI below.
356         String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(pkg);
357         String pkgRawSecondaryCpuAbi = AndroidPackageUtils.getRawSecondaryCpuAbi(pkg);
358         final NativeLibraryPaths initialLibraryPaths = deriveNativeLibraryPaths(
359                 new Abis(pkgRawPrimaryCpuAbi, pkgRawSecondaryCpuAbi),
360                 appLib32InstallDir, pkg.getPath(),
361                 pkg.getBaseApkPath(), isSystemApp,
362                 isUpdatedSystemApp);
363 
364         final boolean extractLibs = shouldExtractLibs(pkg, isSystemApp, isUpdatedSystemApp);
365 
366         final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
367         final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
368         final boolean onIncremental = isIncrementalPath(pkg.getPath());
369 
370         String primaryCpuAbi = null;
371         String secondaryCpuAbi = null;
372 
373         NativeLibraryHelper.Handle handle = null;
374         try {
375             handle = AndroidPackageUtils.createNativeLibraryHandle(pkg);
376             // TODO(multiArch): This can be null for apps that didn't go through the
377             // usual installation process. We can calculate it again, like we
378             // do during install time.
379             //
380             // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally
381             // unnecessary.
382             final File nativeLibraryRoot = new File(nativeLibraryRootStr);
383 
384             // Null out the abis so that they can be recalculated.
385             primaryCpuAbi = null;
386             secondaryCpuAbi = null;
387             if (pkg.isMultiArch()) {
388                 // Force the match for these cases
389                 // 1. pkg.getTargetSdkVersion >= Build.VERSION_CODES.VANILLA_ICE_CREAM
390                 // 2. cpuAbiOverride is null. If it is non-null, it is set via shell for testing
391                 final boolean forceMatch = Flags.forceMultiArchNativeLibsMatch()
392                         && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.VANILLA_ICE_CREAM
393                         && cpuAbiOverride == null;
394 
395                 String[] supported32BitAbis = forceMatch ? getNativelySupported32BitAbis()
396                         : Build.SUPPORTED_32_BIT_ABIS;
397                 String[] supported64BitAbis = forceMatch ? getNativelySupported64BitAbis()
398                         : Build.SUPPORTED_64_BIT_ABIS;
399 
400                 final boolean systemSupports32BitAbi = supported32BitAbis.length > 0;
401                 final boolean systemSupports64BitAbi = supported64BitAbis.length > 0;
402 
403                 int abi32 = PackageManager.NO_NATIVE_LIBRARIES;
404                 int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
405                 if (systemSupports32BitAbi) {
406                     if (extractLibs) {
407                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
408                         abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
409                                 nativeLibraryRoot, supported32BitAbis,
410                                 useIsaSpecificSubdirs, onIncremental);
411                     } else {
412                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
413                         abi32 = NativeLibraryHelper.findSupportedAbi(
414                                 handle, supported32BitAbis);
415                     }
416                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
417                 }
418 
419                 // Shared library native code should be in the APK zip aligned
420                 if (abi32 >= 0 && AndroidPackageUtils.isLibrary(pkg) && extractLibs) {
421                     throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
422                             "Shared library native lib extraction not supported");
423                 }
424 
425                 maybeThrowExceptionForMultiArchCopy(
426                         "Error unpackaging 32 bit native libs for multiarch app.", abi32,
427                         forceMatch && systemSupports32BitAbi);
428 
429                 if (systemSupports64BitAbi) {
430                     if (extractLibs) {
431                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
432                         abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
433                                 nativeLibraryRoot, supported64BitAbis,
434                                 useIsaSpecificSubdirs, onIncremental);
435                     } else {
436                         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
437                         abi64 = NativeLibraryHelper.findSupportedAbi(
438                                 handle, supported64BitAbis);
439                     }
440                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
441                 }
442 
443                 maybeThrowExceptionForMultiArchCopy(
444                         "Error unpackaging 64 bit native libs for multiarch app.", abi64,
445                         forceMatch && systemSupports64BitAbi);
446 
447                 if (abi64 >= 0) {
448                     // Shared library native libs should be in the APK zip aligned
449                     if (extractLibs && AndroidPackageUtils.isLibrary(pkg)) {
450                         throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
451                                 "Shared library native lib extraction not supported");
452                     }
453                     primaryCpuAbi = supported64BitAbis[abi64];
454                 }
455 
456                 if (abi32 >= 0) {
457                     final String abi = supported32BitAbis[abi32];
458                     if (abi64 >= 0) {
459                         if (pkg.is32BitAbiPreferred()) {
460                             secondaryCpuAbi = primaryCpuAbi;
461                             primaryCpuAbi = abi;
462                         } else {
463                             secondaryCpuAbi = abi;
464                         }
465                     } else {
466                         primaryCpuAbi = abi;
467                     }
468                 }
469             } else {
470                 String[] abiList = (cpuAbiOverride != null)
471                         ? new String[]{cpuAbiOverride} : Build.SUPPORTED_ABIS;
472 
473                 // If an app that contains RenderScript has target API level < 21, it needs to run
474                 // with 32-bit ABI, and its APK file will contain a ".bc" file.
475                 // If an app that contains RenderScript has target API level >= 21, it can run with
476                 // either 32-bit or 64-bit ABI, and its APK file will not contain a ".bc" file.
477                 // Therefore, on a device that supports both 32-bit and 64-bit ABIs, we scan the app
478                 // APK to see if it has a ".bc" file. If so, we will run it with 32-bit ABI.
479                 // However, if the device only supports 64-bit ABI but does not support 32-bit ABI,
480                 // we will fail the installation for such an app because it won't be able to run.
481                 boolean needsRenderScriptOverride = false;
482                 // No need to check if the device only supports 32-bit
483                 if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null
484                         && NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
485                     if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
486                         abiList = Build.SUPPORTED_32_BIT_ABIS;
487                         needsRenderScriptOverride = true;
488                     } else {
489                         throw new PackageManagerException(
490                                 INSTALL_FAILED_CPU_ABI_INCOMPATIBLE,
491                                 "Apps that contain RenderScript with target API level < 21 are not "
492                                         + "supported on 64-bit only platforms");
493                     }
494                 }
495 
496                 final int copyRet;
497                 if (extractLibs) {
498                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
499                     copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
500                             nativeLibraryRoot, abiList, useIsaSpecificSubdirs, onIncremental);
501                 } else {
502                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
503                     copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
504                 }
505                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
506 
507                 if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
508                     throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
509                             "Error unpackaging native libs for app, errorCode=" + copyRet);
510                 }
511 
512                 if (copyRet >= 0) {
513                     // Shared libraries that have native libs must be multi-architecture
514                     if (AndroidPackageUtils.isLibrary(pkg)) {
515                         throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
516                                 "Shared library with native libs must be multiarch");
517                     }
518                     primaryCpuAbi = abiList[copyRet];
519                 } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES
520                         && cpuAbiOverride != null) {
521                     primaryCpuAbi = cpuAbiOverride;
522                 } else if (needsRenderScriptOverride) {
523                     primaryCpuAbi = abiList[0];
524                 }
525             }
526         } catch (IOException ioe) {
527             Slog.e(PackageManagerService.TAG, "Unable to get canonical file " + ioe.toString());
528         } finally {
529             IoUtils.closeQuietly(handle);
530         }
531 
532         // Now that we've calculated the ABIs and determined if it's an internal app,
533         // we will go ahead and populate the nativeLibraryPath.
534 
535         final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
536         return new Pair<>(abis,
537                 deriveNativeLibraryPaths(abis, appLib32InstallDir,
538                         pkg.getPath(), pkg.getBaseApkPath(), isSystemApp,
539                         isUpdatedSystemApp));
540     }
541 
shouldExtractLibs(AndroidPackage pkg, boolean isSystemApp, boolean isUpdatedSystemApp)542     private boolean shouldExtractLibs(AndroidPackage pkg, boolean isSystemApp,
543             boolean isUpdatedSystemApp) {
544         // We shouldn't extract libs if the package is a library or if extractNativeLibs=false
545         boolean extractLibs = !AndroidPackageUtils.isLibrary(pkg)
546                 && pkg.isExtractNativeLibrariesRequested();
547         // We shouldn't attempt to extract libs from system app when it was not updated.
548         if (isSystemApp && !isUpdatedSystemApp) {
549             extractLibs = false;
550         }
551         return extractLibs;
552     }
553 
554     /**
555      * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
556      * i.e, so that all packages can be run inside a single process if required.
557      *
558      * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
559      * this function will either try and make the ABI for all packages in
560      * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
561      * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
562      * variant is used when installing or updating a package that belongs to a shared user.
563      *
564      * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
565      * adds unnecessary complexity.
566      */
567     @Override
568     @Nullable
getAdjustedAbiForSharedUser( ArraySet<? extends PackageStateInternal> packagesForUser, AndroidPackage scannedPackage)569     public String getAdjustedAbiForSharedUser(
570             ArraySet<? extends PackageStateInternal> packagesForUser,
571             AndroidPackage scannedPackage) {
572         String requiredInstructionSet = null;
573         if (scannedPackage != null) {
574             String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage);
575             if (pkgRawPrimaryCpuAbi != null) {
576                 requiredInstructionSet = VMRuntime.getInstructionSet(pkgRawPrimaryCpuAbi);
577             }
578         }
579 
580         PackageStateInternal requirer = null;
581         for (PackageStateInternal ps : packagesForUser) {
582             // If packagesForUser contains scannedPackage, we skip it. This will happen
583             // when scannedPackage is an update of an existing package. Without this check,
584             // we will never be able to change the ABI of any package belonging to a shared
585             // user, even if it's compatible with other packages.
586             if (scannedPackage != null && scannedPackage.getPackageName().equals(
587                     ps.getPackageName())) {
588                 continue;
589             }
590             if (ps.getPrimaryCpuAbiLegacy() == null) {
591                 continue;
592             }
593 
594             final String instructionSet =
595                     VMRuntime.getInstructionSet(ps.getPrimaryCpuAbiLegacy());
596             if (requiredInstructionSet != null && !requiredInstructionSet.equals(instructionSet)) {
597                 // We have a mismatch between instruction sets (say arm vs arm64) warn about
598                 // this but there's not much we can do.
599                 String errorMessage = "Instruction set mismatch, "
600                         + ((requirer == null) ? "[caller]" : requirer)
601                         + " requires " + requiredInstructionSet + " whereas " + ps
602                         + " requires " + instructionSet;
603                 Slog.w(PackageManagerService.TAG, errorMessage);
604             }
605 
606             if (requiredInstructionSet == null) {
607                 requiredInstructionSet = instructionSet;
608                 requirer = ps;
609             }
610         }
611 
612         if (requiredInstructionSet == null) {
613             return null;
614         }
615         final String adjustedAbi;
616         if (requirer != null) {
617             // requirer != null implies that either scannedPackage was null or that
618             // scannedPackage did not require an ABI, in which case we have to adjust
619             // scannedPackage to match the ABI of the set (which is the same as
620             // requirer's ABI)
621             adjustedAbi = requirer.getPrimaryCpuAbiLegacy();
622         } else {
623             // requirer == null implies that we're updating all ABIs in the set to
624             // match scannedPackage.
625             adjustedAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage);
626         }
627         return adjustedAbi;
628     }
629 
630     @Override
checkPackageAlignment( AndroidPackage pkg, String libraryRoot, boolean nativeLibraryRootRequiresIsa, String abiOverride)631     public int checkPackageAlignment(
632             AndroidPackage pkg,
633             String libraryRoot,
634             boolean nativeLibraryRootRequiresIsa,
635             String abiOverride) {
636         NativeLibraryHelper.Handle handle = null;
637         try {
638             handle = AndroidPackageUtils.createNativeLibraryHandle(pkg);
639             return NativeLibraryHelper.checkAlignmentForCompatMode(
640                             handle, libraryRoot, nativeLibraryRootRequiresIsa, abiOverride);
641         } catch (IOException e) {
642             Slog.e(PackageManagerService.TAG, "Failed to check alignment of package : "
643                     + pkg.getPackageName());
644             return ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
645         }
646     }
647 }
648