am 46e462a3: Merge change I852f8e46 into eclair

Merge commit '46e462a380f90ed8101f9ac3f950a3c702772842' into eclair-plus-aosp

* commit '46e462a380f90ed8101f9ac3f950a3c702772842':
  Only re-initialize backup state if @pm@ metadata is missing,
This commit is contained in:
Dan Egnor
2009-09-30 14:57:30 -07:00
committed by Android Git Automerger

View File

@@ -205,11 +205,9 @@ class BackupManagerService extends IBackupManager.Stub {
File mDataDir; File mDataDir;
File mJournalDir; File mJournalDir;
File mJournal; File mJournal;
RandomAccessFile mJournalStream;
// Keep a log of all the apps we've ever backed up // Keep a log of all the apps we've ever backed up
private File mEverStored; private File mEverStored;
private RandomAccessFile mEverStoredStream;
HashSet<String> mEverStoredApps = new HashSet<String>(); HashSet<String> mEverStoredApps = new HashSet<String>();
// Persistently track the need to do a full init // Persistently track the need to do a full init
@@ -257,7 +255,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Set up the backup-request journaling // Set up the backup-request journaling
mJournalDir = new File(mBaseStateDir, "pending"); mJournalDir = new File(mBaseStateDir, "pending");
mJournalDir.mkdirs(); // creates mBaseStateDir along the way mJournalDir.mkdirs(); // creates mBaseStateDir along the way
makeJournalLocked(); // okay because no other threads are running yet mJournal = null; // will be created on first use
// Set up the various sorts of package tracking we do // Set up the various sorts of package tracking we do
initPackageTracking(); initPackageTracking();
@@ -369,56 +367,51 @@ class BackupManagerService extends IBackupManager.Stub {
// this log, we sanity-check its contents here and reconstruct it. // this log, we sanity-check its contents here and reconstruct it.
mEverStored = new File(mBaseStateDir, "processed"); mEverStored = new File(mBaseStateDir, "processed");
File tempProcessedFile = new File(mBaseStateDir, "processed.new"); File tempProcessedFile = new File(mBaseStateDir, "processed.new");
try {
// If there are previous contents, parse them out then start a new
// file to continue the recordkeeping.
if (mEverStored.exists()) {
RandomAccessFile temp = new RandomAccessFile(tempProcessedFile, "rw");
mEverStoredStream = new RandomAccessFile(mEverStored, "r");
// parse its existing contents
mEverStoredStream.seek(0);
temp.seek(0);
try {
while (true) {
PackageInfo info;
String pkg = mEverStoredStream.readUTF();
try {
info = mPackageManager.getPackageInfo(pkg, 0);
mEverStoredApps.add(pkg);
temp.writeUTF(pkg);
if (DEBUG) Log.v(TAG, " + " + pkg);
} catch (NameNotFoundException e) {
// nope, this package was uninstalled; don't include it
if (DEBUG) Log.v(TAG, " - " + pkg);
}
}
} catch (EOFException e) {
// now we're at EOF
}
// Once we've rewritten the backup history log, atomically replace the
// old one with the new one then reopen the file for continuing use.
temp.close();
mEverStoredStream.close();
tempProcessedFile.renameTo(mEverStored);
}
// This will create the file if it doesn't exist
mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
mEverStoredStream.seek(mEverStoredStream.length());
} catch (IOException e) {
Log.e(TAG, "Unable to open known-stored file!");
mEverStoredStream = null;
}
// If we were in the middle of removing something from the ever-backed-up // If we were in the middle of removing something from the ever-backed-up
// file, there might be a transient "processed.new" file still present. // file, there might be a transient "processed.new" file still present.
// We've reconstructed a coherent state at this point though, so we can // Ignore it -- we'll validate "processed" against the current package set.
// safely discard that file now.
if (tempProcessedFile.exists()) { if (tempProcessedFile.exists()) {
tempProcessedFile.delete(); tempProcessedFile.delete();
} }
// If there are previous contents, parse them out then start a new
// file to continue the recordkeeping.
if (mEverStored.exists()) {
RandomAccessFile temp = null;
RandomAccessFile in = null;
try {
temp = new RandomAccessFile(tempProcessedFile, "rws");
in = new RandomAccessFile(mEverStored, "r");
while (true) {
PackageInfo info;
String pkg = in.readUTF();
try {
info = mPackageManager.getPackageInfo(pkg, 0);
mEverStoredApps.add(pkg);
temp.writeUTF(pkg);
if (DEBUG) Log.v(TAG, " + " + pkg);
} catch (NameNotFoundException e) {
// nope, this package was uninstalled; don't include it
if (DEBUG) Log.v(TAG, " - " + pkg);
}
}
} catch (EOFException e) {
// Once we've rewritten the backup history log, atomically replace the
// old one with the new one then reopen the file for continuing use.
if (!tempProcessedFile.renameTo(mEverStored)) {
Log.e(TAG, "Error renaming " + tempProcessedFile + " to " + mEverStored);
}
} catch (IOException e) {
Log.e(TAG, "Error in processed file", e);
} finally {
try { if (temp != null) temp.close(); } catch (IOException e) {}
try { if (in != null) in.close(); } catch (IOException e) {}
}
}
// Register for broadcasts about package install, etc., so we can // Register for broadcasts about package install, etc., so we can
// update the provider list. // update the provider list.
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
@@ -428,41 +421,29 @@ class BackupManagerService extends IBackupManager.Stub {
mContext.registerReceiver(mBroadcastReceiver, filter); mContext.registerReceiver(mBroadcastReceiver, filter);
} }
private void makeJournalLocked() {
try {
mJournal = File.createTempFile("journal", null, mJournalDir);
mJournalStream = new RandomAccessFile(mJournal, "rwd");
} catch (IOException e) {
Log.e(TAG, "Unable to write backup journals");
mJournal = null;
mJournalStream = null;
}
}
private void parseLeftoverJournals() { private void parseLeftoverJournals() {
if (mJournal != null) { for (File f : mJournalDir.listFiles()) {
File[] allJournals = mJournalDir.listFiles(); if (mJournal == null || f.compareTo(mJournal) != 0) {
for (File f : allJournals) { // This isn't the current journal, so it must be a leftover. Read
if (f.compareTo(mJournal) != 0) { // out the package names mentioned there and schedule them for
// This isn't the current journal, so it must be a leftover. Read // backup.
// out the package names mentioned there and schedule them for RandomAccessFile in = null;
// backup. try {
try { Log.i(TAG, "Found stale backup journal, scheduling:");
Log.i(TAG, "Found stale backup journal, scheduling:"); in = new RandomAccessFile(f, "r");
RandomAccessFile in = new RandomAccessFile(f, "r"); while (true) {
while (true) { String packageName = in.readUTF();
String packageName = in.readUTF(); Log.i(TAG, " + " + packageName);
Log.i(TAG, " + " + packageName); dataChanged(packageName);
dataChanged(packageName);
}
} catch (EOFException e) {
// no more data; we're done
} catch (Exception e) {
// can't read it or other error; just skip it
} finally {
// close/delete the file
f.delete();
} }
} catch (EOFException e) {
// no more data; we're done
} catch (Exception e) {
Log.e(TAG, "Can't read " + f, e);
} finally {
// close/delete the file
try { if (in != null) in.close(); } catch (IOException e) {}
f.delete();
} }
} }
} }
@@ -505,19 +486,8 @@ class BackupManagerService extends IBackupManager.Stub {
void resetBackupState(File stateFileDir) { void resetBackupState(File stateFileDir) {
synchronized (mQueueLock) { synchronized (mQueueLock) {
// Wipe the "what we've ever backed up" tracking // Wipe the "what we've ever backed up" tracking
try {
// close the ever-stored journal...
if (mEverStoredStream != null) {
mEverStoredStream.close();
}
// ... so we can delete it and start over
mEverStored.delete();
mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
} catch (IOException e) {
Log.e(TAG, "Unable to open known-stored file!");
mEverStoredStream = null;
}
mEverStoredApps.clear(); mEverStoredApps.clear();
mEverStored.delete();
// Remove all the state files // Remove all the state files
for (File sf : stateFileDir.listFiles()) { for (File sf : stateFileDir.listFiles()) {
@@ -533,11 +503,7 @@ class BackupManagerService extends IBackupManager.Stub {
int uid = mBackupParticipants.keyAt(i); int uid = mBackupParticipants.keyAt(i);
HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i); HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
for (ApplicationInfo app: participants) { for (ApplicationInfo app: participants) {
try { dataChanged(app.packageName);
dataChanged(app.packageName);
} catch (RemoteException e) {
// can't happen; we're in the same process
}
} }
} }
} }
@@ -652,7 +618,6 @@ class BackupManagerService extends IBackupManager.Stub {
// snapshot the pending-backup set and work on that // snapshot the pending-backup set and work on that
ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>(); ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
File oldJournal = mJournal;
synchronized (mQueueLock) { synchronized (mQueueLock) {
// Do we have any work to do? // Do we have any work to do?
if (mPendingBackups.size() > 0) { if (mPendingBackups.size() > 0) {
@@ -663,14 +628,8 @@ class BackupManagerService extends IBackupManager.Stub {
mPendingBackups.clear(); mPendingBackups.clear();
// Start a new backup-queue journal file too // Start a new backup-queue journal file too
if (mJournalStream != null) { File oldJournal = mJournal;
try { mJournal = null;
mJournalStream.close();
} catch (IOException e) {
// don't need to do anything
}
makeJournalLocked();
}
// At this point, we have started a new journal file, and the old // At this point, we have started a new journal file, and the old
// file identity is being passed to the backup processing thread. // file identity is being passed to the backup processing thread.
@@ -763,11 +722,7 @@ class BackupManagerService extends IBackupManager.Stub {
if (!mEverStoredApps.contains(pkg.packageName)) { if (!mEverStoredApps.contains(pkg.packageName)) {
if (DEBUG) Log.i(TAG, "New app " + pkg.packageName if (DEBUG) Log.i(TAG, "New app " + pkg.packageName
+ " never backed up; scheduling"); + " never backed up; scheduling");
try { dataChanged(pkg.packageName);
dataChanged(pkg.packageName);
} catch (RemoteException e) {
// can't happen; it's a local method call
}
} }
} }
} }
@@ -871,58 +826,57 @@ class BackupManagerService extends IBackupManager.Stub {
// Called from the backup thread: record that the given app has been successfully // Called from the backup thread: record that the given app has been successfully
// backed up at least once // backed up at least once
void logBackupComplete(String packageName) { void logBackupComplete(String packageName) {
if (mEverStoredStream != null && !packageName.equals(PACKAGE_MANAGER_SENTINEL)) { if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) return;
synchronized (mEverStoredApps) {
if (mEverStoredApps.add(packageName)) { synchronized (mEverStoredApps) {
try { if (!mEverStoredApps.add(packageName)) return;
mEverStoredStream.writeUTF(packageName);
} catch (IOException e) { RandomAccessFile out = null;
Log.e(TAG, "Unable to log backup of " + packageName + ", ceasing log"); try {
try { out = new RandomAccessFile(mEverStored, "rws");
mEverStoredStream.close(); out.seek(out.length());
} catch (IOException ioe) { out.writeUTF(packageName);
// we're dropping it; no need to handle an exception on close here } catch (IOException e) {
} Log.e(TAG, "Can't log backup of " + packageName + " to " + mEverStored);
mEverStoredStream = null; } finally {
} try { if (out != null) out.close(); } catch (IOException e) {}
}
} }
} }
} }
// Remove our awareness of having ever backed up the given package // Remove our awareness of having ever backed up the given package
void removeEverBackedUp(String packageName) { void removeEverBackedUp(String packageName) {
if (DEBUG) Log.v(TAG, "Removing backed-up knowledge of " + packageName if (DEBUG) Log.v(TAG, "Removing backed-up knowledge of " + packageName + ", new set:");
+ ", new set:");
if (mEverStoredStream != null) { synchronized (mEverStoredApps) {
synchronized (mEverStoredApps) { // Rewrite the file and rename to overwrite. If we reboot in the middle,
// Rewrite the file and rename to overwrite. If we reboot in the middle, // we'll recognize on initialization time that the package no longer
// we'll recognize on initialization time that the package no longer // exists and fix it up then.
// exists and fix it up then. File tempKnownFile = new File(mBaseStateDir, "processed.new");
File tempKnownFile = new File(mBaseStateDir, "processed.new"); RandomAccessFile known = null;
try { try {
mEverStoredStream.close(); known = new RandomAccessFile(tempKnownFile, "rws");
RandomAccessFile known = new RandomAccessFile(tempKnownFile, "rw"); mEverStoredApps.remove(packageName);
mEverStoredApps.remove(packageName); for (String s : mEverStoredApps) {
for (String s : mEverStoredApps) { known.writeUTF(s);
known.writeUTF(s); if (DEBUG) Log.v(TAG, " " + s);
if (DEBUG) Log.v(TAG, " " + s);
}
known.close();
tempKnownFile.renameTo(mEverStored);
mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
} catch (IOException e) {
// Bad: we couldn't create the new copy. For safety's sake we
// abandon the whole process and remove all what's-backed-up
// state entirely, meaning we'll force a backup pass for every
// participant on the next boot or [re]install.
Log.w(TAG, "Error rewriting backed-up set; halting log");
mEverStoredStream = null;
mEverStoredApps.clear();
tempKnownFile.delete();
mEverStored.delete();
} }
known.close();
known = null;
if (!tempKnownFile.renameTo(mEverStored)) {
throw new IOException("Can't rename " + tempKnownFile + " to " + mEverStored);
}
} catch (IOException e) {
// Bad: we couldn't create the new copy. For safety's sake we
// abandon the whole process and remove all what's-backed-up
// state entirely, meaning we'll force a backup pass for every
// participant on the next boot or [re]install.
Log.w(TAG, "Error rewriting " + mEverStored, e);
mEverStoredApps.clear();
tempKnownFile.delete();
mEverStored.delete();
} finally {
try { if (known != null) known.close(); } catch (IOException e) {}
} }
} }
} }
@@ -1018,8 +972,7 @@ class BackupManagerService extends IBackupManager.Stub {
} }
class ClearDataObserver extends IPackageDataObserver.Stub { class ClearDataObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(String packageName, boolean succeeded) public void onRemoveCompleted(String packageName, boolean succeeded) {
throws RemoteException {
synchronized(mClearDataLock) { synchronized(mClearDataLock) {
mClearingData = false; mClearingData = false;
mClearDataLock.notifyAll(); mClearDataLock.notifyAll();
@@ -1061,9 +1014,11 @@ class BackupManagerService extends IBackupManager.Stub {
try { try {
EventLog.writeEvent(BACKUP_START_EVENT, mTransport.transportDirName()); EventLog.writeEvent(BACKUP_START_EVENT, mTransport.transportDirName());
// If we haven't stored anything yet, we need to do an init operation. // If we haven't stored package manager metadata yet, we must init the transport.
if (status == BackupConstants.TRANSPORT_OK && mEverStoredApps.size() == 0) { File pmState = new File(mStateDir, PACKAGE_MANAGER_SENTINEL);
Log.i(TAG, "Initializing (wiping) backup transport storage"); if (status == BackupConstants.TRANSPORT_OK && pmState.length() <= 0) {
Log.i(TAG, "Initializing (wiping) backup state and transport storage");
resetBackupState(mStateDir); // Just to make sure.
status = mTransport.initializeDevice(); status = mTransport.initializeDevice();
if (status == BackupConstants.TRANSPORT_OK) { if (status == BackupConstants.TRANSPORT_OK) {
EventLog.writeEvent(BACKUP_INITIALIZE_EVENT); EventLog.writeEvent(BACKUP_INITIALIZE_EVENT);
@@ -1107,10 +1062,9 @@ class BackupManagerService extends IBackupManager.Stub {
if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) { if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
// The backend reports that our dataset has been wiped. We need to // The backend reports that our dataset has been wiped. We need to
// reset all of our bookkeeping and instead run a new backup pass for // reset all of our bookkeeping and instead run a new backup pass for
// everything. // everything. This must come after mBackupOrRestoreInProgress is cleared.
EventLog.writeEvent(BACKUP_RESET_EVENT, mTransport.transportDirName()); EventLog.writeEvent(BACKUP_RESET_EVENT, mTransport.transportDirName());
resetBackupState(mStateDir); resetBackupState(mStateDir);
backupNow();
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Error in backup thread", e); Log.e(TAG, "Error in backup thread", e);
@@ -1123,11 +1077,7 @@ class BackupManagerService extends IBackupManager.Stub {
if (status != BackupConstants.TRANSPORT_OK) { if (status != BackupConstants.TRANSPORT_OK) {
Log.w(TAG, "Backup pass unsuccessful, restaging"); Log.w(TAG, "Backup pass unsuccessful, restaging");
for (BackupRequest req : mQueue) { for (BackupRequest req : mQueue) {
try { dataChanged(req.appInfo.packageName);
dataChanged(req.appInfo.packageName);
} catch (RemoteException e) {
// can't happen; it's a local call
}
} }
// We also want to reset the backup schedule based on whatever // We also want to reset the backup schedule based on whatever
@@ -1141,7 +1091,7 @@ class BackupManagerService extends IBackupManager.Stub {
// this pass's journal any more; or it failed, in which case we just // this pass's journal any more; or it failed, in which case we just
// re-enqueued all of these packages in the current active journal. // re-enqueued all of these packages in the current active journal.
// Either way, we no longer need this pass's journal. // Either way, we no longer need this pass's journal.
if (!mJournal.delete()) { if (mJournal != null && !mJournal.delete()) {
Log.e(TAG, "Unable to remove backup journal file " + mJournal); Log.e(TAG, "Unable to remove backup journal file " + mJournal);
} }
@@ -1150,6 +1100,12 @@ class BackupManagerService extends IBackupManager.Stub {
synchronized (mQueueLock) { synchronized (mQueueLock) {
mBackupOrRestoreInProgress = false; mBackupOrRestoreInProgress = false;
} }
if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
// This must come after mBackupOrRestoreInProgress is cleared.
backupNow();
}
mWakelock.release(); mWakelock.release();
} }
} }
@@ -1782,7 +1738,7 @@ class BackupManagerService extends IBackupManager.Stub {
// ----- IBackupManager binder interface ----- // ----- IBackupManager binder interface -----
public void dataChanged(String packageName) throws RemoteException { public void dataChanged(String packageName) {
// Record that we need a backup pass for the caller. Since multiple callers // Record that we need a backup pass for the caller. Since multiple callers
// may share a uid, we need to note all candidates within that uid and schedule // may share a uid, we need to note all candidates within that uid and schedule
// a backup pass for each of them. // a backup pass for each of them.
@@ -1840,14 +1796,17 @@ class BackupManagerService extends IBackupManager.Stub {
} }
private void writeToJournalLocked(String str) { private void writeToJournalLocked(String str) {
if (mJournalStream != null) { RandomAccessFile out = null;
try { try {
mJournalStream.writeUTF(str); if (mJournal == null) mJournal = File.createTempFile("journal", null, mJournalDir);
} catch (IOException e) { out = new RandomAccessFile(mJournal, "rws");
Log.e(TAG, "Error writing to backup journal"); out.seek(out.length());
mJournalStream = null; out.writeUTF(str);
mJournal = null; } catch (IOException e) {
} Log.e(TAG, "Can't write " + str + " to backup journal", e);
mJournal = null;
} finally {
try { if (out != null) out.close(); } catch (IOException e) {}
} }
} }
@@ -1902,7 +1861,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Run a backup pass immediately for any applications that have declared // Run a backup pass immediately for any applications that have declared
// that they have pending updates. // that they have pending updates.
public void backupNow() throws RemoteException { public void backupNow() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow"); mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass"); if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
@@ -2210,8 +2169,16 @@ class BackupManagerService extends IBackupManager.Stub {
pw.println("Available transports:"); pw.println("Available transports:");
for (String t : listAllTransports()) { for (String t : listAllTransports()) {
String pad = (t.equals(mCurrentTransport)) ? " * " : " "; pw.println((t.equals(mCurrentTransport) ? " * " : " ") + t);
pw.println(pad + t); try {
File dir = new File(mBaseStateDir, getTransport(t).transportDirName());
for (File f : dir.listFiles()) {
pw.println(" " + f.getName() + " - " + f.length() + " state bytes");
}
} catch (RemoteException e) {
Log.e(TAG, "Error in transportDirName()", e);
pw.println(" Error: " + e);
}
} }
pw.println("Pending init: " + mPendingInits.size()); pw.println("Pending init: " + mPendingInits.size());