blob: b37e2680605b5fb6c92e42dce8e71125f97f06c8 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.rollback;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.rollback.RollbackInfo;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.ParseException;
import java.time.Instant;
import java.util.ArrayList;
/**
* Information about a rollback available for a set of atomically installed
* packages.
*/
class RollbackData {
@IntDef(flag = true, prefix = { "ROLLBACK_STATE_" }, value = {
ROLLBACK_STATE_ENABLING,
ROLLBACK_STATE_AVAILABLE,
ROLLBACK_STATE_COMMITTED,
})
@Retention(RetentionPolicy.SOURCE)
@interface RollbackState {}
/**
* The rollback is in the process of being enabled. It is not yet
* available for use.
*/
static final int ROLLBACK_STATE_ENABLING = 0;
/**
* The rollback is currently available.
*/
static final int ROLLBACK_STATE_AVAILABLE = 1;
/**
* The rollback has been committed.
*/
static final int ROLLBACK_STATE_COMMITTED = 3;
/**
* The rollback info for this rollback.
*/
public final RollbackInfo info;
/**
* The directory where the rollback data is stored.
*/
public final File backupDir;
/**
* The time when the upgrade occurred, for purposes of expiring
* rollback data.
*
* The timestamp is not applicable for all rollback states, but we make
* sure to keep it non-null to avoid potential errors there.
*/
public @NonNull Instant timestamp;
/**
* The session ID for the staged session if this rollback data represents a staged session,
* {@code -1} otherwise.
*/
public final int stagedSessionId;
/**
* The current state of the rollback.
* ENABLING, AVAILABLE, or COMMITTED.
*/
public @RollbackState int state;
/**
* The id of the post-reboot apk session for a staged install, if any.
*/
public int apkSessionId = -1;
/**
* True if we are expecting the package manager to call restoreUserData
* for this rollback because it has just been committed but the rollback
* has not yet been fully applied.
*/
// NOTE: All accesses to this field are from the RollbackManager handler thread.
public boolean restoreUserDataInProgress = false;
/**
* Constructs a new, empty RollbackData instance.
*
* @param rollbackId the id of the rollback.
* @param backupDir the directory where the rollback data is stored.
* @param stagedSessionId the session id if this is a staged rollback, -1 otherwise.
*/
RollbackData(int rollbackId, File backupDir, int stagedSessionId) {
this.info = new RollbackInfo(rollbackId,
/* packages */ new ArrayList<>(),
/* isStaged */ stagedSessionId != -1,
/* causePackages */ new ArrayList<>(),
/* committedSessionId */ -1);
this.backupDir = backupDir;
this.stagedSessionId = stagedSessionId;
this.state = ROLLBACK_STATE_ENABLING;
this.timestamp = Instant.now();
}
/**
* Constructs a RollbackData instance with full rollback data information.
*/
RollbackData(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
@RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress) {
this.info = info;
this.backupDir = backupDir;
this.timestamp = timestamp;
this.stagedSessionId = stagedSessionId;
this.state = state;
this.apkSessionId = apkSessionId;
this.restoreUserDataInProgress = restoreUserDataInProgress;
}
/**
* Whether the rollback is for rollback of a staged install.
*/
public boolean isStaged() {
return info.isStaged();
}
static String rollbackStateToString(@RollbackState int state) {
switch (state) {
case RollbackData.ROLLBACK_STATE_ENABLING: return "enabling";
case RollbackData.ROLLBACK_STATE_AVAILABLE: return "available";
case RollbackData.ROLLBACK_STATE_COMMITTED: return "committed";
}
throw new AssertionError("Invalid rollback state: " + state);
}
static @RollbackState int rollbackStateFromString(String state)
throws ParseException {
switch (state) {
case "enabling": return RollbackData.ROLLBACK_STATE_ENABLING;
case "available": return RollbackData.ROLLBACK_STATE_AVAILABLE;
case "committed": return RollbackData.ROLLBACK_STATE_COMMITTED;
}
throw new ParseException("Invalid rollback state: " + state, 0);
}
public String getStateAsString() {
return rollbackStateToString(state);
}
}