Skip to content

Commit c408a5d

Browse files
Adam CohenAndroid (Google) Code Review
authored andcommitted
Merge "Fixing issue where widgets file was getting blown away, issue: 5036321" into ics-mr0
2 parents b14b2c2 + 9730031 commit c408a5d

File tree

1 file changed

+57
-108
lines changed

1 file changed

+57
-108
lines changed

services/java/com/android/server/AppWidgetService.java

Lines changed: 57 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,6 @@
1616

1717
package com.android.server;
1818

19-
import java.io.File;
20-
import java.io.FileDescriptor;
21-
import java.io.FileInputStream;
22-
import java.io.FileOutputStream;
23-
import java.io.IOException;
24-
import java.io.PrintWriter;
25-
import java.util.ArrayList;
26-
import java.util.HashMap;
27-
import java.util.HashSet;
28-
import java.util.Iterator;
29-
import java.util.List;
30-
import java.util.Locale;
31-
32-
import org.apache.commons.logging.impl.SimpleLog;
33-
import org.xmlpull.v1.XmlPullParser;
34-
import org.xmlpull.v1.XmlPullParserException;
35-
import org.xmlpull.v1.XmlSerializer;
36-
3719
import android.app.AlarmManager;
3820
import android.app.PendingIntent;
3921
import android.appwidget.AppWidgetManager;
@@ -42,9 +24,9 @@
4224
import android.content.ComponentName;
4325
import android.content.Context;
4426
import android.content.Intent;
45-
import android.content.Intent.FilterComparison;
4627
import android.content.IntentFilter;
4728
import android.content.ServiceConnection;
29+
import android.content.Intent.FilterComparison;
4830
import android.content.pm.ActivityInfo;
4931
import android.content.pm.ApplicationInfo;
5032
import android.content.pm.PackageInfo;
@@ -58,7 +40,6 @@
5840
import android.os.Binder;
5941
import android.os.Bundle;
6042
import android.os.IBinder;
61-
import android.os.Process;
6243
import android.os.RemoteException;
6344
import android.os.SystemClock;
6445
import android.util.AttributeSet;
@@ -68,20 +49,37 @@
6849
import android.util.TypedValue;
6950
import android.util.Xml;
7051
import android.widget.RemoteViews;
71-
import android.widget.RemoteViewsService;
7252

7353
import com.android.internal.appwidget.IAppWidgetHost;
7454
import com.android.internal.appwidget.IAppWidgetService;
55+
import com.android.internal.os.AtomicFile;
7556
import com.android.internal.util.FastXmlSerializer;
7657
import com.android.internal.widget.IRemoteViewsAdapterConnection;
7758
import com.android.internal.widget.IRemoteViewsFactory;
7859

60+
import org.xmlpull.v1.XmlPullParser;
61+
import org.xmlpull.v1.XmlPullParserException;
62+
import org.xmlpull.v1.XmlSerializer;
63+
64+
import java.io.File;
65+
import java.io.FileDescriptor;
66+
import java.io.FileInputStream;
67+
import java.io.FileNotFoundException;
68+
import java.io.FileOutputStream;
69+
import java.io.IOException;
70+
import java.io.PrintWriter;
71+
import java.util.ArrayList;
72+
import java.util.HashMap;
73+
import java.util.HashSet;
74+
import java.util.Iterator;
75+
import java.util.List;
76+
import java.util.Locale;
77+
7978
class AppWidgetService extends IAppWidgetService.Stub
8079
{
8180
private static final String TAG = "AppWidgetService";
8281

8382
private static final String SETTINGS_FILENAME = "appwidgets.xml";
84-
private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp";
8583
private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
8684

8785
/*
@@ -1159,70 +1157,46 @@ void sendInitialBroadcasts() {
11591157

11601158
// only call from initialization -- it assumes that the data structures are all empty
11611159
void loadStateLocked() {
1162-
File temp = savedStateTempFile();
1163-
File real = savedStateRealFile();
1164-
1165-
// prefer the real file. If it doesn't exist, use the temp one, and then copy it to the
1166-
// real one. if there is both a real file and a temp one, assume that the temp one isn't
1167-
// fully written and delete it.
1168-
if (real.exists()) {
1169-
readStateFromFileLocked(real);
1170-
if (temp.exists()) {
1171-
//noinspection ResultOfMethodCallIgnored
1172-
temp.delete();
1160+
AtomicFile file = savedStateFile();
1161+
try {
1162+
FileInputStream stream = file.openRead();
1163+
readStateFromFileLocked(stream);
1164+
1165+
if (stream != null) {
1166+
try {
1167+
stream.close();
1168+
} catch (IOException e) {
1169+
Slog.w(TAG, "Failed to close state FileInputStream " + e);
1170+
}
11731171
}
1174-
} else if (temp.exists()) {
1175-
readStateFromFileLocked(temp);
1176-
//noinspection ResultOfMethodCallIgnored
1177-
temp.renameTo(real);
1172+
} catch (FileNotFoundException e) {
1173+
Slog.w(TAG, "Failed to read state: " + e);
11781174
}
11791175
}
1180-
1176+
11811177
void saveStateLocked() {
1182-
File temp = savedStateTempFile();
1183-
File real = savedStateRealFile();
1184-
1185-
if (!real.exists()) {
1186-
// If the real one doesn't exist, it's either because this is the first time
1187-
// or because something went wrong while copying them. In this case, we can't
1188-
// trust anything that's in temp. In order to have the loadState code not
1189-
// use the temporary one until it's fully written, create an empty file
1190-
// for real, which will we'll shortly delete.
1191-
try {
1192-
//noinspection ResultOfMethodCallIgnored
1193-
real.createNewFile();
1194-
} catch (IOException e) {
1195-
// Ignore
1178+
AtomicFile file = savedStateFile();
1179+
FileOutputStream stream;
1180+
try {
1181+
stream = file.startWrite();
1182+
if (writeStateToFileLocked(stream)) {
1183+
file.finishWrite(stream);
1184+
} else {
1185+
file.failWrite(stream);
1186+
Slog.w(TAG, "Failed to save state, restoring backup.");
11961187
}
1188+
} catch (IOException e) {
1189+
Slog.w(TAG, "Failed open state file for write: " + e);
11971190
}
1198-
1199-
if (temp.exists()) {
1200-
//noinspection ResultOfMethodCallIgnored
1201-
temp.delete();
1202-
}
1203-
1204-
if (!writeStateToFileLocked(temp)) {
1205-
Slog.w(TAG, "Failed to persist new settings");
1206-
return;
1207-
}
1208-
1209-
//noinspection ResultOfMethodCallIgnored
1210-
real.delete();
1211-
//noinspection ResultOfMethodCallIgnored
1212-
temp.renameTo(real);
12131191
}
12141192

1215-
boolean writeStateToFileLocked(File file) {
1216-
FileOutputStream stream = null;
1193+
boolean writeStateToFileLocked(FileOutputStream stream) {
12171194
int N;
12181195

12191196
try {
1220-
stream = new FileOutputStream(file, false);
12211197
XmlSerializer out = new FastXmlSerializer();
12221198
out.setOutput(stream, "utf-8");
12231199
out.startDocument(null, true);
1224-
1225-
12261200
out.startTag(null, "gs");
12271201

12281202
int providerIndex = 0;
@@ -1264,31 +1238,17 @@ boolean writeStateToFileLocked(File file) {
12641238
out.endTag(null, "gs");
12651239

12661240
out.endDocument();
1267-
stream.close();
12681241
return true;
12691242
} catch (IOException e) {
1270-
try {
1271-
if (stream != null) {
1272-
stream.close();
1273-
}
1274-
} catch (IOException ex) {
1275-
// Ignore
1276-
}
1277-
if (file.exists()) {
1278-
//noinspection ResultOfMethodCallIgnored
1279-
file.delete();
1280-
}
1243+
Slog.w(TAG, "Failed to write state: " + e);
12811244
return false;
12821245
}
12831246
}
12841247

1285-
void readStateFromFileLocked(File file) {
1286-
FileInputStream stream = null;
1287-
1248+
void readStateFromFileLocked(FileInputStream stream) {
12881249
boolean success = false;
12891250

12901251
try {
1291-
stream = new FileInputStream(file);
12921252
XmlPullParser parser = Xml.newPullParser();
12931253
parser.setInput(stream, null);
12941254

@@ -1390,22 +1350,15 @@ else if ("g".equals(tag)) {
13901350
} while (type != XmlPullParser.END_DOCUMENT);
13911351
success = true;
13921352
} catch (NullPointerException e) {
1393-
Slog.w(TAG, "failed parsing " + file, e);
1353+
Slog.w(TAG, "failed parsing " + e);
13941354
} catch (NumberFormatException e) {
1395-
Slog.w(TAG, "failed parsing " + file, e);
1355+
Slog.w(TAG, "failed parsing " + e);
13961356
} catch (XmlPullParserException e) {
1397-
Slog.w(TAG, "failed parsing " + file, e);
1357+
Slog.w(TAG, "failed parsing " + e);
13981358
} catch (IOException e) {
1399-
Slog.w(TAG, "failed parsing " + file, e);
1359+
Slog.w(TAG, "failed parsing " + e);
14001360
} catch (IndexOutOfBoundsException e) {
1401-
Slog.w(TAG, "failed parsing " + file, e);
1402-
}
1403-
try {
1404-
if (stream != null) {
1405-
stream.close();
1406-
}
1407-
} catch (IOException e) {
1408-
// Ignore
1361+
Slog.w(TAG, "failed parsing " + e);
14091362
}
14101363

14111364
if (success) {
@@ -1416,6 +1369,8 @@ else if ("g".equals(tag)) {
14161369
}
14171370
} else {
14181371
// failed reading, clean up
1372+
Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
1373+
14191374
mAppWidgetIds.clear();
14201375
mHosts.clear();
14211376
final int N = mInstalledProviders.size();
@@ -1425,14 +1380,8 @@ else if ("g".equals(tag)) {
14251380
}
14261381
}
14271382

1428-
File savedStateTempFile() {
1429-
return new File("/data/system/" + SETTINGS_TMP_FILENAME);
1430-
//return new File(mContext.getFilesDir(), SETTINGS_FILENAME);
1431-
}
1432-
1433-
File savedStateRealFile() {
1434-
return new File("/data/system/" + SETTINGS_FILENAME);
1435-
//return new File(mContext.getFilesDir(), SETTINGS_TMP_FILENAME);
1383+
AtomicFile savedStateFile() {
1384+
return new AtomicFile(new File("/data/system/" + SETTINGS_FILENAME));
14361385
}
14371386

14381387
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {

0 commit comments

Comments
 (0)