1616
1717package 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-
3719import android .app .AlarmManager ;
3820import android .app .PendingIntent ;
3921import android .appwidget .AppWidgetManager ;
4224import android .content .ComponentName ;
4325import android .content .Context ;
4426import android .content .Intent ;
45- import android .content .Intent .FilterComparison ;
4627import android .content .IntentFilter ;
4728import android .content .ServiceConnection ;
29+ import android .content .Intent .FilterComparison ;
4830import android .content .pm .ActivityInfo ;
4931import android .content .pm .ApplicationInfo ;
5032import android .content .pm .PackageInfo ;
5840import android .os .Binder ;
5941import android .os .Bundle ;
6042import android .os .IBinder ;
61- import android .os .Process ;
6243import android .os .RemoteException ;
6344import android .os .SystemClock ;
6445import android .util .AttributeSet ;
6849import android .util .TypedValue ;
6950import android .util .Xml ;
7051import android .widget .RemoteViews ;
71- import android .widget .RemoteViewsService ;
7252
7353import com .android .internal .appwidget .IAppWidgetHost ;
7454import com .android .internal .appwidget .IAppWidgetService ;
55+ import com .android .internal .os .AtomicFile ;
7556import com .android .internal .util .FastXmlSerializer ;
7657import com .android .internal .widget .IRemoteViewsAdapterConnection ;
7758import 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+
7978class 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