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