INSTALL_FAILED_ABORTED
程序员文章站
2024-03-13 09:56:21
...
android 安装流程.报错
INSTALL_FAILED_ABORTED: Session was abandoned
网上查得到安装流程中 在安装最后会使用
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
岂不知,这句话就是导致这个报错的元凶
正常流程中,不需要使用这句话.只有异常处理中才要用这句话
我们可以从源码中看一下:
client端
官方入口
frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
/**
* Send the package to the package installer and then register a event result observer that
* will call {@link #launchFinishBasedOnResult(int, int, String)}
*/
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
volatile boolean isDone;
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
session = 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();
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) {
float fraction = ((float) numRead / (float) sizeBytes);
session.addProgress(fraction);
}
}
}
}
return session;
} catch (IOException | SecurityException e) {
Log.e(LOG_TAG, "Could not write package", e);
session.close();
return null;
} finally {
synchronized (this) {
isDone = true;
notifyAll();
}
}
}
@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) {
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntent.setPackage(getPackageName());
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
if (!isCancelled()) {
launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}
frameworks/base/core/java/android/content/pm/PackageInstaller.java
/**
* Completely abandon this session, destroying all staged data and
* rendering it invalid. Abandoned sessions will be reported to
* {@link SessionCallback} listeners as failures. This is equivalent to
* opening the session and calling {@link Session#abandon()}.
* 完全放弃此会话,破坏所有暂存的数据并使之无效。 放弃的会话将作为失败报告给{@link
* SessionCallback}侦听器。 这等效于打开会话并调用{@link Session#abandon()}。
*/
public void abandon() {
try {
mSession.abandon();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
service端
真正执行的地方
frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
@Override
public void abandon() {
if (hasParentSessionId()) {
throw new IllegalStateException(
"Session " + sessionId + " is a child of multi-package session "
+ mParentSessionId + " and may not be abandoned directly.");
}
List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
synchronized (mLock) {
if (params.isStaged && mDestroyed) {
// If a user abandons staged session in an unsafe state, then system will try to
// abandon the destroyed staged session when it is safe on behalf of the user.
assertCallerIsOwnerOrRootOrSystemLocked();
} else {
assertCallerIsOwnerOrRootLocked();
}
if (isStagedAndInTerminalState()) {
// We keep the session in the database if it's in a finalized state. It will be
// removed by PackageInstallerService when the last update time is old enough.
// Also, in such cases cleanStageDir() has already been executed so no need to
// do it now.
return;
}
if (mCommitted && params.isStaged) {
mDestroyed = true;
if (!mStagingManager.abortCommittedSessionLocked(this)) {
// Do not clean up the staged session from system. It is not safe yet.
mCallback.onStagedSessionChanged(this);
return;
}
cleanStageDir(childSessions);
}
if (mRelinquished) {
Slog.d(TAG, "Ignoring abandon after commit relinquished control");
return;
}
destroyInternal();
}
dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
}