PackageInstaller.java revision f174c6e6de6ba863179401aa7b3d55d91ceed707
13a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey/* 23a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Copyright (C) 2014 The Android Open Source Project 33a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * 43a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 53a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * you may not use this file except in compliance with the License. 63a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * You may obtain a copy of the License at 73a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * 83a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 93a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * 103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 123a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * See the License for the specific language governing permissions and 143a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * limitations under the License. 153a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey */ 163a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypackage android.content.pm; 183a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.annotation.NonNull; 2016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.annotation.Nullable; 211cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.annotation.SdkConstant; 221cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport android.annotation.SdkConstant.SdkConstantType; 233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.PackageInstallObserver; 243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.app.PackageUninstallObserver; 25bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport android.os.Bundle; 2678cc340c2de873d6995c283b777476f7237d690fJeff Sharkeyimport android.os.FileBridge; 2716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.os.Handler; 2816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.os.Looper; 2916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport android.os.Message; 303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.ParcelFileDescriptor; 313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeyimport android.os.RemoteException; 32a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport android.util.ExceptionUtils; 333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 34ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkeyimport java.io.Closeable; 35a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkeyimport java.io.IOException; 361cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.io.InputStream; 3778cc340c2de873d6995c283b777476f7237d690fJeff Sharkeyimport java.io.OutputStream; 381cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkeyimport java.security.MessageDigest; 3916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport java.util.ArrayList; 4016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkeyimport java.util.Iterator; 41bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkeyimport java.util.List; 4278cc340c2de873d6995c283b777476f7237d690fJeff Sharkey 436c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey/** 446c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Offers the ability to install, upgrade, and remove applications on the 456c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * device. This includes support for apps packaged either as a single 466c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * "monolithic" APK, or apps packaged as multiple "split" APKs. 476c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * <p> 486c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * An app is delivered for installation through a 496c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * {@link PackageInstaller.Session}, which any app can create. Once the session 506c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * is created, the installer can stream one or more APKs into place until it 516c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * decides to either commit or destroy the session. Committing may require user 526c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * intervention to complete the installation. 536c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * <p> 546c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Sessions can install brand new apps, upgrade existing apps, or add new splits 55da96e137bcc8191c584ada7b5de31eaae92f244fJeff Sharkey * into an existing app. 566c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * <p> 57da96e137bcc8191c584ada7b5de31eaae92f244fJeff Sharkey * Apps packaged as multiple split APKs always consist of a single "base" APK 586c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * (with a {@code null} split name) and zero or more "split" APKs (with unique 596c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * split names). Any subset of these APKs can be installed together, as long as 606c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * the following constraints are met: 616c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * <ul> 626c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * <li>All APKs must have the exact same package name, version code, and signing 636c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * certificates. 646c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * <li>All APKs must have unique split names. 65da96e137bcc8191c584ada7b5de31eaae92f244fJeff Sharkey * <li>All installations must contain a single base APK. 666c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * </ul> 676c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkeypublic class PackageInstaller { 691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * Activity Action: Show details about a particular install session. This 711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * may surface actions such as pause, resume, or cancel. 721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * <p> 731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * This should always be scoped to the installer package that owns the 741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * session. Clients should use {@link InstallSessionInfo#getDetailsIntent()} 751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * to build this intent correctly. 761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * <p> 771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * In some cases, a matching Activity may not exist, so ensure you safeguard 781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * against this. 791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; 821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * An integer session ID. 851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * 861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * @see #ACTION_SESSION_DETAILS 871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID"; 891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final PackageManager mPm; 913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final IPackageInstaller mInstaller; 923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final int mUserId; 933a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private final String mInstallerPackageName; 943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 9516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>(); 9616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 973a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey /** {@hide} */ 98ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey public PackageInstaller(PackageManager pm, IPackageInstaller installer, 99ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey String installerPackageName, int userId) { 1003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mPm = pm; 1013a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mInstaller = installer; 1023a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mInstallerPackageName = installerPackageName; 103ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey mUserId = userId; 1043a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1066c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 1076c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Create a new session using the given parameters, returning a unique ID 1086c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * that represents the session. Once created, the session can be opened 1096c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * multiple times across multiple device boots. 1106c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * <p> 1116c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * The system may automatically destroy sessions that have not been 1126c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * finalized (either committed or abandoned) within a reasonable period of 1136c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * time, typically on the order of a day. 1146c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * 1156c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * @throws IOException if parameters were unsatisfiable, such as lack of 1166c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * disk space or unavailable media. 117f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey * @return positive, non-zero unique ID that represents the created session. 118f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey * This ID remains consistent across device reboots until the 119f174c6e6de6ba863179401aa7b3d55d91ceed707Jeff Sharkey * session is finalized. IDs are not reused during a given boot. 1206c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 12116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public int createSession(@NonNull InstallSessionParams params) throws IOException { 1223a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey try { 12316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return mInstaller.createSession(params, mInstallerPackageName, mUserId); 124a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } catch (RuntimeException e) { 125a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey ExceptionUtils.maybeUnwrapIOException(e); 126a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey throw e; 1273a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } catch (RemoteException e) { 1283a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw e.rethrowAsRuntimeException(); 1293a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1313a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1326c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 13316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Open an existing session to actively perform work. To succeed, the caller 13416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * must be the owner of the install session. 1356c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 13616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public @NonNull Session openSession(int sessionId) { 1373a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey try { 1383a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey return new Session(mInstaller.openSession(sessionId)); 1393a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } catch (RemoteException e) { 1403a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw e.rethrowAsRuntimeException(); 1413a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1423a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1446c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 14516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Return details for a specific session. To succeed, the caller must either 14616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * own this session, or be the current home app. 1476c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 14816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public @Nullable InstallSessionInfo getSessionInfo(int sessionId) { 1493a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey try { 15016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return mInstaller.getSessionInfo(sessionId); 15116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } catch (RemoteException e) { 15216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey throw e.rethrowAsRuntimeException(); 15316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 15416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 15516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 15616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey /** 15716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Return list of all active install sessions, regardless of the installer. 15816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * To succeed, the caller must be the current home app. 15916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey */ 16016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public @NonNull List<InstallSessionInfo> getAllSessions() { 16116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey try { 16216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return mInstaller.getAllSessions(mUserId); 16316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } catch (RemoteException e) { 16416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey throw e.rethrowAsRuntimeException(); 16516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 16616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 16716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 16816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey /** 16916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Return list of all install sessions owned by the calling app. 17016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey */ 17116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public @NonNull List<InstallSessionInfo> getMySessions() { 17216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey try { 17316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return mInstaller.getMySessions(mInstallerPackageName, mUserId); 1743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } catch (RemoteException e) { 1753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw e.rethrowAsRuntimeException(); 1763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1783a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1796c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 1806c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Uninstall the given package, removing it completely from the device. This 1816c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * method is only available to the current "installer of record" for the 1826c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * package. 1836c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 18416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void uninstall(@NonNull String packageName, @NonNull UninstallCallback callback) { 1853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey try { 186bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey mInstaller.uninstall(packageName, 0, 18716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey new UninstallCallbackDelegate(callback).getBinder(), mUserId); 1883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } catch (RemoteException e) { 1893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw e.rethrowAsRuntimeException(); 1903a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1913a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 1923a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 1936c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 1946c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Uninstall only a specific split from the given package. 1956c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * 1966c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * @hide 1976c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 19816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void uninstall(@NonNull String packageName, @NonNull String splitName, 19916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @NonNull UninstallCallback callback) { 2003a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey try { 201bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey mInstaller.uninstallSplit(packageName, splitName, 0, 20216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey new UninstallCallbackDelegate(callback).getBinder(), mUserId); 203bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } catch (RemoteException e) { 204bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey throw e.rethrowAsRuntimeException(); 205bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 206bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 207bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 2086c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 2096c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Events for observing session lifecycle. 2101cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * <p> 2111cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * A typical session lifecycle looks like this: 2121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * <ul> 2131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * <li>An installer creates a session to indicate pending app delivery. All 2141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * install details are available at this point. 2151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * <li>The installer opens the session to deliver APK data. Note that a 2161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * session may be opened and closed multiple times as network connectivity 2171cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * changes. The installer may deliver periodic progress updates. 2181cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * <li>The installer commits or abandons the session, resulting in the 2191cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * session being finished. 2201cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * </ul> 2216c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 22216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public static abstract class SessionCallback { 2236c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 2241cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * New session has been created. Details about the session can be 2251cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * obtained from {@link PackageInstaller#getSessionInfo(int)}. 2266c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 22716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public abstract void onCreated(int sessionId); 2286c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey 2296c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 2301cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * Session has been opened. A session is usually opened when the 2311cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * installer is actively writing data. 2321cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 2331cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public abstract void onOpened(int sessionId); 2341cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2351cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 2366c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Progress for given session has been updated. 2376c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * <p> 2386c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Note that this progress may not directly correspond to the value 23916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * reported by {@link PackageInstaller.Session#setProgress(float)}, as 24016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * the system may carve out a portion of the overall progress to 24116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * represent its own internal installation work. 2426c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 24316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public abstract void onProgressChanged(int sessionId, float progress); 2446c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey 2456c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 2461cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * Session has been closed. 2471cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 2481cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public abstract void onClosed(int sessionId); 2491cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 2501cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 25116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Session has completely finished, either with success or failure. 2526c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 25316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public abstract void onFinished(int sessionId, boolean success); 25416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 25516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 25616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey /** {@hide} */ 25716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements 25816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey Handler.Callback { 25916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private static final int MSG_SESSION_CREATED = 1; 2601cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_OPENED = 2; 2611cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_PROGRESS_CHANGED = 3; 2621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_CLOSED = 4; 2631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey private static final int MSG_SESSION_FINISHED = 5; 26416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 26516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final SessionCallback mCallback; 26616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final Handler mHandler; 26716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 26816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public SessionCallbackDelegate(SessionCallback callback, Looper looper) { 26916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallback = callback; 27016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mHandler = new Handler(looper, this); 27116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 27216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 27316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 27416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public boolean handleMessage(Message msg) { 27516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey switch (msg.what) { 27616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey case MSG_SESSION_CREATED: 27716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallback.onCreated(msg.arg1); 27816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return true; 2791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_OPENED: 2801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallback.onOpened(msg.arg1); 2811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return true; 28216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey case MSG_SESSION_PROGRESS_CHANGED: 28316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallback.onProgressChanged(msg.arg1, (float) msg.obj); 28416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return true; 2851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey case MSG_SESSION_CLOSED: 2861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mCallback.onClosed(msg.arg1); 2871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return true; 28816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey case MSG_SESSION_FINISHED: 28916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mCallback.onFinished(msg.arg1, msg.arg2 != 0); 29016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return true; 29116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 29216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey return false; 29316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 29416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 29516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 29616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void onSessionCreated(int sessionId) { 29716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget(); 29816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 29916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 30016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 3011cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void onSessionOpened(int sessionId) { 3021cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mHandler.obtainMessage(MSG_SESSION_OPENED, sessionId, 0).sendToTarget(); 3031cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3041cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3051cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey @Override 30616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void onSessionProgressChanged(int sessionId, float progress) { 30716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress) 30816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey .sendToTarget(); 30916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 31016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 31116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey @Override 3121cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public void onSessionClosed(int sessionId) { 3131cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey mHandler.obtainMessage(MSG_SESSION_CLOSED, sessionId, 0).sendToTarget(); 3141cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 3151cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 3161cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey @Override 31716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void onSessionFinished(int sessionId, boolean success) { 31816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0) 31916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey .sendToTarget(); 32016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 321bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 322bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 3236c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 32416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Register to watch for session lifecycle events. To succeed, the caller 32516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * must be the current home app. 3266c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 32716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void addSessionCallback(@NonNull SessionCallback callback) { 32816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey addSessionCallback(callback, new Handler()); 32916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 33016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 33116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey /** 33216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Register to watch for session lifecycle events. To succeed, the caller 33316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * must be the current home app. 33416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * 33516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * @param handler to dispatch callback events through, otherwise uses 33616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * calling thread. 33716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey */ 33816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { 33916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mDelegates) { 34016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback, 34116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey handler.getLooper()); 34216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey try { 34316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mInstaller.registerCallback(delegate, mUserId); 34416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } catch (RemoteException e) { 34516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey throw e.rethrowAsRuntimeException(); 34616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 34716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mDelegates.add(delegate); 348bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 349bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 350bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 3516c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 35216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Unregister an existing callback. 3536c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 35416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void removeSessionCallback(@NonNull SessionCallback callback) { 35516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey synchronized (mDelegates) { 35616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) { 35716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final SessionCallbackDelegate delegate = i.next(); 35816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (delegate.mCallback == callback) { 35916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey try { 36016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mInstaller.unregisterCallback(delegate); 36116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } catch (RemoteException e) { 36216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey throw e.rethrowAsRuntimeException(); 36316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 36416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey i.remove(); 36516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 36616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 3673a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3683a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3693a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 3703a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey /** 3713a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * An installation that is being actively staged. For an install to succeed, 3723a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * all existing and new packages must have identical package names, version 3733a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * codes, and signing certificates. 3743a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * <p> 3753a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * A session may contain any number of split packages. If the application 3763a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * does not yet exist, this session must include a base package. 3773a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey * <p> 37816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * If an APK included in this session is already defined by the existing 37916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * installation (for example, the same split name), the APK in this session 38016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * will replace the existing APK. 3813a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey */ 382ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey public static class Session implements Closeable { 3833a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey private IPackageInstallerSession mSession; 3843a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 3853a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey /** {@hide} */ 3863a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public Session(IPackageInstallerSession session) { 3873a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey mSession = session; 3883a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 3893a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 3906c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 39116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Set current progress. Valid values are anywhere between 0 and 1. 3926c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 39316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void setProgress(float progress) { 3943a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey try { 395a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mSession.setClientProgress(progress); 396a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } catch (RemoteException e) { 397a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey throw e.rethrowAsRuntimeException(); 398a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 399a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 400a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 401a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey /** {@hide} */ 40216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void addProgress(float progress) { 403a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey try { 404a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey mSession.addClientProgress(progress); 4053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } catch (RemoteException e) { 4063a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw e.rethrowAsRuntimeException(); 4073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 41078cc340c2de873d6995c283b777476f7237d690fJeff Sharkey /** 41116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Open a stream to write an APK file into the session. 41216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * <p> 41316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * The returned stream will start writing data at the requested offset 41416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * in the underlying file, which can be used to resume a partially 41516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * written file. If a valid file length is specified, the system will 41616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * preallocate the underlying disk space to optimize placement on disk. 41716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * It's strongly recommended to provide a valid file length when known. 41816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * <p> 41916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * You can write data into the returned stream, optionally call 42016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * {@link #fsync(OutputStream)} as needed to ensure bytes have been 42116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * persisted to disk, and then close when finished. All streams must be 42216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * closed before calling {@link #commit(CommitCallback)}. 42316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * 42416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * @param name arbitrary, unique name of your choosing to identify the 42516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * APK being written. You can open a file again for 42616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * additional writes (such as after a reboot) by using the 42716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * same name. This name is only meaningful within the context 42816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * of a single install session. 42916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * @param offsetBytes offset into the file to begin writing at, or 0 to 43016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * start at the beginning of the file. 43116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * @param lengthBytes total size of the file being written, used to 43216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * preallocate the underlying disk space, or -1 if unknown. 43378cc340c2de873d6995c283b777476f7237d690fJeff Sharkey */ 43416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes, 43516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey long lengthBytes) throws IOException { 4363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey try { 43716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final ParcelFileDescriptor clientSocket = mSession.openWrite(name, 43878cc340c2de873d6995c283b777476f7237d690fJeff Sharkey offsetBytes, lengthBytes); 43978cc340c2de873d6995c283b777476f7237d690fJeff Sharkey return new FileBridge.FileBridgeOutputStream(clientSocket.getFileDescriptor()); 440a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } catch (RuntimeException e) { 441a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey ExceptionUtils.maybeUnwrapIOException(e); 442a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey throw e; 4433a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } catch (RemoteException e) { 4441cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throw e.rethrowAsRuntimeException(); 4453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4463a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 4473a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 4486c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 4496c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Ensure that any outstanding data for given stream has been committed 4506c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * to disk. This is only valid for streams returned from 4516c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * {@link #openWrite(String, long, long)}. 4526c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 45316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void fsync(@NonNull OutputStream out) throws IOException { 454a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey if (out instanceof FileBridge.FileBridgeOutputStream) { 455a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey ((FileBridge.FileBridgeOutputStream) out).fsync(); 456a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } else { 457a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey throw new IllegalArgumentException("Unrecognized stream"); 458a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 459a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey } 460a10311434778ea1be1621c2251c0c8c2966f337bJeff Sharkey 4616c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 4621cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * List all APK names contained in this session. 4631cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * <p> 4641cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * This returns all names which have been previously written through 4651cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * {@link #openWrite(String, long, long)} as part of this session. 4661cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 4671cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public @NonNull String[] list() { 4681cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 4691cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return mSession.list(); 4701cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (RemoteException e) { 4711cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throw e.rethrowAsRuntimeException(); 4721cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4731cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4741cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4751cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 4761cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * Open a stream to read an APK file from the session. 4771cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * <p> 4781cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * This is only valid for names which have been previously written 4791cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * through {@link #openWrite(String, long, long)} as part of this 4801cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * session. For example, this stream may be used to calculate a 4811cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey * {@link MessageDigest} of a written APK before committing. 4821cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey */ 4831cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey public @NonNull InputStream openRead(@NonNull String name) throws IOException { 4841cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey try { 4851cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey final ParcelFileDescriptor pfd = mSession.openRead(name); 4861cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey return new ParcelFileDescriptor.AutoCloseInputStream(pfd); 4871cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (RuntimeException e) { 4881cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey ExceptionUtils.maybeUnwrapIOException(e); 4891cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throw e; 4901cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } catch (RemoteException e) { 4911cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey throw e.rethrowAsRuntimeException(); 4921cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4931cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey } 4941cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey 4951cb2d0d4bba387665128c62c342e59103ea4be26Jeff Sharkey /** 4966c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Attempt to commit everything staged in this session. This may require 4976c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * user intervention, and so it may not happen immediately. The final 4986c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * result of the commit will be reported through the given callback. 4996c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * <p> 5006c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Once this method is called, no additional mutations may be performed 5016c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * on the session. If the device reboots before the session has been 5026c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * finalized, you may commit the session again. 5036c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 50416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void commit(@NonNull CommitCallback callback) { 5053a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey try { 50616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mSession.commit(new CommitCallbackDelegate(callback).getBinder()); 5073a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } catch (RemoteException e) { 5083a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw e.rethrowAsRuntimeException(); 5093a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5103a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5113a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 5126c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 5136c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Release this session object. You can open the session again if it 5146c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * hasn't been finalized. 5156c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 516ec55ef0934b8e0d1bb705434947de817f7be57f1Jeff Sharkey @Override 5173a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey public void close() { 51816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey try { 51916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mSession.close(); 52016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } catch (RemoteException e) { 52116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey throw e.rethrowAsRuntimeException(); 52216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 5233a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5243a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey 5256c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 52616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Completely abandon this session, destroying all staged data and 52716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * rendering it invalid. 5286c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 52916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public void abandon() { 5303a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey try { 53116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey mSession.abandon(); 5323a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } catch (RemoteException e) { 5333a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey throw e.rethrowAsRuntimeException(); 5343a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5353a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 5363a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey } 537bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 5386c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 5396c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Final result of an uninstall request. 5406c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 54116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public static abstract class UninstallCallback { 542bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey public abstract void onSuccess(); 543bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey public abstract void onFailure(String msg); 544bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 545bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 5466c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** {@hide} */ 54716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private static class UninstallCallbackDelegate extends PackageUninstallObserver { 54816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private final UninstallCallback target; 549bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 55016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public UninstallCallbackDelegate(UninstallCallback target) { 551bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey this.target = target; 552bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 553bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 554bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey @Override 555bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey public void onUninstallFinished(String basePackageName, int returnCode) { 55616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (returnCode == PackageManager.DELETE_SUCCEEDED) { 55716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey target.onSuccess(); 55816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } else { 55916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final String msg = PackageManager.deleteStatusToString(returnCode); 56016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey target.onFailure(msg); 561bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 562bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 563bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 564bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 5656c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 5666c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * Final result of a session commit request. 5676c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 56816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public static abstract class CommitCallback { 5696c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** 57016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * Generic unknown failure. The system will always try to provide a more 57116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * specific failure reason, but in some rare cases this may be 57216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * delivered. 5736c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey */ 57416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public static final int FAILURE_UNKNOWN = 0; 575bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 576bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey /** 577bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * One or more of the APKs included in the session was invalid. For 578bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * example, they might be malformed, corrupt, incorrectly signed, 579bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * mismatched, etc. The installer may want to try downloading and 580bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * installing again. 581bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey */ 58216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public static final int FAILURE_INVALID = 1; 583bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 584bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey /** 5856c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * This install session conflicts (or is inconsistent with) with another 5866c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * package already installed on the device. For example, an existing 5876c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * permission, incompatible certificates, etc. The user may be able to 5886c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey * uninstall another app to fix the issue. 58916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * <p> 59016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * The extras bundle may contain {@link #EXTRA_PACKAGE_NAME} if one 59116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * specific package was identified as the cause of the conflict. If 59216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey * unknown, or multiple packages, the extra may be {@code null}. 593bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey */ 59416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public static final int FAILURE_CONFLICT = 2; 595bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 596bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey /** 597bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * This install session failed due to storage issues. For example, 598bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * the device may be running low on space, or the required external 599bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * media may be unavailable. The user may be able to help free space 600bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * or insert the correct media. 601bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey */ 60216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public static final int FAILURE_STORAGE = 3; 603bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 604bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey /** 605bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * This install session is fundamentally incompatible with this 606bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * device. For example, the package may require a hardware feature 607bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * that doesn't exist, it may be missing native code for the device 608bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * ABI, or it requires a newer SDK version, etc. This install would 609bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey * never succeed. 610bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey */ 61116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public static final int FAILURE_INCOMPATIBLE = 4; 61216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 61316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public static final String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; 61416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 61516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public abstract void onSuccess(); 61616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public abstract void onFailure(int failureReason, String msg, Bundle extras); 617bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 618bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 6196c833e07a05c48ca60ee4d72421bf8b1e78dc710Jeff Sharkey /** {@hide} */ 62016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private static class CommitCallbackDelegate extends PackageInstallObserver { 62116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey private final CommitCallback target; 622bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 62316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey public CommitCallbackDelegate(CommitCallback target) { 624bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey this.target = target; 625bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 626bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey 627bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey @Override 628bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey public void packageInstalled(String basePackageName, Bundle extras, int returnCode, 629bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey String msg) { 63016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (returnCode == PackageManager.INSTALL_SUCCEEDED) { 63116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey target.onSuccess(); 63216c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } else { 63316c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey final int failureReason = PackageManager.installStatusToFailureReason(returnCode); 63416c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey msg = PackageManager.installStatusToString(returnCode) + ": " + msg; 63516c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 63616c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey if (extras != null) { 63716c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey extras.putString(CommitCallback.EXTRA_PACKAGE_NAME, 63816c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey extras.getString(PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE)); 63916c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey } 64016c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey 64116c8e3f49497b6046972ae650772f65768366be8Jeff Sharkey target.onFailure(failureReason, msg, extras); 642bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 643bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 644bb580670350b76fa2fcc5ee873f99b7970759cbfJeff Sharkey } 6453a44f3f1b446315ef894e01d2ab9b5388c2bd8c4Jeff Sharkey} 646