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