am c408a5d5: Merge "Fixing issue where widgets file was getting blown away, issue: 5036321" into ics-mr0

* commit 'c408a5d5738c84160a7e9a8299c953ea638bcef4':
  Fixing issue where widgets file was getting blown away, issue: 5036321
This commit is contained in:
Adam Cohen
2011-10-13 13:40:01 -07:00
committed by Android Git Automerger

View File

@@ -16,24 +16,6 @@
package com.android.server; package com.android.server;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.apache.commons.logging.impl.SimpleLog;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManager;
@@ -42,9 +24,9 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.Intent.FilterComparison;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.Intent.FilterComparison;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
@@ -58,7 +40,6 @@ import android.net.Uri;
import android.os.Binder; import android.os.Binder;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.AttributeSet; import android.util.AttributeSet;
@@ -68,20 +49,37 @@ import android.util.Slog;
import android.util.TypedValue; import android.util.TypedValue;
import android.util.Xml; import android.util.Xml;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
import com.android.internal.appwidget.IAppWidgetHost; import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.AtomicFile;
import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FastXmlSerializer;
import com.android.internal.widget.IRemoteViewsAdapterConnection; import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory; import com.android.internal.widget.IRemoteViewsFactory;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
class AppWidgetService extends IAppWidgetService.Stub class AppWidgetService extends IAppWidgetService.Stub
{ {
private static final String TAG = "AppWidgetService"; private static final String TAG = "AppWidgetService";
private static final String SETTINGS_FILENAME = "appwidgets.xml"; private static final String SETTINGS_FILENAME = "appwidgets.xml";
private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp";
private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
/* /*
@@ -1159,70 +1157,46 @@ class AppWidgetService extends IAppWidgetService.Stub
// only call from initialization -- it assumes that the data structures are all empty // only call from initialization -- it assumes that the data structures are all empty
void loadStateLocked() { void loadStateLocked() {
File temp = savedStateTempFile(); AtomicFile file = savedStateFile();
File real = savedStateRealFile(); try {
FileInputStream stream = file.openRead();
readStateFromFileLocked(stream);
// prefer the real file. If it doesn't exist, use the temp one, and then copy it to the if (stream != null) {
// real one. if there is both a real file and a temp one, assume that the temp one isn't try {
// fully written and delete it. stream.close();
if (real.exists()) { } catch (IOException e) {
readStateFromFileLocked(real); Slog.w(TAG, "Failed to close state FileInputStream " + e);
if (temp.exists()) { }
//noinspection ResultOfMethodCallIgnored
temp.delete();
} }
} else if (temp.exists()) { } catch (FileNotFoundException e) {
readStateFromFileLocked(temp); Slog.w(TAG, "Failed to read state: " + e);
//noinspection ResultOfMethodCallIgnored
temp.renameTo(real);
} }
} }
void saveStateLocked() { void saveStateLocked() {
File temp = savedStateTempFile(); AtomicFile file = savedStateFile();
File real = savedStateRealFile(); FileOutputStream stream;
try {
if (!real.exists()) { stream = file.startWrite();
// If the real one doesn't exist, it's either because this is the first time if (writeStateToFileLocked(stream)) {
// or because something went wrong while copying them. In this case, we can't file.finishWrite(stream);
// trust anything that's in temp. In order to have the loadState code not } else {
// use the temporary one until it's fully written, create an empty file file.failWrite(stream);
// for real, which will we'll shortly delete. Slog.w(TAG, "Failed to save state, restoring backup.");
try {
//noinspection ResultOfMethodCallIgnored
real.createNewFile();
} catch (IOException e) {
// Ignore
} }
} catch (IOException e) {
Slog.w(TAG, "Failed open state file for write: " + e);
} }
if (temp.exists()) {
//noinspection ResultOfMethodCallIgnored
temp.delete();
}
if (!writeStateToFileLocked(temp)) {
Slog.w(TAG, "Failed to persist new settings");
return;
}
//noinspection ResultOfMethodCallIgnored
real.delete();
//noinspection ResultOfMethodCallIgnored
temp.renameTo(real);
} }
boolean writeStateToFileLocked(File file) { boolean writeStateToFileLocked(FileOutputStream stream) {
FileOutputStream stream = null;
int N; int N;
try { try {
stream = new FileOutputStream(file, false);
XmlSerializer out = new FastXmlSerializer(); XmlSerializer out = new FastXmlSerializer();
out.setOutput(stream, "utf-8"); out.setOutput(stream, "utf-8");
out.startDocument(null, true); out.startDocument(null, true);
out.startTag(null, "gs"); out.startTag(null, "gs");
int providerIndex = 0; int providerIndex = 0;
@@ -1264,31 +1238,17 @@ class AppWidgetService extends IAppWidgetService.Stub
out.endTag(null, "gs"); out.endTag(null, "gs");
out.endDocument(); out.endDocument();
stream.close();
return true; return true;
} catch (IOException e) { } catch (IOException e) {
try { Slog.w(TAG, "Failed to write state: " + e);
if (stream != null) {
stream.close();
}
} catch (IOException ex) {
// Ignore
}
if (file.exists()) {
//noinspection ResultOfMethodCallIgnored
file.delete();
}
return false; return false;
} }
} }
void readStateFromFileLocked(File file) { void readStateFromFileLocked(FileInputStream stream) {
FileInputStream stream = null;
boolean success = false; boolean success = false;
try { try {
stream = new FileInputStream(file);
XmlPullParser parser = Xml.newPullParser(); XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, null); parser.setInput(stream, null);
@@ -1390,22 +1350,15 @@ class AppWidgetService extends IAppWidgetService.Stub
} while (type != XmlPullParser.END_DOCUMENT); } while (type != XmlPullParser.END_DOCUMENT);
success = true; success = true;
} catch (NullPointerException e) { } catch (NullPointerException e) {
Slog.w(TAG, "failed parsing " + file, e); Slog.w(TAG, "failed parsing " + e);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Slog.w(TAG, "failed parsing " + file, e); Slog.w(TAG, "failed parsing " + e);
} catch (XmlPullParserException e) { } catch (XmlPullParserException e) {
Slog.w(TAG, "failed parsing " + file, e); Slog.w(TAG, "failed parsing " + e);
} catch (IOException e) { } catch (IOException e) {
Slog.w(TAG, "failed parsing " + file, e); Slog.w(TAG, "failed parsing " + e);
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
Slog.w(TAG, "failed parsing " + file, e); Slog.w(TAG, "failed parsing " + e);
}
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {
// Ignore
} }
if (success) { if (success) {
@@ -1416,6 +1369,8 @@ class AppWidgetService extends IAppWidgetService.Stub
} }
} else { } else {
// failed reading, clean up // failed reading, clean up
Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
mAppWidgetIds.clear(); mAppWidgetIds.clear();
mHosts.clear(); mHosts.clear();
final int N = mInstalledProviders.size(); final int N = mInstalledProviders.size();
@@ -1425,14 +1380,8 @@ class AppWidgetService extends IAppWidgetService.Stub
} }
} }
File savedStateTempFile() { AtomicFile savedStateFile() {
return new File("/data/system/" + SETTINGS_TMP_FILENAME); return new AtomicFile(new File("/data/system/" + SETTINGS_FILENAME));
//return new File(mContext.getFilesDir(), SETTINGS_FILENAME);
}
File savedStateRealFile() {
return new File("/data/system/" + SETTINGS_FILENAME);
//return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME);
} }
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {