Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1cb2d0d4 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Persist install sessions, more lifecycle.

To resume install sessions across device boots, persist session
details and read at boot.  Drop sessions older than 3 days, since
they're probably buggy installers.

Add session callback lifecycle around open/close to give home apps
details about active installs.  Also give them a well-known intent
to show session details.

Extend Session to list staged APKs and open them read-only, giving
installers a mechanism to verify delivered bits, for example using
MessageDigest, before committing.

Switch to generating random session IDs instead of sequential.

Defensively resize app icons if too large.  Reject runaway
installers when they have too many active sessions.

Bug: 16514389
Change-Id: I66c2266cb82fc72b1eb980a615566773f4290498
parent 874bcd82
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -8515,9 +8515,11 @@ package android.content.pm {
    method public android.graphics.Bitmap getAppIcon();
    method public java.lang.CharSequence getAppLabel();
    method public java.lang.String getAppPackageName();
    method public android.content.Intent getDetailsIntent();
    method public java.lang.String getInstallerPackageName();
    method public float getProgress();
    method public int getSessionId();
    method public boolean isOpen();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
  }
@@ -8531,7 +8533,6 @@ package android.content.pm {
    method public void setInstallLocation(int);
    method public void setOriginatingUri(android.net.Uri);
    method public void setReferrerUri(android.net.Uri);
    method public void setSignatures(android.content.pm.Signature[]);
    method public void setSize(long);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
@@ -8647,6 +8648,8 @@ package android.content.pm {
    method public android.content.pm.PackageInstaller.Session openSession(int);
    method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
    method public void uninstall(java.lang.String, android.content.pm.PackageInstaller.UninstallCallback);
    field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
    field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
  }
  public static abstract class PackageInstaller.CommitCallback {
@@ -8666,14 +8669,18 @@ package android.content.pm {
    method public void close();
    method public void commit(android.content.pm.PackageInstaller.CommitCallback);
    method public void fsync(java.io.OutputStream) throws java.io.IOException;
    method public java.lang.String[] list();
    method public java.io.InputStream openRead(java.lang.String) throws java.io.IOException;
    method public java.io.OutputStream openWrite(java.lang.String, long, long) throws java.io.IOException;
    method public void setProgress(float);
  }
  public static abstract class PackageInstaller.SessionCallback {
    ctor public PackageInstaller.SessionCallback();
    method public abstract void onClosed(int);
    method public abstract void onCreated(int);
    method public abstract void onFinished(int, boolean);
    method public abstract void onOpened(int);
    method public abstract void onProgressChanged(int, float);
  }
+14 −8
Original line number Diff line number Diff line
@@ -59,7 +59,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.SizedInputStream;

import libcore.io.IoUtils;
import libcore.io.Streams;

import java.io.File;
import java.io.FileDescriptor;
@@ -1068,6 +1067,8 @@ public final class Pm {
            }
        }

        final InstallSessionInfo info = mInstaller.getSessionInfo(sessionId);

        PackageInstaller.Session session = null;
        InputStream in = null;
        OutputStream out = null;
@@ -1081,16 +1082,21 @@ public final class Pm {
            }
            out = session.openWrite(splitName, 0, sizeBytes);

            final int n = Streams.copy(in, out);
            session.fsync(out);
            int total = 0;
            byte[] buffer = new byte[65536];
            int c;
            while ((c = in.read(buffer)) != -1) {
                total += c;
                out.write(buffer, 0, c);

            final InstallSessionInfo info = mInstaller.getSessionInfo(sessionId);
                if (info.sizeBytes > 0) {
                final float fraction = ((float) n / (float) info.sizeBytes);
                    final float fraction = ((float) c / (float) info.sizeBytes);
                    session.addProgress(fraction);
                }
            }
            session.fsync(out);

            System.out.println("Success: streamed " + n + " bytes");
            System.out.println("Success: streamed " + total + " bytes");
        } finally {
            IoUtils.closeQuietly(out);
            IoUtils.closeQuietly(in);
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package android.content.pm;
/** {@hide} */
oneway interface IPackageInstallerCallback {
    void onSessionCreated(int sessionId);
    void onSessionOpened(int sessionId);
    void onSessionProgressChanged(int sessionId, float progress);
    void onSessionClosed(int sessionId);
    void onSessionFinished(int sessionId, boolean success);
}
+2 −0
Original line number Diff line number Diff line
@@ -24,7 +24,9 @@ interface IPackageInstallerSession {
    void setClientProgress(float progress);
    void addClientProgress(float progress);

    String[] list();
    ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes);
    ParcelFileDescriptor openRead(String name);

    void close();
    void commit(in IPackageInstallObserver2 observer);
+30 −0
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@

package android.content.pm;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,6 +34,8 @@ public class InstallSessionInfo implements Parcelable {
    public String installerPackageName;
    /** {@hide} */
    public float progress;
    /** {@hide} */
    public boolean open;

    /** {@hide} */
    public int mode;
@@ -53,6 +57,7 @@ public class InstallSessionInfo implements Parcelable {
        sessionId = source.readInt();
        installerPackageName = source.readString();
        progress = source.readFloat();
        open = source.readInt() != 0;

        mode = source.readInt();
        sizeBytes = source.readLong();
@@ -87,6 +92,13 @@ public class InstallSessionInfo implements Parcelable {
        return progress;
    }

    /**
     * Return if this session is currently open.
     */
    public boolean isOpen() {
        return open;
    }

    /**
     * Return the package name this session is working with. May be {@code null}
     * if unknown.
@@ -111,6 +123,23 @@ public class InstallSessionInfo implements Parcelable {
        return appLabel;
    }

    /**
     * Return an Intent that can be started to view details about this install
     * session. This may surface actions such as pause, resume, or cancel.
     * <p>
     * In some cases, a matching Activity may not exist, so ensure you safeguard
     * against this.
     *
     * @see PackageInstaller#ACTION_SESSION_DETAILS
     */
    public @Nullable Intent getDetailsIntent() {
        final Intent intent = new Intent(PackageInstaller.ACTION_SESSION_DETAILS);
        intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
        intent.setPackage(installerPackageName);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        return intent;
    }

    @Override
    public int describeContents() {
        return 0;
@@ -121,6 +150,7 @@ public class InstallSessionInfo implements Parcelable {
        dest.writeInt(sessionId);
        dest.writeString(installerPackageName);
        dest.writeFloat(progress);
        dest.writeInt(open ? 1 : 0);

        dest.writeInt(mode);
        dest.writeLong(sizeBytes);
Loading