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