Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9730031f authored by Adam Cohen's avatar Adam Cohen
Browse files

Fixing issue where widgets file was getting blown away, issue: 5036321

Change-Id: If40a9c79f70e11eee935b2dd2614e723423ff3bf
parent 99f36683
Loading
Loading
Loading
Loading
+57 −108
Original line number Diff line number Diff line
@@ -16,24 +16,6 @@

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.PendingIntent;
import android.appwidget.AppWidgetManager;
@@ -42,9 +24,9 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.Intent.FilterComparison;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.Intent.FilterComparison;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -58,7 +40,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -68,20 +49,37 @@ import android.util.Slog;
import android.util.TypedValue;
import android.util.Xml;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;

import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.AtomicFile;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.widget.IRemoteViewsAdapterConnection;
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
{
    private static final String TAG = "AppWidgetService";

    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

    /*
@@ -1159,70 +1157,46 @@ class AppWidgetService extends IAppWidgetService.Stub

    // only call from initialization -- it assumes that the data structures are all empty
    void loadStateLocked() {
        File temp = savedStateTempFile();
        File real = savedStateRealFile();
        AtomicFile file = savedStateFile();
        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
        // real one.  if there is both a real file and a temp one, assume that the temp one isn't
        // fully written and delete it.
        if (real.exists()) {
            readStateFromFileLocked(real);
            if (temp.exists()) {
                //noinspection ResultOfMethodCallIgnored
                temp.delete();
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    Slog.w(TAG, "Failed to close state FileInputStream " + e);
                }
            }
        } else if (temp.exists()) {
            readStateFromFileLocked(temp);
            //noinspection ResultOfMethodCallIgnored
            temp.renameTo(real);
        } catch (FileNotFoundException e) {
            Slog.w(TAG, "Failed to read state: " + e);
        }
    }

    void saveStateLocked() {
        File temp = savedStateTempFile();
        File real = savedStateRealFile();

        if (!real.exists()) {
            // If the real one doesn't exist, it's either because this is the first time
            // or because something went wrong while copying them.  In this case, we can't
            // trust anything that's in temp.  In order to have the loadState code not
            // use the temporary one until it's fully written, create an empty file
            // for real, which will we'll shortly delete.
        AtomicFile file = savedStateFile();
        FileOutputStream stream;
        try {
                //noinspection ResultOfMethodCallIgnored
                real.createNewFile();
            } catch (IOException e) {
                // Ignore
            }
        }

        if (temp.exists()) {
            //noinspection ResultOfMethodCallIgnored
            temp.delete();
            stream = file.startWrite();
            if (writeStateToFileLocked(stream)) {
                file.finishWrite(stream);
            } else {
                file.failWrite(stream);
                Slog.w(TAG, "Failed to save state, restoring backup.");
            }

        if (!writeStateToFileLocked(temp)) {
            Slog.w(TAG, "Failed to persist new settings");
            return;
        } catch (IOException e) {
            Slog.w(TAG, "Failed open state file for write: " + e);
        }

        //noinspection ResultOfMethodCallIgnored
        real.delete();
        //noinspection ResultOfMethodCallIgnored
        temp.renameTo(real);
    }

    boolean writeStateToFileLocked(File file) {
        FileOutputStream stream = null;
    boolean writeStateToFileLocked(FileOutputStream stream) {
        int N;

        try {
            stream = new FileOutputStream(file, false);
            XmlSerializer out = new FastXmlSerializer();
            out.setOutput(stream, "utf-8");
            out.startDocument(null, true);

            
            out.startTag(null, "gs");

            int providerIndex = 0;
@@ -1264,31 +1238,17 @@ class AppWidgetService extends IAppWidgetService.Stub
            out.endTag(null, "gs");

            out.endDocument();
            stream.close();
            return true;
        } catch (IOException e) {
            try {
                if (stream != null) {
                    stream.close();
                }
            } catch (IOException ex) {
                // Ignore
            }
            if (file.exists()) {
                //noinspection ResultOfMethodCallIgnored
                file.delete();
            }
            Slog.w(TAG, "Failed to write state: " + e);
            return false;
        }
    }

    void readStateFromFileLocked(File file) {
        FileInputStream stream = null;

    void readStateFromFileLocked(FileInputStream stream) {
        boolean success = false;

        try {
            stream = new FileInputStream(file);
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(stream, null);

@@ -1390,22 +1350,15 @@ class AppWidgetService extends IAppWidgetService.Stub
            } while (type != XmlPullParser.END_DOCUMENT);
            success = true;
        } catch (NullPointerException e) {
            Slog.w(TAG, "failed parsing " + file, e);
            Slog.w(TAG, "failed parsing " + e);
        } catch (NumberFormatException e) {
            Slog.w(TAG, "failed parsing " + file, e);
            Slog.w(TAG, "failed parsing " + e);
        } catch (XmlPullParserException e) {
            Slog.w(TAG, "failed parsing " + file, e);
            Slog.w(TAG, "failed parsing " + e);
        } catch (IOException e) {
            Slog.w(TAG, "failed parsing " + file, e);
            Slog.w(TAG, "failed parsing " + e);
        } catch (IndexOutOfBoundsException e) {
            Slog.w(TAG, "failed parsing " + file, e);
        }
        try {
            if (stream != null) {
                stream.close();
            }
        } catch (IOException e) {
            // Ignore
            Slog.w(TAG, "failed parsing " + e);
        }

        if (success) {
@@ -1416,6 +1369,8 @@ class AppWidgetService extends IAppWidgetService.Stub
            }
        } else {
            // failed reading, clean up
            Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");

            mAppWidgetIds.clear();
            mHosts.clear();
            final int N = mInstalledProviders.size();
@@ -1425,14 +1380,8 @@ class AppWidgetService extends IAppWidgetService.Stub
        }
    }

    File savedStateTempFile() {
        return new File("/data/system/" + SETTINGS_TMP_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);
    AtomicFile savedStateFile() {
        return new AtomicFile(new File("/data/system/" + SETTINGS_FILENAME));
    }

    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {