Loading core/java/android/content/pm/IPackageInstallerSession.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -26,9 +26,12 @@ interface IPackageInstallerSession { void addClientProgress(float progress); String[] getNames(); ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes); ParcelFileDescriptor openRead(String name); void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd); void removeSplit(String splitName); void close(); Loading core/java/android/content/pm/PackageInstaller.java +12 −0 Original line number Diff line number Diff line Loading @@ -829,7 +829,19 @@ public class PackageInstaller { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** {@hide} */ public void write(@NonNull String name, long offsetBytes, long lengthBytes, @NonNull ParcelFileDescriptor fd) throws IOException { try { mSession.write(name, offsetBytes, lengthBytes, fd); } catch (RuntimeException e) { ExceptionUtils.maybeUnwrapIOException(e); throw e; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +52 −4 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ import android.os.RevocableFileDescriptor; import android.os.UserHandle; import android.os.storage.StorageManager; import android.system.ErrnoException; import android.system.Int64Ref; import android.system.Os; import android.system.OsConstants; import android.system.StructStat; Loading Loading @@ -575,14 +576,24 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) { try { return openWriteInternal(name, offsetBytes, lengthBytes); return doWriteInternal(name, offsetBytes, lengthBytes, null); } catch (IOException e) { throw ExceptionUtils.wrap(e); } } private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes) throws IOException { @Override public void write(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor fd) { try { doWriteInternal(name, offsetBytes, lengthBytes, fd); } catch (IOException e) { throw ExceptionUtils.wrap(e); } } private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor incomingFd) throws IOException { // Quick sanity check of state, and allocate a pipe for ourselves. We // then do heavy disk allocation outside the lock, but this open pipe // will block any attempted install transitions. Loading Loading @@ -636,7 +647,44 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET); } if (incomingFd != null) { switch (Binder.getCallingUid()) { case android.os.Process.SHELL_UID: case android.os.Process.ROOT_UID: break; default: throw new SecurityException("Reverse mode only supported from shell"); } // In "reverse" mode, we're streaming data ourselves from the // incoming FD, which means we never have to hand out our // sensitive internal FD. We still rely on a "bridge" being // inserted above to hold the session active. try { final Int64Ref last = new Int64Ref(0); FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, (long progress) -> { if (params.sizeBytes > 0) { final long delta = progress - last.value; last.value = progress; addClientProgress((float) delta / (float) params.sizeBytes); } }, null, lengthBytes); } finally { IoUtils.closeQuietly(targetFd); IoUtils.closeQuietly(incomingFd); // We're done here, so remove the "bridge" that was holding // the session active. synchronized (mLock) { if (PackageInstaller.ENABLE_REVOCABLE_FD) { mFds.remove(fd); } else { mBridges.remove(bridge); } } } return null; } else if (PackageInstaller.ENABLE_REVOCABLE_FD) { fd.init(mContext, targetFd); return fd.getRevocableFileDescriptor(); } else { Loading services/core/java/com/android/server/pm/PackageManagerShellCommand.java +13 −42 Original line number Diff line number Diff line Loading @@ -16,6 +16,12 @@ package com.android.server.pm; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; import android.accounts.IAccountManager; import android.app.ActivityManager; import android.app.ActivityManagerInternal; Loading @@ -32,8 +38,10 @@ import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; Loading @@ -41,9 +49,6 @@ import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.pm.VersionedPackage; Loading Loading @@ -73,7 +78,6 @@ import android.util.PrintWriterPrinter; import com.android.internal.content.PackageHelper; import com.android.internal.util.ArrayUtils; import com.android.internal.util.SizedInputStream; import com.android.server.LocalServices; import com.android.server.SystemConfig; Loading @@ -81,9 +85,8 @@ import dalvik.system.DexFile; import libcore.io.IoUtils; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URISyntaxException; import java.util.ArrayList; Loading @@ -95,12 +98,6 @@ import java.util.WeakHashMap; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; class PackageManagerShellCommand extends ShellCommand { /** Path for streaming APK content */ private static final String STDIN_PATH = "-"; Loading Loading @@ -2213,7 +2210,7 @@ class PackageManagerShellCommand extends ShellCommand { final PrintWriter pw = getOutPrintWriter(); final ParcelFileDescriptor fd; if (STDIN_PATH.equals(inPath)) { fd = null; fd = new ParcelFileDescriptor(getInFileDescriptor()); } else if (inPath != null) { fd = openFileForSystem(inPath, "r"); if (fd == null) { Loading @@ -2225,53 +2222,27 @@ class PackageManagerShellCommand extends ShellCommand { return -1; } } else { fd = null; fd = new ParcelFileDescriptor(getInFileDescriptor()); } if (sizeBytes <= 0) { getErrPrintWriter().println("Error: must specify a APK size"); return 1; } final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId); PackageInstaller.Session session = null; InputStream in = null; OutputStream out = null; try { session = new PackageInstaller.Session( mInterface.getPackageInstaller().openSession(sessionId)); if (fd != null) { in = new ParcelFileDescriptor.AutoCloseInputStream(fd); } else { in = new SizedInputStream(getRawInputStream(), sizeBytes); } out = session.openWrite(splitName, 0, sizeBytes); int total = 0; byte[] buffer = new byte[1024 * 1024]; int c; while ((c = in.read(buffer)) != -1) { total += c; out.write(buffer, 0, c); if (info.sizeBytes > 0) { final float fraction = ((float) c / (float) info.sizeBytes); session.addProgress(fraction); } } session.fsync(out); session.write(splitName, 0, sizeBytes, fd); if (logSuccess) { pw.println("Success: streamed " + total + " bytes"); pw.println("Success: streamed " + sizeBytes + " bytes"); } return 0; } catch (IOException e) { getErrPrintWriter().println("Error: failed to write; " + e.getMessage()); return 1; } finally { IoUtils.closeQuietly(out); IoUtils.closeQuietly(in); IoUtils.closeQuietly(session); } } Loading Loading
core/java/android/content/pm/IPackageInstallerSession.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -26,9 +26,12 @@ interface IPackageInstallerSession { void addClientProgress(float progress); String[] getNames(); ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes); ParcelFileDescriptor openRead(String name); void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd); void removeSplit(String splitName); void close(); Loading
core/java/android/content/pm/PackageInstaller.java +12 −0 Original line number Diff line number Diff line Loading @@ -829,7 +829,19 @@ public class PackageInstaller { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** {@hide} */ public void write(@NonNull String name, long offsetBytes, long lengthBytes, @NonNull ParcelFileDescriptor fd) throws IOException { try { mSession.write(name, offsetBytes, lengthBytes, fd); } catch (RuntimeException e) { ExceptionUtils.maybeUnwrapIOException(e); throw e; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +52 −4 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ import android.os.RevocableFileDescriptor; import android.os.UserHandle; import android.os.storage.StorageManager; import android.system.ErrnoException; import android.system.Int64Ref; import android.system.Os; import android.system.OsConstants; import android.system.StructStat; Loading Loading @@ -575,14 +576,24 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes) { try { return openWriteInternal(name, offsetBytes, lengthBytes); return doWriteInternal(name, offsetBytes, lengthBytes, null); } catch (IOException e) { throw ExceptionUtils.wrap(e); } } private ParcelFileDescriptor openWriteInternal(String name, long offsetBytes, long lengthBytes) throws IOException { @Override public void write(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor fd) { try { doWriteInternal(name, offsetBytes, lengthBytes, fd); } catch (IOException e) { throw ExceptionUtils.wrap(e); } } private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor incomingFd) throws IOException { // Quick sanity check of state, and allocate a pipe for ourselves. We // then do heavy disk allocation outside the lock, but this open pipe // will block any attempted install transitions. Loading Loading @@ -636,7 +647,44 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Os.lseek(targetFd, offsetBytes, OsConstants.SEEK_SET); } if (incomingFd != null) { switch (Binder.getCallingUid()) { case android.os.Process.SHELL_UID: case android.os.Process.ROOT_UID: break; default: throw new SecurityException("Reverse mode only supported from shell"); } // In "reverse" mode, we're streaming data ourselves from the // incoming FD, which means we never have to hand out our // sensitive internal FD. We still rely on a "bridge" being // inserted above to hold the session active. try { final Int64Ref last = new Int64Ref(0); FileUtils.copy(incomingFd.getFileDescriptor(), targetFd, (long progress) -> { if (params.sizeBytes > 0) { final long delta = progress - last.value; last.value = progress; addClientProgress((float) delta / (float) params.sizeBytes); } }, null, lengthBytes); } finally { IoUtils.closeQuietly(targetFd); IoUtils.closeQuietly(incomingFd); // We're done here, so remove the "bridge" that was holding // the session active. synchronized (mLock) { if (PackageInstaller.ENABLE_REVOCABLE_FD) { mFds.remove(fd); } else { mBridges.remove(bridge); } } } return null; } else if (PackageInstaller.ENABLE_REVOCABLE_FD) { fd.init(mContext, targetFd); return fd.getRevocableFileDescriptor(); } else { Loading
services/core/java/com/android/server/pm/PackageManagerShellCommand.java +13 −42 Original line number Diff line number Diff line Loading @@ -16,6 +16,12 @@ package com.android.server.pm; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; import android.accounts.IAccountManager; import android.app.ActivityManager; import android.app.ActivityManagerInternal; Loading @@ -32,8 +38,10 @@ import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; Loading @@ -41,9 +49,6 @@ import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.pm.VersionedPackage; Loading Loading @@ -73,7 +78,6 @@ import android.util.PrintWriterPrinter; import com.android.internal.content.PackageHelper; import com.android.internal.util.ArrayUtils; import com.android.internal.util.SizedInputStream; import com.android.server.LocalServices; import com.android.server.SystemConfig; Loading @@ -81,9 +85,8 @@ import dalvik.system.DexFile; import libcore.io.IoUtils; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.URISyntaxException; import java.util.ArrayList; Loading @@ -95,12 +98,6 @@ import java.util.WeakHashMap; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; class PackageManagerShellCommand extends ShellCommand { /** Path for streaming APK content */ private static final String STDIN_PATH = "-"; Loading Loading @@ -2213,7 +2210,7 @@ class PackageManagerShellCommand extends ShellCommand { final PrintWriter pw = getOutPrintWriter(); final ParcelFileDescriptor fd; if (STDIN_PATH.equals(inPath)) { fd = null; fd = new ParcelFileDescriptor(getInFileDescriptor()); } else if (inPath != null) { fd = openFileForSystem(inPath, "r"); if (fd == null) { Loading @@ -2225,53 +2222,27 @@ class PackageManagerShellCommand extends ShellCommand { return -1; } } else { fd = null; fd = new ParcelFileDescriptor(getInFileDescriptor()); } if (sizeBytes <= 0) { getErrPrintWriter().println("Error: must specify a APK size"); return 1; } final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId); PackageInstaller.Session session = null; InputStream in = null; OutputStream out = null; try { session = new PackageInstaller.Session( mInterface.getPackageInstaller().openSession(sessionId)); if (fd != null) { in = new ParcelFileDescriptor.AutoCloseInputStream(fd); } else { in = new SizedInputStream(getRawInputStream(), sizeBytes); } out = session.openWrite(splitName, 0, sizeBytes); int total = 0; byte[] buffer = new byte[1024 * 1024]; int c; while ((c = in.read(buffer)) != -1) { total += c; out.write(buffer, 0, c); if (info.sizeBytes > 0) { final float fraction = ((float) c / (float) info.sizeBytes); session.addProgress(fraction); } } session.fsync(out); session.write(splitName, 0, sizeBytes, fd); if (logSuccess) { pw.println("Success: streamed " + total + " bytes"); pw.println("Success: streamed " + sizeBytes + " bytes"); } return 0; } catch (IOException e) { getErrPrintWriter().println("Error: failed to write; " + e.getMessage()); return 1; } finally { IoUtils.closeQuietly(out); IoUtils.closeQuietly(in); IoUtils.closeQuietly(session); } } Loading