Loading core/java/android/content/pm/PackageInstaller.java +34 −0 Original line number Diff line number Diff line Loading @@ -2072,6 +2072,25 @@ public class PackageInstaller { return new InstallInfo(result); } /** * Parse a single APK file passed as an FD to get install relevant information about * the package wrapped in {@link InstallInfo}. * @throws PackageParsingException if the package source file(s) provided is(are) not valid, * or the parser isn't able to parse the supplied source(s). * @hide */ @NonNull public InstallInfo readInstallInfo(@NonNull ParcelFileDescriptor pfd, @Nullable String debugPathName, int flags) throws PackageParsingException { final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult<PackageLite> result = ApkLiteParseUtils.parseMonolithicPackageLite(input, pfd.getFileDescriptor(), debugPathName, flags); if (result.isError()) { throw new PackageParsingException(result.getErrorCode(), result.getErrorMessage()); } return new InstallInfo(result); } // (b/239722738) This class serves as a bridge between the PackageLite class, which // is a hidden class, and the consumers of this class. (e.g. InstallInstalling.java) // This is a part of an effort to remove dependency on hidden APIs and use SystemAPIs or Loading Loading @@ -2125,6 +2144,21 @@ public class PackageInstaller { public long calculateInstalledSize(@NonNull SessionParams params) throws IOException { return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride); } /** * @param params {@link SessionParams} of the installation * @param pfd of an APK opened for read * @return Total disk space occupied by an application after installation. * Includes the size of the raw APKs, possibly unpacked resources, raw dex metadata files, * and all relevant native code. * @throws IOException when size of native binaries cannot be calculated. * @hide */ public long calculateInstalledSize(@NonNull SessionParams params, @NonNull ParcelFileDescriptor pfd) throws IOException { return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride, pfd.getFileDescriptor()); } } /** Loading core/java/android/content/pm/parsing/ApkLiteParseUtils.java +28 −1 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ public class ApkLiteParseUtils { } /** * Parse lightweight details about a single APK files. * Parse lightweight details about a single APK file. */ public static ParseResult<PackageLite> parseMonolithicPackageLite(ParseInput input, File packageFile, int flags) { Loading @@ -134,6 +134,33 @@ public class ApkLiteParseUtils { } } /** * Parse lightweight details about a single APK file passed as an FD. */ public static ParseResult<PackageLite> parseMonolithicPackageLite(ParseInput input, FileDescriptor packageFd, String debugPathName, int flags) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); try { final ParseResult<ApkLite> result = parseApkLite(input, packageFd, debugPathName, flags); if (result.isError()) { return input.error(result); } final ApkLite baseApk = result.getResult(); final String packagePath = debugPathName; return input.success( new PackageLite(packagePath, baseApk.getPath(), baseApk, null /* splitNames */, null /* isFeatureSplits */, null /* usesSplitNames */, null /* configForSplit */, null /* splitApkPaths */, null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(), null /* requiredSplitTypes */, null, /* splitTypes */ baseApk.isAllowUpdateOwnership())); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * Parse lightweight details about a directory of APKs. * Loading packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java +9 −4 Original line number Diff line number Diff line Loading @@ -16,14 +16,14 @@ package com.android.packageinstaller; import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_STAGED_SESSION_ID; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import androidx.annotation.Nullable; import java.io.File; /** * Trampoline activity. Calls PackageInstallerActivity and deletes staged install file onResult. */ Loading Loading @@ -52,8 +52,13 @@ public class DeleteStagedFileOnResult extends Activity { super.onDestroy(); if (isFinishing()) { File sourceFile = new File(getIntent().getData().getPath()); new Thread(sourceFile::delete).start(); // While we expect PIA/InstallStaging to abandon/commit the session, still there // might be cases when the session becomes orphan. int sessionId = getIntent().getIntExtra(EXTRA_STAGED_SESSION_ID, 0); try { getPackageManager().getPackageInstaller().abandonSession(sessionId); } catch (SecurityException ignored) { } } } } packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java +14 −93 Original line number Diff line number Diff line Loading @@ -16,17 +16,17 @@ package com.android.packageinstaller; import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_STAGED_SESSION_ID; import android.app.PendingIntent; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.InstallInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Process; import android.util.Log; import android.view.View; import android.widget.Button; Loading @@ -34,10 +34,7 @@ import android.widget.Button; import androidx.annotation.Nullable; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Send package to the package manager and handle results from package manager. Once the Loading Loading @@ -77,7 +74,7 @@ public class InstallInstalling extends AlertActivity { .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mPackageURI = getIntent().getData(); if ("package".equals(mPackageURI.getScheme())) { if (PackageInstallerActivity.SCHEME_PACKAGE.equals(mPackageURI.getScheme())) { try { getPackageManager().installExistingPackage(appInfo.packageName); launchSuccess(); Loading @@ -86,6 +83,8 @@ public class InstallInstalling extends AlertActivity { PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } } else { // ContentResolver.SCHEME_FILE // STAGED_SESSION_ID extra contains an ID of a previously staged install session. final File sourceFile = new File(mPackageURI.getPath()); PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile); Loading Loading @@ -122,41 +121,6 @@ public class InstallInstalling extends AlertActivity { // Does not happen } } else { PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); final Uri referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER); params.setPackageSource( referrerUri != null ? PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE : PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE); params.setInstallAsInstantApp(false); params.setReferrerUri(referrerUri); params.setOriginatingUri(getIntent() .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI)); params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID, Process.INVALID_UID)); params.setInstallerPackageName(getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME)); params.setInstallReason(PackageManager.INSTALL_REASON_USER); File file = new File(mPackageURI.getPath()); try { final InstallInfo result = getPackageManager().getPackageInstaller() .readInstallInfo(file, 0); params.setAppPackageName(result.getPackageName()); params.setInstallLocation(result.getInstallLocation()); try { params.setSize(result.calculateInstalledSize(params)); } catch (IOException e) { e.printStackTrace(); params.setSize(file.length()); } } catch (PackageInstaller.PackageParsingException e) { Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.", e); Log.e(LOG_TAG, "Cannot calculate installed size " + file + ". Try only apk size."); params.setSize(file.length()); } try { mInstallId = InstallEventReceiver .addObserver(this, EventResultPersister.GENERATE_NEW_ID, Loading @@ -166,9 +130,14 @@ public class InstallInstalling extends AlertActivity { PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } try { mSessionId = getPackageManager().getPackageInstaller().createSession(params); } catch (IOException e) { mSessionId = getIntent().getIntExtra(EXTRA_STAGED_SESSION_ID, 0); // Try to open session previously staged in InstallStaging. try (PackageInstaller.Session ignored = getPackageManager().getPackageInstaller().openSession( mSessionId)) { Log.d(LOG_TAG, "Staged session is valid, proceeding with the install"); } catch (IOException | SecurityException e) { Log.e(LOG_TAG, "Invalid session id passed", e); launchFailure(PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } Loading Loading @@ -293,57 +262,9 @@ public class InstallInstalling extends AlertActivity { @Override protected PackageInstaller.Session doInBackground(Void... params) { PackageInstaller.Session session; try { session = getPackageManager().getPackageInstaller().openSession(mSessionId); return getPackageManager().getPackageInstaller().openSession(mSessionId); } catch (IOException e) { synchronized (this) { isDone = true; notifyAll(); } return null; } session.setStagingProgress(0); try { File file = new File(mPackageURI.getPath()); try (InputStream in = new FileInputStream(file)) { long sizeBytes = file.length(); long totalRead = 0; try (OutputStream out = session .openWrite("PackageInstaller", 0, sizeBytes)) { byte[] buffer = new byte[1024 * 1024]; while (true) { int numRead = in.read(buffer); if (numRead == -1) { session.fsync(out); break; } if (isCancelled()) { session.close(); break; } out.write(buffer, 0, numRead); if (sizeBytes > 0) { totalRead += numRead; float fraction = ((float) totalRead / (float) sizeBytes); session.setStagingProgress(fraction); } } } } return session; } catch (IOException | SecurityException e) { Log.e(LOG_TAG, "Could not write package", e); session.close(); return null; } finally { synchronized (this) { Loading packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java +193 −51 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/content/pm/PackageInstaller.java +34 −0 Original line number Diff line number Diff line Loading @@ -2072,6 +2072,25 @@ public class PackageInstaller { return new InstallInfo(result); } /** * Parse a single APK file passed as an FD to get install relevant information about * the package wrapped in {@link InstallInfo}. * @throws PackageParsingException if the package source file(s) provided is(are) not valid, * or the parser isn't able to parse the supplied source(s). * @hide */ @NonNull public InstallInfo readInstallInfo(@NonNull ParcelFileDescriptor pfd, @Nullable String debugPathName, int flags) throws PackageParsingException { final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing(); final ParseResult<PackageLite> result = ApkLiteParseUtils.parseMonolithicPackageLite(input, pfd.getFileDescriptor(), debugPathName, flags); if (result.isError()) { throw new PackageParsingException(result.getErrorCode(), result.getErrorMessage()); } return new InstallInfo(result); } // (b/239722738) This class serves as a bridge between the PackageLite class, which // is a hidden class, and the consumers of this class. (e.g. InstallInstalling.java) // This is a part of an effort to remove dependency on hidden APIs and use SystemAPIs or Loading Loading @@ -2125,6 +2144,21 @@ public class PackageInstaller { public long calculateInstalledSize(@NonNull SessionParams params) throws IOException { return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride); } /** * @param params {@link SessionParams} of the installation * @param pfd of an APK opened for read * @return Total disk space occupied by an application after installation. * Includes the size of the raw APKs, possibly unpacked resources, raw dex metadata files, * and all relevant native code. * @throws IOException when size of native binaries cannot be calculated. * @hide */ public long calculateInstalledSize(@NonNull SessionParams params, @NonNull ParcelFileDescriptor pfd) throws IOException { return InstallLocationUtils.calculateInstalledSize(mPkg, params.abiOverride, pfd.getFileDescriptor()); } } /** Loading
core/java/android/content/pm/parsing/ApkLiteParseUtils.java +28 −1 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ public class ApkLiteParseUtils { } /** * Parse lightweight details about a single APK files. * Parse lightweight details about a single APK file. */ public static ParseResult<PackageLite> parseMonolithicPackageLite(ParseInput input, File packageFile, int flags) { Loading @@ -134,6 +134,33 @@ public class ApkLiteParseUtils { } } /** * Parse lightweight details about a single APK file passed as an FD. */ public static ParseResult<PackageLite> parseMonolithicPackageLite(ParseInput input, FileDescriptor packageFd, String debugPathName, int flags) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); try { final ParseResult<ApkLite> result = parseApkLite(input, packageFd, debugPathName, flags); if (result.isError()) { return input.error(result); } final ApkLite baseApk = result.getResult(); final String packagePath = debugPathName; return input.success( new PackageLite(packagePath, baseApk.getPath(), baseApk, null /* splitNames */, null /* isFeatureSplits */, null /* usesSplitNames */, null /* configForSplit */, null /* splitApkPaths */, null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(), null /* requiredSplitTypes */, null, /* splitTypes */ baseApk.isAllowUpdateOwnership())); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } /** * Parse lightweight details about a directory of APKs. * Loading
packages/PackageInstaller/src/com/android/packageinstaller/DeleteStagedFileOnResult.java +9 −4 Original line number Diff line number Diff line Loading @@ -16,14 +16,14 @@ package com.android.packageinstaller; import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_STAGED_SESSION_ID; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import androidx.annotation.Nullable; import java.io.File; /** * Trampoline activity. Calls PackageInstallerActivity and deletes staged install file onResult. */ Loading Loading @@ -52,8 +52,13 @@ public class DeleteStagedFileOnResult extends Activity { super.onDestroy(); if (isFinishing()) { File sourceFile = new File(getIntent().getData().getPath()); new Thread(sourceFile::delete).start(); // While we expect PIA/InstallStaging to abandon/commit the session, still there // might be cases when the session becomes orphan. int sessionId = getIntent().getIntExtra(EXTRA_STAGED_SESSION_ID, 0); try { getPackageManager().getPackageInstaller().abandonSession(sessionId); } catch (SecurityException ignored) { } } } }
packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java +14 −93 Original line number Diff line number Diff line Loading @@ -16,17 +16,17 @@ package com.android.packageinstaller; import static com.android.packageinstaller.PackageInstallerActivity.EXTRA_STAGED_SESSION_ID; import android.app.PendingIntent; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.InstallInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Process; import android.util.Log; import android.view.View; import android.widget.Button; Loading @@ -34,10 +34,7 @@ import android.widget.Button; import androidx.annotation.Nullable; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Send package to the package manager and handle results from package manager. Once the Loading Loading @@ -77,7 +74,7 @@ public class InstallInstalling extends AlertActivity { .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mPackageURI = getIntent().getData(); if ("package".equals(mPackageURI.getScheme())) { if (PackageInstallerActivity.SCHEME_PACKAGE.equals(mPackageURI.getScheme())) { try { getPackageManager().installExistingPackage(appInfo.packageName); launchSuccess(); Loading @@ -86,6 +83,8 @@ public class InstallInstalling extends AlertActivity { PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } } else { // ContentResolver.SCHEME_FILE // STAGED_SESSION_ID extra contains an ID of a previously staged install session. final File sourceFile = new File(mPackageURI.getPath()); PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile); Loading Loading @@ -122,41 +121,6 @@ public class InstallInstalling extends AlertActivity { // Does not happen } } else { PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); final Uri referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER); params.setPackageSource( referrerUri != null ? PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE : PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE); params.setInstallAsInstantApp(false); params.setReferrerUri(referrerUri); params.setOriginatingUri(getIntent() .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI)); params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID, Process.INVALID_UID)); params.setInstallerPackageName(getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME)); params.setInstallReason(PackageManager.INSTALL_REASON_USER); File file = new File(mPackageURI.getPath()); try { final InstallInfo result = getPackageManager().getPackageInstaller() .readInstallInfo(file, 0); params.setAppPackageName(result.getPackageName()); params.setInstallLocation(result.getInstallLocation()); try { params.setSize(result.calculateInstalledSize(params)); } catch (IOException e) { e.printStackTrace(); params.setSize(file.length()); } } catch (PackageInstaller.PackageParsingException e) { Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.", e); Log.e(LOG_TAG, "Cannot calculate installed size " + file + ". Try only apk size."); params.setSize(file.length()); } try { mInstallId = InstallEventReceiver .addObserver(this, EventResultPersister.GENERATE_NEW_ID, Loading @@ -166,9 +130,14 @@ public class InstallInstalling extends AlertActivity { PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } try { mSessionId = getPackageManager().getPackageInstaller().createSession(params); } catch (IOException e) { mSessionId = getIntent().getIntExtra(EXTRA_STAGED_SESSION_ID, 0); // Try to open session previously staged in InstallStaging. try (PackageInstaller.Session ignored = getPackageManager().getPackageInstaller().openSession( mSessionId)) { Log.d(LOG_TAG, "Staged session is valid, proceeding with the install"); } catch (IOException | SecurityException e) { Log.e(LOG_TAG, "Invalid session id passed", e); launchFailure(PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } Loading Loading @@ -293,57 +262,9 @@ public class InstallInstalling extends AlertActivity { @Override protected PackageInstaller.Session doInBackground(Void... params) { PackageInstaller.Session session; try { session = getPackageManager().getPackageInstaller().openSession(mSessionId); return getPackageManager().getPackageInstaller().openSession(mSessionId); } catch (IOException e) { synchronized (this) { isDone = true; notifyAll(); } return null; } session.setStagingProgress(0); try { File file = new File(mPackageURI.getPath()); try (InputStream in = new FileInputStream(file)) { long sizeBytes = file.length(); long totalRead = 0; try (OutputStream out = session .openWrite("PackageInstaller", 0, sizeBytes)) { byte[] buffer = new byte[1024 * 1024]; while (true) { int numRead = in.read(buffer); if (numRead == -1) { session.fsync(out); break; } if (isCancelled()) { session.close(); break; } out.write(buffer, 0, numRead); if (sizeBytes > 0) { totalRead += numRead; float fraction = ((float) totalRead / (float) sizeBytes); session.setStagingProgress(fraction); } } } } return session; } catch (IOException | SecurityException e) { Log.e(LOG_TAG, "Could not write package", e); session.close(); return null; } finally { synchronized (this) { Loading
packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java +193 −51 File changed.Preview size limit exceeded, changes collapsed. Show changes