summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2009-06-14 21:13:03 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-06-14 21:13:03 -0700
commitdaf701fa6250ae89ad93e2e41127e0f676a322a5 (patch)
tree5b816f0e72d4bd2b0b2040242799c4008abf3a59
parentaa73f17201481f943345253328071118abc02933 (diff)
parent2fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2 (diff)
downloadframeworks_base-daf701fa6250ae89ad93e2e41127e0f676a322a5.zip
frameworks_base-daf701fa6250ae89ad93e2e41127e0f676a322a5.tar.gz
frameworks_base-daf701fa6250ae89ad93e2e41127e0f676a322a5.tar.bz2
am 2fdd428e: Fix some backup reader/writer issues; make local transport do backup
Merge commit '2fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2' * commit '2fdd428e0f18384160f7c38ce3a2cd9ba7e7b2c2': Fix some backup reader/writer issues; make local transport do backup Fix the jni initializer. Add RestoreFileHelper, BackupDataInput, and add java wrappers for the methods on BackupDataOutput. Fix bug #1812041: activity manager crash with bad args. Journal backup requests so that they won't be lost in a crash Fix data connection issues.
-rw-r--r--core/java/android/app/FullBackupAgent.java5
-rw-r--r--core/java/android/backup/BackupDataInput.java103
-rw-r--r--core/java/android/backup/BackupDataOutput.java22
-rw-r--r--core/java/android/backup/FileBackupHelper.java43
-rw-r--r--core/java/android/backup/RestoreHelper.java23
-rw-r--r--core/java/android/backup/RestoreHelperDistributor.java28
-rw-r--r--core/java/android/backup/SharedPreferencesBackupHelper.java23
-rw-r--r--core/java/com/android/internal/backup/LocalTransport.java86
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_backup_BackupDataInput.cpp173
-rw-r--r--core/jni/android_backup_BackupDataOutput.cpp51
-rw-r--r--core/jni/android_backup_FileBackupHelper.cpp4
-rw-r--r--libs/utils/BackupData.cpp2
-rw-r--r--services/java/com/android/server/BackupManagerService.java99
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java50
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java19
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java21
-rw-r--r--tests/backup/src/com/android/backuptest/BackupTestAgent.java3
19 files changed, 655 insertions, 103 deletions
diff --git a/core/java/android/app/FullBackupAgent.java b/core/java/android/app/FullBackupAgent.java
index 18d62e3..bf5cb5d 100644
--- a/core/java/android/app/FullBackupAgent.java
+++ b/core/java/android/app/FullBackupAgent.java
@@ -47,12 +47,11 @@ public class FullBackupAgent extends BackupAgent {
}
// That's the file set; now back it all up
- FileBackupHelper.performBackup(this, oldState, data, newState,
- (String[]) allFiles.toArray());
+ FileBackupHelper helper = new FileBackupHelper(this);
+ helper.performBackup(oldState, data, newState, (String[])allFiles.toArray());
}
@Override
public void onRestore(ParcelFileDescriptor data, ParcelFileDescriptor newState) {
}
-
}
diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java
new file mode 100644
index 0000000..609dd90
--- /dev/null
+++ b/core/java/android/backup/BackupDataInput.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2009 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 android.backup;
+
+import android.content.Context;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/** @hide */
+public class BackupDataInput {
+ int mBackupReader;
+
+ private EntityHeader mHeader = new EntityHeader();
+ private boolean mHeaderReady;
+
+ private static class EntityHeader {
+ String key;
+ int dataSize;
+ }
+
+ public BackupDataInput(FileDescriptor fd) {
+ if (fd == null) throw new NullPointerException();
+ mBackupReader = ctor(fd);
+ if (mBackupReader == 0) {
+ throw new RuntimeException("Native initialization failed with fd=" + fd);
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ dtor(mBackupReader);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public boolean readNextHeader() throws IOException {
+ int result = readNextHeader_native(mBackupReader, mHeader);
+ if (result == 0) {
+ // read successfully
+ mHeaderReady = true;
+ return true;
+ } else if (result > 0) {
+ // done
+ mHeaderReady = false;
+ return false;
+ } else {
+ // error
+ mHeaderReady = false;
+ throw new IOException("result=0x" + Integer.toHexString(result));
+ }
+ }
+
+ public String getKey() {
+ if (mHeaderReady) {
+ return mHeader.key;
+ } else {
+ throw new IllegalStateException("mHeaderReady=false");
+ }
+ }
+
+ public int getDataSize() {
+ if (mHeaderReady) {
+ return mHeader.dataSize;
+ } else {
+ throw new IllegalStateException("mHeaderReady=false");
+ }
+ }
+
+ public int readEntityData(byte[] data, int size) throws IOException {
+ if (mHeaderReady) {
+ int result = readEntityData_native(mBackupReader, data, size);
+ if (result >= 0) {
+ return result;
+ } else {
+ throw new IOException("result=0x" + Integer.toHexString(result));
+ }
+ } else {
+ throw new IllegalStateException("mHeaderReady=false");
+ }
+ }
+
+ private native static int ctor(FileDescriptor fd);
+ private native static void dtor(int mBackupReader);
+
+ private native int readNextHeader_native(int mBackupReader, EntityHeader entity);
+ private native int readEntityData_native(int mBackupReader, byte[] data, int size);
+}
diff --git a/core/java/android/backup/BackupDataOutput.java b/core/java/android/backup/BackupDataOutput.java
index 25ae15b..1348d81 100644
--- a/core/java/android/backup/BackupDataOutput.java
+++ b/core/java/android/backup/BackupDataOutput.java
@@ -19,6 +19,7 @@ package android.backup;
import android.content.Context;
import java.io.FileDescriptor;
+import java.io.IOException;
/** @hide */
public class BackupDataOutput {
@@ -37,6 +38,24 @@ public class BackupDataOutput {
}
}
+ public int writeEntityHeader(String key, int dataSize) throws IOException {
+ int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
+ if (result >= 0) {
+ return result;
+ } else {
+ throw new IOException("result=0x" + Integer.toHexString(result));
+ }
+ }
+
+ public int writeEntityData(byte[] data, int size) throws IOException {
+ int result = writeEntityData_native(mBackupWriter, data, size);
+ if (result >= 0) {
+ return result;
+ } else {
+ throw new IOException("result=0x" + Integer.toHexString(result));
+ }
+ }
+
protected void finalize() throws Throwable {
try {
dtor(mBackupWriter);
@@ -47,5 +66,8 @@ public class BackupDataOutput {
private native static int ctor(FileDescriptor fd);
private native static void dtor(int mBackupWriter);
+
+ private native static int writeEntityHeader_native(int mBackupWriter, String key, int dataSize);
+ private native static int writeEntityData_native(int mBackupWriter, byte[] data, int size);
}
diff --git a/core/java/android/backup/FileBackupHelper.java b/core/java/android/backup/FileBackupHelper.java
index 99051bf..ed840bb 100644
--- a/core/java/android/backup/FileBackupHelper.java
+++ b/core/java/android/backup/FileBackupHelper.java
@@ -27,21 +27,56 @@ import java.io.FileDescriptor;
public class FileBackupHelper {
private static final String TAG = "FileBackupHelper";
+ Context mContext;
+ String mKeyPrefix;
+
+ public FileBackupHelper(Context context) {
+ mContext = context;
+ }
+
+ public FileBackupHelper(Context context, String keyPrefix) {
+ mContext = context;
+ mKeyPrefix = keyPrefix;
+ }
+
/**
* Based on oldState, determine which of the files from the application's data directory
* need to be backed up, write them to the data stream, and fill in newState with the
* state as it exists now.
*/
- public static void performBackup(Context context,
- ParcelFileDescriptor oldState, BackupDataOutput data,
+ public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState, String[] files) {
- File base = context.getFilesDir();
+ // file names
+ File base = mContext.getFilesDir();
final int N = files.length;
String[] fullPaths = new String[N];
for (int i=0; i<N; i++) {
fullPaths[i] = (new File(base, files[i])).getAbsolutePath();
}
- performBackup_checked(oldState, data, newState, fullPaths, files);
+
+ // keys
+ String[] keys = makeKeys(mKeyPrefix, files);
+
+ // go
+ performBackup_checked(oldState, data, newState, fullPaths, keys);
+ }
+
+ /**
+ * If keyPrefix is not null, prepend it to each of the strings in <code>original</code>;
+ * otherwise, return original.
+ */
+ static String[] makeKeys(String keyPrefix, String[] original) {
+ if (keyPrefix != null) {
+ String[] keys;
+ final int N = original.length;
+ keys = new String[N];
+ for (int i=0; i<N; i++) {
+ keys[i] = keyPrefix + ':' + original[i];
+ }
+ return keys;
+ } else {
+ return original;
+ }
}
/**
diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/RestoreHelper.java
new file mode 100644
index 0000000..ebd9906
--- /dev/null
+++ b/core/java/android/backup/RestoreHelper.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2009 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 android.backup;
+
+/** @hide */
+public interface RestoreHelper {
+ public void performRestore();
+}
+
diff --git a/core/java/android/backup/RestoreHelperDistributor.java b/core/java/android/backup/RestoreHelperDistributor.java
new file mode 100644
index 0000000..555ca79
--- /dev/null
+++ b/core/java/android/backup/RestoreHelperDistributor.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2009 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 android.backup;
+
+import java.util.HashMap;
+
+/** @hide */
+public class RestoreHelperDistributor {
+ HashMap<String,RestoreHelper> mHelpers;
+
+ public void addHelper(String keyPrefix, RestoreHelper helper) {
+ mHelpers.put(keyPrefix, helper);
+ }
+}
diff --git a/core/java/android/backup/SharedPreferencesBackupHelper.java b/core/java/android/backup/SharedPreferencesBackupHelper.java
index 923dc1b..cad79df 100644
--- a/core/java/android/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/backup/SharedPreferencesBackupHelper.java
@@ -23,16 +23,33 @@ import java.io.FileDescriptor;
/** @hide */
public class SharedPreferencesBackupHelper {
- public static void performBackup(Context context,
- ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
+ private Context mContext;
+ private String mKeyPrefix;
+
+ public SharedPreferencesBackupHelper(Context context) {
+ mContext = context;
+ }
+
+ public SharedPreferencesBackupHelper(Context context, String keyPrefix) {
+ mContext = context;
+ mKeyPrefix = keyPrefix;
+ }
+
+ public void performBackup(ParcelFileDescriptor oldSnapshot, ParcelFileDescriptor newSnapshot,
BackupDataOutput data, String[] prefGroups) {
+ Context context = mContext;
+
// make filenames for the prefGroups
final int N = prefGroups.length;
String[] files = new String[N];
for (int i=0; i<N; i++) {
- files[i] = context.getSharedPrefsFile(prefGroups[i]).toString();
+ files[i] = context.getSharedPrefsFile(prefGroups[i]).getAbsolutePath();
}
+ // make keys if necessary
+ String[] keys = FileBackupHelper.makeKeys(mKeyPrefix, prefGroups);
+
+ // go
FileBackupHelper.performBackup_checked(oldSnapshot, data, newSnapshot, files, prefGroups);
}
}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 62fba4a..83182f2 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -1,5 +1,6 @@
package com.android.internal.backup;
+import android.backup.BackupDataInput;
import android.backup.RestoreSet;
import android.content.Context;
import android.content.pm.PackageInfo;
@@ -24,7 +25,7 @@ import java.util.ArrayList;
public class LocalTransport extends IBackupTransport.Stub {
private static final String TAG = "LocalTransport";
- private static final String DATA_FILE_NAME = "data";
+ private static final boolean DEBUG = true;
private Context mContext;
private PackageManager mPackageManager;
@@ -37,6 +38,7 @@ public class LocalTransport extends IBackupTransport.Stub {
public LocalTransport(Context context) {
+ if (DEBUG) Log.v(TAG, "Transport constructed");
mContext = context;
mPackageManager = context.getPackageManager();
}
@@ -47,29 +49,63 @@ public class LocalTransport extends IBackupTransport.Stub {
}
public int startSession() throws RemoteException {
+ if (DEBUG) Log.v(TAG, "session started");
+ mDataDir.mkdirs();
return 0;
}
public int endSession() throws RemoteException {
+ if (DEBUG) Log.v(TAG, "session ended");
return 0;
}
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
throws RemoteException {
- File packageDir = new File(mDataDir, packageInfo.packageName);
- File imageFileName = new File(packageDir, DATA_FILE_NAME);
-
- //!!! TODO: process the (partial) update into the persistent restore set:
-
- // Parse out the existing image file into the key/value map
+ if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
+ int err = 0;
- // Parse out the backup data into the key/value updates
-
- // Apply the backup key/value updates to the image
+ File packageDir = new File(mDataDir, packageInfo.packageName);
+ packageDir.mkdirs();
- // Write out the image in the canonical format
+ // Each 'record' in the restore set is kept in its own file, named by
+ // the record key. Wind through the data file, extracting individual
+ // record operations and building a set of all the updates to apply
+ // in this update.
+ BackupDataInput changeSet = new BackupDataInput(data.getFileDescriptor());
+ try {
+ int bufSize = 512;
+ byte[] buf = new byte[bufSize];
+ while (changeSet.readNextHeader()) {
+ String key = changeSet.getKey();
+ int dataSize = changeSet.getDataSize();
+ if (DEBUG) Log.v(TAG, "Got change set key=" + key + " size=" + dataSize);
+ if (dataSize > bufSize) {
+ bufSize = dataSize;
+ buf = new byte[bufSize];
+ }
+ changeSet.readEntityData(buf, dataSize);
+ if (DEBUG) Log.v(TAG, " + data size " + dataSize);
+
+ File entityFile = new File(packageDir, key);
+ FileOutputStream entity = new FileOutputStream(entityFile);
+ try {
+ entity.write(buf, 0, dataSize);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to update key file "
+ + entityFile.getAbsolutePath());
+ err = -1;
+ } finally {
+ entity.close();
+ }
+ }
+ } catch (IOException e) {
+ // oops, something went wrong. abort the operation and return error.
+ Log.v(TAG, "Exception reading backup input:");
+ e.printStackTrace();
+ err = -1;
+ }
- return -1;
+ return err;
}
// Restore handling
@@ -83,6 +119,7 @@ public class LocalTransport extends IBackupTransport.Stub {
}
public PackageInfo[] getAppSet(int token) throws android.os.RemoteException {
+ if (DEBUG) Log.v(TAG, "getting app set " + token);
// the available packages are the extant subdirs of mDatadir
File[] packageDirs = mDataDir.listFiles(mDirFileFilter);
ArrayList<PackageInfo> packages = new ArrayList<PackageInfo>();
@@ -99,9 +136,11 @@ public class LocalTransport extends IBackupTransport.Stub {
}
}
- Log.v(TAG, "Built app set of " + packages.size() + " entries:");
- for (PackageInfo p : packages) {
- Log.v(TAG, " + " + p.packageName);
+ if (DEBUG) {
+ Log.v(TAG, "Built app set of " + packages.size() + " entries:");
+ for (PackageInfo p : packages) {
+ Log.v(TAG, " + " + p.packageName);
+ }
}
PackageInfo[] result = new PackageInfo[packages.size()];
@@ -110,16 +149,25 @@ public class LocalTransport extends IBackupTransport.Stub {
public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor output)
throws android.os.RemoteException {
+ if (DEBUG) Log.v(TAG, "getting restore data " + token + " : " + packageInfo.packageName);
// we only support one hardcoded restore set
if (token != 0) return -1;
// the data for a given package is at a known location
File packageDir = new File(mDataDir, packageInfo.packageName);
- File imageFile = new File(packageDir, DATA_FILE_NAME);
- // restore is relatively easy: we already maintain the full data set in
- // the canonical form understandable to the BackupAgent
- return copyFileToFD(imageFile, output);
+ // The restore set is the concatenation of the individual record blobs,
+ // each of which is a file in the package's directory
+ File[] blobs = packageDir.listFiles();
+ int err = 0;
+ if (blobs != null && blobs.length > 0) {
+ for (File f : blobs) {
+ err = copyFileToFD(f, output);
+ if (err != 0) break;
+ }
+ }
+
+ return err;
}
private int copyFileToFD(File source, ParcelFileDescriptor dest) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 31cc4f7..aca6670 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -115,6 +115,7 @@ LOCAL_SRC_FILES:= \
android_location_GpsLocationProvider.cpp \
com_android_internal_os_ZygoteInit.cpp \
com_android_internal_graphics_NativeUtils.cpp \
+ android_backup_BackupDataInput.cpp \
android_backup_BackupDataOutput.cpp \
android_backup_FileBackupHelper.cpp
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6de37f0..4512fef 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -153,6 +153,7 @@ extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
extern int register_android_util_Base64(JNIEnv* env);
extern int register_android_location_GpsLocationProvider(JNIEnv* env);
+extern int register_android_backup_BackupDataInput(JNIEnv *env);
extern int register_android_backup_BackupDataOutput(JNIEnv *env);
extern int register_android_backup_FileBackupHelper(JNIEnv *env);
@@ -1168,6 +1169,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
REG_JNI(register_android_util_Base64),
REG_JNI(register_android_location_GpsLocationProvider),
+ REG_JNI(register_android_backup_BackupDataInput),
REG_JNI(register_android_backup_BackupDataOutput),
REG_JNI(register_android_backup_FileBackupHelper),
};
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
new file mode 100644
index 0000000..5b2fb73
--- /dev/null
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "FileBackupHelper_native"
+#include <utils/Log.h>
+
+#include "JNIHelp.h"
+#include <android_runtime/AndroidRuntime.h>
+
+#include <utils/BackupHelpers.h>
+
+namespace android
+{
+
+// java.io.FileDescriptor
+static jfieldID s_descriptorField = 0;
+
+// android.backup.BackupDataInput$EntityHeader
+static jfieldID s_keyField = 0;
+static jfieldID s_dataSizeField = 0;
+
+static int
+ctor_native(JNIEnv* env, jobject clazz, jobject fileDescriptor)
+{
+ int err;
+
+ int fd = env->GetIntField(fileDescriptor, s_descriptorField);
+ if (fd == -1) {
+ return NULL;
+ }
+
+ return (int)new BackupDataReader(fd);
+}
+
+static void
+dtor_native(JNIEnv* env, jobject clazz, int r)
+{
+ delete (BackupDataReader*)r;
+}
+
+static jint
+readNextHeader_native(JNIEnv* env, jobject clazz, int r, jobject entity)
+{
+ int err;
+ BackupDataReader* reader = (BackupDataReader*)r;
+
+ err = reader->Status();
+ if (err != 0) {
+ return err < 0 ? err : -1;
+ }
+
+ int type = 0;
+
+ err = reader->ReadNextHeader(&type);
+ if (err == EIO) {
+ // Clean EOF with no footer block; just claim we're done
+ return 1;
+ }
+
+ if (err != 0) {
+ return err < 0 ? err : -1;
+ }
+
+ switch (type) {
+ case BACKUP_HEADER_APP_V1:
+ {
+ String8 packageName;
+ int cookie;
+ err = reader->ReadAppHeader(&packageName, &cookie);
+ if (err != 0) {
+ LOGD("ReadAppHeader() returned %d; aborting", err);
+ return err < 0 ? err : -1;
+ }
+ break;
+ }
+ case BACKUP_HEADER_ENTITY_V1:
+ {
+ String8 key;
+ size_t dataSize;
+ err = reader->ReadEntityHeader(&key, &dataSize);
+ if (err != 0) {
+ LOGD("ReadEntityHeader(); aborting", err);
+ return err < 0 ? err : -1;
+ }
+ // TODO: Set the fields in the entity object
+ jstring keyStr = env->NewStringUTF(key.string());
+ env->SetObjectField(entity, s_keyField, keyStr);
+ env->SetIntField(entity, s_dataSizeField, dataSize);
+ return 0;
+ }
+ case BACKUP_FOOTER_APP_V1:
+ {
+ break;
+ }
+ default:
+ LOGD("Unknown header type: 0x%08x\n", type);
+ return -1;
+ }
+
+ // done
+ return 1;
+}
+
+static jint
+readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int size)
+{
+ int err;
+ BackupDataReader* reader = (BackupDataReader*)r;
+
+ if (env->GetArrayLength(data) < size) {
+ // size mismatch
+ return -1;
+ }
+
+ jbyte* dataBytes = env->GetByteArrayElements(data, NULL);
+ if (dataBytes == NULL) {
+ return -2;
+ }
+
+ err = reader->ReadEntityData(dataBytes, size);
+
+ env->ReleaseByteArrayElements(data, dataBytes, 0);
+
+ return err;
+}
+
+static const JNINativeMethod g_methods[] = {
+ { "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
+ { "dtor", "(I)V", (void*)dtor_native },
+ { "readNextHeader_native", "(ILandroid/backup/BackupDataInput$EntityHeader;)I",
+ (void*)readNextHeader_native },
+ { "readEntityData_native", "(I[BI)I", (void*)readEntityData_native },
+};
+
+int register_android_backup_BackupDataInput(JNIEnv* env)
+{
+ //LOGD("register_android_backup_BackupDataInput");
+
+ jclass clazz;
+
+ clazz = env->FindClass("java/io/FileDescriptor");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
+ s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
+ LOG_FATAL_IF(s_descriptorField == NULL,
+ "Unable to find descriptor field in java.io.FileDescriptor");
+
+ clazz = env->FindClass("android/backup/BackupDataInput$EntityHeader");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.backup.BackupDataInput.EntityHeader");
+ s_keyField = env->GetFieldID(clazz, "key", "Ljava/lang/String;");
+ LOG_FATAL_IF(s_keyField == NULL,
+ "Unable to find key field in android.backup.BackupDataInput.EntityHeader");
+ s_dataSizeField = env->GetFieldID(clazz, "dataSize", "I");
+ LOG_FATAL_IF(s_dataSizeField == NULL,
+ "Unable to find dataSize field in android.backup.BackupDataInput.EntityHeader");
+
+ return AndroidRuntime::registerNativeMethods(env, "android/backup/BackupDataInput",
+ g_methods, NELEM(g_methods));
+}
+
+}
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index aab1233..6362439 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -28,7 +28,7 @@ namespace android
static jfieldID s_descriptorField = 0;
static int
-ctor_native(JNIEnv* env, jobject This, jobject fileDescriptor)
+ctor_native(JNIEnv* env, jobject clazz, jobject fileDescriptor)
{
int err;
@@ -41,19 +41,62 @@ ctor_native(JNIEnv* env, jobject This, jobject fileDescriptor)
}
static void
-dtor_native(JNIEnv* env, jobject This, int fd)
+dtor_native(JNIEnv* env, jobject clazz, int w)
{
- delete (BackupDataWriter*)fd;
+ delete (BackupDataWriter*)w;
+}
+
+static jint
+writeEntityHeader_native(JNIEnv* env, jobject clazz, int w, jstring key, int dataSize)
+{
+ int err;
+ BackupDataWriter* writer = (BackupDataWriter*)w;
+
+ const char* keyUTF = env->GetStringUTFChars(key, NULL);
+ if (keyUTF == NULL) {
+ return -1;
+ }
+
+ err = writer->WriteEntityHeader(String8(keyUTF), dataSize);
+
+ env->ReleaseStringUTFChars(key, keyUTF);
+
+ return err;
+}
+
+static jint
+writeEntityData_native(JNIEnv* env, jobject clazz, int w, jbyteArray data, int size)
+{
+ int err;
+ BackupDataWriter* writer = (BackupDataWriter*)w;
+
+ if (env->GetArrayLength(data) > size) {
+ // size mismatch
+ return -1;
+ }
+
+ jbyte* dataBytes = env->GetByteArrayElements(data, NULL);
+ if (dataBytes == NULL) {
+ return -1;
+ }
+
+ err = writer->WriteEntityData(dataBytes, size);
+
+ env->ReleaseByteArrayElements(data, dataBytes, JNI_ABORT);
+
+ return err;
}
static const JNINativeMethod g_methods[] = {
{ "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
{ "dtor", "(I)V", (void*)dtor_native },
+ { "writeEntityHeader_native", "(ILjava/lang/String;I)I", (void*)writeEntityHeader_native },
+ { "writeEntityData_native", "(I[BI)I", (void*)writeEntityData_native },
};
int register_android_backup_BackupDataOutput(JNIEnv* env)
{
- LOGD("register_android_backup_BackupDataOutput");
+ //LOGD("register_android_backup_BackupDataOutput");
jclass clazz;
diff --git a/core/jni/android_backup_FileBackupHelper.cpp b/core/jni/android_backup_FileBackupHelper.cpp
index 2ee064b..418db8a 100644
--- a/core/jni/android_backup_FileBackupHelper.cpp
+++ b/core/jni/android_backup_FileBackupHelper.cpp
@@ -25,6 +25,7 @@
namespace android
{
+// java.io.FileDescriptor
static jfieldID s_descriptorField = 0;
static int
@@ -34,7 +35,6 @@ performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data,
int err;
// all parameters have already been checked against null
- LOGD("oldState=%p newState=%p data=%p\n", oldState, newState, data);
int oldStateFD = oldState != NULL ? env->GetIntField(oldState, s_descriptorField) : -1;
int newStateFD = env->GetIntField(newState, s_descriptorField);
BackupDataWriter* dataStream = (BackupDataWriter*)data;
@@ -74,8 +74,6 @@ static const JNINativeMethod g_methods[] = {
int register_android_backup_FileBackupHelper(JNIEnv* env)
{
- LOGD("register_android_backup_FileBackupHelper");
-
jclass clazz;
clazz = env->FindClass("java/io/FileDescriptor");
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 120f23d..8c9f875 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -327,7 +327,7 @@ BackupDataReader::ReadAppHeader(String8* packageName, int* cookie)
}
size_t size = m_header.app.packageLen;
char* buf = packageName->lockBuffer(size);
- if (packageName == NULL) {
+ if (buf == NULL) {
packageName->unlockBuffer();
m_status = ENOMEM;
return m_status;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index d3067ec..47a6ede 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -51,11 +51,13 @@ import com.android.internal.backup.LocalTransport;
import com.android.internal.backup.GoogleTransport;
import com.android.internal.backup.IBackupTransport;
+import java.io.EOFException;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
+import java.io.RandomAccessFile;
import java.lang.String;
import java.util.ArrayList;
import java.util.HashMap;
@@ -122,6 +124,9 @@ class BackupManagerService extends IBackupManager.Stub {
private File mStateDir;
private File mDataDir;
+ private File mJournalDir;
+ private File mJournal;
+ private RandomAccessFile mJournalStream;
public BackupManagerService(Context context) {
mContext = context;
@@ -133,6 +138,11 @@ class BackupManagerService extends IBackupManager.Stub {
mStateDir.mkdirs();
mDataDir = Environment.getDownloadCacheDirectory();
+ // Set up the backup-request journaling
+ mJournalDir = new File(mStateDir, "pending");
+ mJournalDir.mkdirs();
+ makeJournalLocked(); // okay because no other threads are running yet
+
//!!! TODO: default to cloud transport, not local
mTransportId = BackupManager.TRANSPORT_LOCAL;
@@ -141,6 +151,10 @@ class BackupManagerService extends IBackupManager.Stub {
addPackageParticipantsLocked(null);
}
+ // Now that we know about valid backup participants, parse any
+ // leftover journal files and schedule a new backup pass
+ parseLeftoverJournals();
+
// Register for broadcasts about package install, etc., so we can
// update the provider list.
IntentFilter filter = new IntentFilter();
@@ -150,6 +164,46 @@ class BackupManagerService extends IBackupManager.Stub {
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() {
+ if (mJournal != null) {
+ File[] allJournals = mJournalDir.listFiles();
+ for (File f : allJournals) {
+ if (f.compareTo(mJournal) != 0) {
+ // This isn't the current journal, so it must be a leftover. Read
+ // out the package names mentioned there and schedule them for
+ // backup.
+ try {
+ Log.i(TAG, "Found stale backup journal, scheduling:");
+ RandomAccessFile in = new RandomAccessFile(f, "r");
+ while (true) {
+ String packageName = in.readUTF();
+ Log.i(TAG, " + " + 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();
+ }
+ }
+ }
+ }
+ }
+
// ----- Track installation/removal of packages -----
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
@@ -198,6 +252,8 @@ class BackupManagerService extends IBackupManager.Stub {
switch (msg.what) {
case MSG_RUN_BACKUP:
// snapshot the pending-backup set and work on that
+ File oldJournal = mJournal;
+ RandomAccessFile oldJournalStream = mJournalStream;
synchronized (mQueueLock) {
if (mBackupQueue == null) {
mBackupQueue = new ArrayList<BackupRequest>();
@@ -207,10 +263,22 @@ class BackupManagerService extends IBackupManager.Stub {
mPendingBackups = new HashMap<ApplicationInfo,BackupRequest>();
}
// !!! TODO: start a new backup-queue journal file too
- // WARNING: If we crash after this line, anything in mPendingBackups will
- // be lost. FIX THIS.
+ if (mJournalStream != null) {
+ try {
+ 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
+ // file identity is being passed to the backup processing thread.
+ // When it completes successfully, that old journal file will be
+ // deleted. If we crash prior to that, the old journal is parsed
+ // at next boot and the journaled requests fulfilled.
}
- (new PerformBackupThread(mTransportId, mBackupQueue)).run();
+ (new PerformBackupThread(mTransportId, mBackupQueue, oldJournal)).run();
break;
case MSG_RUN_FULL_BACKUP:
@@ -433,10 +501,13 @@ class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "PerformBackupThread";
int mTransport;
ArrayList<BackupRequest> mQueue;
+ File mJournal;
- public PerformBackupThread(int transportId, ArrayList<BackupRequest> queue) {
+ public PerformBackupThread(int transportId, ArrayList<BackupRequest> queue,
+ File journal) {
mTransport = transportId;
mQueue = queue;
+ mJournal = journal;
}
@Override
@@ -468,6 +539,10 @@ class BackupManagerService extends IBackupManager.Stub {
Log.e(TAG, "Error ending transport");
e.printStackTrace();
}
+
+ if (!mJournal.delete()) {
+ Log.e(TAG, "Unable to remove backup journal file " + mJournal.getAbsolutePath());
+ }
}
private void doQueuedBackups(IBackupTransport transport) {
@@ -782,7 +857,9 @@ class BackupManagerService extends IBackupManager.Stub {
// one already there, then overwrite it, but no harm done.
BackupRequest req = new BackupRequest(app, false);
mPendingBackups.put(app, req);
- // !!! TODO: write to the pending-backup journal file in case of crash
+
+ // Journal this request in case of crash
+ writeToJournalLocked(packageName);
}
}
@@ -804,6 +881,18 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ private void writeToJournalLocked(String str) {
+ if (mJournalStream != null) {
+ try {
+ mJournalStream.writeUTF(str);
+ } catch (IOException e) {
+ Log.e(TAG, "Error writing to backup journal");
+ mJournalStream = null;
+ mJournal = null;
+ }
+ }
+ }
+
// Schedule a backup pass for a given package. This method will schedule a
// full backup even for apps that do not declare an android:backupAgent, so
// use with care.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6a81178..07d6b6f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import com.android.internal.os.BatteryStatsImpl;
-import com.android.internal.os.RuntimeInit;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
import com.android.server.ProcessStats;
@@ -2761,7 +2760,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// instance of the activity so a new fresh one can be started.
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
if (!ret.finishing) {
- int index = indexOfTokenLocked(ret, false);
+ int index = indexOfTokenLocked(ret);
if (index >= 0) {
finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
null, "clear");
@@ -2854,7 +2853,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord sourceRecord = null;
HistoryRecord resultRecord = null;
if (resultTo != null) {
- int index = indexOfTokenLocked(resultTo, false);
+ int index = indexOfTokenLocked(resultTo);
if (DEBUG_RESULTS) Log.v(
TAG, "Sending result to " + resultTo + " (index " + index + ")");
if (index >= 0) {
@@ -3420,7 +3419,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized (this) {
- int index = indexOfTokenLocked(callingActivity, false);
+ int index = indexOfTokenLocked(callingActivity);
if (index < 0) {
return false;
}
@@ -3570,7 +3569,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public void setRequestedOrientation(IBinder token,
int requestedOrientation) {
synchronized (this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return;
}
@@ -3592,7 +3591,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public int getRequestedOrientation(IBinder token) {
synchronized (this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
@@ -3648,7 +3647,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
TAG, "Finishing activity: token=" + token
+ ", result=" + resultCode + ", data=" + resultData);
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return false;
}
@@ -3772,7 +3771,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
int mode) {
- final int index = indexOfTokenLocked(r, false);
+ final int index = indexOfTokenLocked(r);
if (index < 0) {
return null;
}
@@ -3897,7 +3896,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public final void finishSubActivity(IBinder token, String resultWho,
int requestCode) {
synchronized(this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return;
}
@@ -4447,7 +4446,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized(this) {
- int index = indexOfTokenLocked(token, true);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return;
}
@@ -5012,7 +5011,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
// Get the activity record.
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
@@ -5166,7 +5165,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord r = null;
synchronized (this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
r = (HistoryRecord)mHistory.get(index);
if (!timeout) {
@@ -5197,7 +5196,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
r = (HistoryRecord)mHistory.get(index);
r.thumbnail = thumbnail;
@@ -5227,7 +5226,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized (this) {
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
if (r.state == ActivityState.DESTROYING) {
@@ -5254,7 +5253,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private HistoryRecord getCallingRecordLocked(IBinder token) {
- int index = indexOfTokenLocked(token, true);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
if (r != null) {
@@ -5266,7 +5265,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public ComponentName getActivityClassForToken(IBinder token) {
synchronized(this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
return r.intent.getComponent();
@@ -5277,7 +5276,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public String getPackageForToken(IBinder token) {
synchronized(this) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index >= 0) {
HistoryRecord r = (HistoryRecord)mHistory.get(index);
return r.packageName;
@@ -5316,7 +5315,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
HistoryRecord activity = null;
if (type == INTENT_SENDER_ACTIVITY_RESULT) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return null;
}
@@ -6837,7 +6836,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
synchronized(this) {
if (r == null) {
- int index = indexOfTokenLocked(token, false);
+ int index = indexOfTokenLocked(token);
if (index < 0) {
return;
}
@@ -8943,7 +8942,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return false;
}
- private final int indexOfTokenLocked(IBinder token, boolean required) {
+ private final int indexOfTokenLocked(IBinder token) {
int count = mHistory.size();
// convert the token to an entry in the history.
@@ -8957,19 +8956,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
break;
}
}
- if (index < 0 && required) {
- RuntimeInit.crash(TAG, new InvalidTokenException(token));
- }
return index;
}
- static class InvalidTokenException extends Exception {
- InvalidTokenException(IBinder token) {
- super("Bad activity token: " + token);
- }
- }
-
private final void killServicesLocked(ProcessRecord app,
boolean allowRestart) {
// Report disconnected services.
@@ -9994,7 +9984,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HistoryRecord activity = null;
if (token != null) {
- int aindex = indexOfTokenLocked(token, false);
+ int aindex = indexOfTokenLocked(token);
if (aindex < 0) {
Log.w(TAG, "Binding with unknown activity: " + token);
return 0;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 42f8fac..c922cec 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -404,6 +404,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
mReconnectIntent = null;
}
+ setState(State.DISCONNECTING);
+
for (DataConnection connBase : dataConnectionList) {
CdmaDataConnection conn = (CdmaDataConnection) connBase;
@@ -419,24 +421,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
stopNetStatPoll();
- /*
- * If we've been asked to tear down the connection,
- * set the state to DISCONNECTING. However, there's
- * a race that can occur if for some reason we were
- * already in the IDLE state. In that case, the call
- * to conn.disconnect() above will immediately post
- * a message to the handler thread that the disconnect
- * is done, and if the handler runs before the code
- * below does, the handler will have set the state to
- * IDLE before the code below runs. If we didn't check
- * for that, future calls to trySetupData would fail,
- * and we would never get out of the DISCONNECTING state.
- */
if (!tearDown) {
setState(State.IDLE);
phone.notifyDataConnection(reason);
- } else if (state != State.IDLE) {
- setState(State.DISCONNECTING);
}
}
@@ -811,6 +798,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
resetPollStats();
}
} else {
+ // reset reconnect timer
+ nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
// in case data setup was attempted when we were on a voice call
trySetupData(Phone.REASON_VOICE_CALL_ENDED);
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 270f78b..71af406 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -636,6 +636,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
mReconnectIntent = null;
}
+ setState(State.DISCONNECTING);
+
for (DataConnection conn : pdpList) {
PdpConnection pdp = (PdpConnection) conn;
if (tearDown) {
@@ -647,25 +649,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
stopNetStatPoll();
- /*
- * If we've been asked to tear down the connection,
- * set the state to DISCONNECTING. However, there's
- * a race that can occur if for some reason we were
- * already in the IDLE state. In that case, the call
- * to pdp.disconnect() above will immediately post
- * a message to the handler thread that the disconnect
- * is done, and if the handler runs before the code
- * below does, the handler will have set the state to
- * IDLE before the code below runs. If we didn't check
- * for that, future calls to trySetupData would fail,
- * and we would never get out of the DISCONNECTING state.
- */
if (!tearDown) {
setState(State.IDLE);
phone.notifyDataConnection(reason);
mActiveApn = null;
- } else if (state != State.IDLE) {
- setState(State.DISCONNECTING);
}
}
@@ -813,6 +800,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (state != State.DISCONNECTING) {
cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
if (!isConnected) {
+ // reset reconnect timer
+ nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
trySetupData(Phone.REASON_APN_CHANGED);
}
}
@@ -1406,6 +1395,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
resetPollStats();
}
} else {
+ // reset reconnect timer
+ nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
// in case data setup was attempted when we were on a voice call
trySetupData(Phone.REASON_VOICE_CALL_ENDED);
}
diff --git a/tests/backup/src/com/android/backuptest/BackupTestAgent.java b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
index 11e520e..a370d69 100644
--- a/tests/backup/src/com/android/backuptest/BackupTestAgent.java
+++ b/tests/backup/src/com/android/backuptest/BackupTestAgent.java
@@ -30,7 +30,8 @@ public class BackupTestAgent extends BackupAgent
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
Log.d(TAG, "onBackup");
- FileBackupHelper.performBackup(this, oldState, data, newState, new String[] {
+ FileBackupHelper helper = new FileBackupHelper(this);
+ helper.performBackup(oldState, data, newState, new String[] {
BackupTestActivity.FILE_NAME
});
}