package com.noshufou.android.su.util; import com.noshufou.android.su.preferences.Preferences; import com.noshufou.android.su.provider.PermissionsProvider.Apps; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.database.Cursor; import android.os.Environment; import android.preference.PreferenceManager; import android.util.Log; import android.util.Xml; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Map; public class BackupUtil { private static final String TAG = "Su.BackupUtil"; public static boolean makeBackup(Context context) { boolean status = false; FileOutputStream file = null; XmlSerializer serializer = Xml.newSerializer(); try { file = new FileOutputStream( new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/subackup.xml")); serializer.setOutput(file, "UTF-8"); serializer.startDocument(null, true); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.startTag("", "backup"); status = backupApps(context, serializer); status = backupPrefs(context, serializer); serializer.endTag("", "backup"); serializer.endDocument(); serializer.flush(); file.close(); } catch (IllegalArgumentException e) { Log.e(TAG, "IllegalArgumentException", e); return false; } catch (IllegalStateException e) { Log.e(TAG, "IllegalStateException", e); return false; } catch (IOException e) { Log.e(TAG, "IOException", e); return false; } return status; } private static boolean backupApps(Context context, XmlSerializer serializer) { Cursor c = context.getContentResolver().query(Apps.CONTENT_URI, null, null, null, null); if (c == null) { return false; } else if (c.getCount() == 0) { c.close(); return true; } try { serializer.startTag("", "apps"); while (c.moveToNext()) { serializer.startTag("", "app"); serializer.attribute("", Apps.PACKAGE, c.getString(c.getColumnIndex(Apps.PACKAGE))); serializer.attribute("", Apps.NAME, c.getString(c.getColumnIndex(Apps.NAME))); serializer.attribute("", Apps.EXEC_UID, c.getString(c.getColumnIndex(Apps.EXEC_UID))); serializer.attribute("", Apps.EXEC_CMD, c.getString(c.getColumnIndex(Apps.EXEC_CMD))); serializer.attribute("", Apps.ALLOW, c.getString(c.getColumnIndex(Apps.ALLOW))); String notifications = c.getString(c.getColumnIndex(Apps.NOTIFICATIONS)); if (notifications != null) { serializer.attribute("", Apps.NOTIFICATIONS, notifications); } String logging = c.getString(c.getColumnIndex(Apps.LOGGING)); if (logging != null) { serializer.attribute("", Apps.LOGGING, logging); } serializer.endTag("", "app"); } serializer.endTag("", "apps"); } catch (IOException e) { Log.e(TAG, "Problem backing up apps", e); return false; } finally { if (c != null) { c.close(); } } return true; } private static boolean backupPrefs(Context context, XmlSerializer serializer) throws IOException { Map<String, ?> prefs = PreferenceManager.getDefaultSharedPreferences(context).getAll(); if (prefs.isEmpty()) { return true; } serializer.startTag("", "prefs"); for (String key: prefs.keySet()) { String type = "unknown"; if (!key.startsWith("pref_") && !key.equals("pin")) { continue; } Object value = prefs.get(key); if (value instanceof Boolean) { type = "boolean"; } else if (value instanceof String) { type = "string"; } else if (value instanceof Integer) { type = "int"; } else if (value instanceof Long) { type = "long"; } serializer.startTag("", type); serializer.attribute("", "name", key); if (type.equals("string")) { serializer.text(String.valueOf(value)); } else { serializer.attribute("", "value", String.valueOf(value)); } serializer.endTag("", type); } serializer.endTag("", "prefs"); return true; } public static int restoreBackup(Context context) { XmlPullParser parser = Xml.newPullParser(); FileInputStream file = null; int appsRestored = 0; try { file = new FileInputStream( new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/subackup.xml")); parser.setInput(file, "UTF-8"); int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_TAG: if (parser.getName().equalsIgnoreCase("apps")) { parser.next(); appsRestored = restoreApps(context, parser); } else if (parser.getName().equalsIgnoreCase("prefs")) { parser.next(); restorePrefs(context, parser); } break; } eventType = parser.next(); } } catch (XmlPullParserException e) { Log.e(TAG, "Error restoring backup", e); return -1; } catch (IOException e) { Log.e(TAG, "Error restoring backup", e); return -1; } return appsRestored; } private static int restoreApps(Context context, XmlPullParser parser) throws XmlPullParserException, IOException { int appsRestored = 0; PackageManager pm = context.getPackageManager(); ContentResolver cr = context.getContentResolver(); int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT && !(eventType == XmlPullParser.END_TAG && parser.getName().equalsIgnoreCase("apps"))) { if (eventType == XmlPullParser.START_TAG && parser.getName().equalsIgnoreCase("app")) { String pkg = parser.getAttributeValue("", Apps.PACKAGE); try { int uid = pm.getApplicationInfo(pkg, 0).uid; ContentValues values = new ContentValues(); values.put(Apps.UID, uid); for (int i = 0; i < parser.getAttributeCount(); i++) { values.put(parser.getAttributeName(i), parser.getAttributeValue(i)); } cr.insert(Apps.CONTENT_URI, values); appsRestored++; } catch (NameNotFoundException e) { Log.i(TAG, "package" + pkg + " not installed, skipping restore"); } } eventType = parser.next(); } return appsRestored; } private static void restorePrefs(Context context, XmlPullParser parser) throws XmlPullParserException, IOException { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences.Editor editor = prefs.edit(); editor.clear(); int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT && !(eventType == XmlPullParser.END_TAG && parser.getName().equalsIgnoreCase("prefs"))) { if (eventType == XmlPullParser.START_TAG) { if (parser.getName().equalsIgnoreCase("boolean")) { editor.putBoolean(parser.getAttributeValue("", "name"), Boolean.parseBoolean(parser.getAttributeValue("", "value"))); } else if (parser.getName().equalsIgnoreCase("string")) { editor.putString(parser.getAttributeValue("", "name"), parser.nextText()); } else if (parser.getName().equalsIgnoreCase("int")) { editor.putInt(parser.getAttributeValue("", "name"), Integer.parseInt(parser.getAttributeValue("", "value"))); } else if (parser.getName().equalsIgnoreCase("long")) { editor.putLong(parser.getAttributeValue("", "name"), Long.parseLong(parser.getAttributeValue("", "value"))); } } eventType = parser.next(); } editor.commit(); if (prefs.getBoolean(Preferences.PIN, false) && !prefs.contains("pin")) { prefs.edit().putBoolean(Preferences.PIN, false).commit(); } } }