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

Commit d1582145 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Restore audio settings and wifi.

Optimize backups by writing an entity only if the checksum of the data has changed.
Call into the hidden AudioService API to apply changed audio settings.
After restoring wifi data, make sure that the permissions and ownership are set
properly for the supplicant process to access it.
Locale isn't restoring properly - TODO added.
parent 8a715b4b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -67,6 +67,12 @@ public class Process {
     */
    public static final int PHONE_UID = 1001;

    /**
     * Defines the UID/GID for the WIFI supplicant process.
     * @hide
     */
    public static final int WIFI_UID = 1010;

    /**
     * Defines the start of a range of UIDs (and GIDs), going from this
     * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
+83 −22
Original line number Diff line number Diff line
@@ -16,12 +16,16 @@

package com.android.providers.settings;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.EOFException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.zip.CRC32;

import android.backup.BackupDataInput;
import android.backup.BackupDataOutput;
@@ -34,7 +38,9 @@ import android.database.Cursor;
import android.media.AudioManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
@@ -52,6 +58,13 @@ public class SettingsBackupAgent extends BackupHelperAgent {
    private static final String KEY_SYNC = "sync_providers";
    private static final String KEY_LOCALE = "locale";

    private static final int STATE_SYSTEM = 0;
    private static final int STATE_SECURE = 1;
    private static final int STATE_SYNC   = 2;
    private static final int STATE_LOCALE = 3;
    private static final int STATE_WIFI   = 4;
    private static final int STATE_SIZE   = 5; // The number of state items

    private static String[] sortedSystemKeys = null;
    private static String[] sortedSecureKeys = null;

@@ -87,20 +100,22 @@ public class SettingsBackupAgent extends BackupHelperAgent {
        byte[] secureSettingsData = getSecureSettings();
        byte[] syncProviders = mSettingsHelper.getSyncProviders();
        byte[] locale = mSettingsHelper.getLocaleData();
        byte[] wifiData = getFileData(FILE_WIFI_SUPPLICANT);

        data.writeEntityHeader(KEY_SYSTEM, systemSettingsData.length);
        data.writeEntityData(systemSettingsData, systemSettingsData.length);

        data.writeEntityHeader(KEY_SECURE, secureSettingsData.length);
        data.writeEntityData(secureSettingsData, secureSettingsData.length);

        data.writeEntityHeader(KEY_SYNC, syncProviders.length);
        data.writeEntityData(syncProviders, syncProviders.length);
        long[] stateChecksums = readOldChecksums(oldState);

        data.writeEntityHeader(KEY_LOCALE, locale.length);
        data.writeEntityData(locale, locale.length);
        stateChecksums[STATE_SYSTEM] =
                writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
        stateChecksums[STATE_SECURE] =
                writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
        stateChecksums[STATE_SYNC] =
                writeIfChanged(stateChecksums[STATE_SYNC], KEY_SYNC, syncProviders, data);
        stateChecksums[STATE_LOCALE] =
                writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
        stateChecksums[STATE_WIFI] =
                writeIfChanged(stateChecksums[STATE_WIFI], FILE_WIFI_SUPPLICANT, wifiData, data);

        backupFile(FILE_WIFI_SUPPLICANT, data);
        writeNewChecksums(stateChecksums, newState);
    }

    @Override
@@ -115,11 +130,15 @@ public class SettingsBackupAgent extends BackupHelperAgent {
            final int size = data.getDataSize();
            if (KEY_SYSTEM.equals(key)) {
                restoreSettings(data, Settings.System.CONTENT_URI);
                mSettingsHelper.applyAudioSettings();
            } else if (KEY_SECURE.equals(key)) {
                restoreSettings(data, Settings.Secure.CONTENT_URI);
// TODO: Re-enable WIFI restore when we figure out a solution for the permissions
//            } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
//                restoreFile(FILE_WIFI_SUPPLICANT, data);
            } else if (FILE_WIFI_SUPPLICANT.equals(key)) {
                restoreFile(FILE_WIFI_SUPPLICANT, data);
                FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
                        FileUtils.S_IRUSR | FileUtils.S_IWUSR |
                        FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                        Process.myUid(), Process.WIFI_UID);
            } else if (KEY_SYNC.equals(key)) {
                mSettingsHelper.setSyncProviders(data);
            } else if (KEY_LOCALE.equals(key)) {
@@ -132,6 +151,49 @@ public class SettingsBackupAgent extends BackupHelperAgent {
        }
    }

    private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
        long[] stateChecksums = new long[STATE_SIZE];

        DataInputStream dataInput = new DataInputStream(
                new FileInputStream(oldState.getFileDescriptor()));
        for (int i = 0; i < STATE_SIZE; i++) {
            try {
                stateChecksums[i] = dataInput.readLong();
            } catch (EOFException eof) {
                break;
            }
        }
        dataInput.close();
        return stateChecksums;
    }

    private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
            throws IOException {
        DataOutputStream dataOutput = new DataOutputStream(
                new FileOutputStream(newState.getFileDescriptor()));
        for (int i = 0; i < STATE_SIZE; i++) {
            dataOutput.writeLong(checksums[i]);
        }
        dataOutput.close();
    }

    private long writeIfChanged(long oldChecksum, String key, byte[] data,
            BackupDataOutput output) {
        CRC32 checkSummer = new CRC32();
        checkSummer.update(data);
        long newChecksum = checkSummer.getValue();
        if (oldChecksum == newChecksum) {
            return oldChecksum;
        }
        try {
            output.writeEntityHeader(key, data.length);
            output.writeEntityData(data, data.length);
        } catch (IOException ioe) {
            // Bail
        }
        return newChecksum;
    }

    private byte[] getSystemSettings() {
        Cursor sortedCursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION,
                null, null, Settings.NameValueTable.NAME);
@@ -248,7 +310,7 @@ public class SettingsBackupAgent extends BackupHelperAgent {
        return result;
    }

    private void backupFile(String filename, BackupDataOutput data) {
    private byte[] getFileData(String filename) {
        try {
            File file = new File(filename);
            if (file.exists()) {
@@ -260,14 +322,13 @@ public class SettingsBackupAgent extends BackupHelperAgent {
                    got = fis.read(bytes, offset, bytes.length - offset);
                    if (got > 0) offset += got;
                } while (offset < bytes.length && got > 0);
                data.writeEntityHeader(filename, bytes.length);
                data.writeEntityData(bytes, bytes.length);
                return bytes;
            } else {
                data.writeEntityHeader(filename, 0);
                data.writeEntityData(EMPTY_DATA, 0);
                return EMPTY_DATA;
            }
        } catch (IOException ioe) {
            Log.w(TAG, "Couldn't backup " + filename);
            return EMPTY_DATA;
        }
    }

+11 −0
Original line number Diff line number Diff line
@@ -167,6 +167,9 @@ public class SettingsHelper {
        // Check if locale was set by the user:
        Configuration conf = mContext.getResources().getConfiguration();
        Locale loc = conf.locale;
        // TODO: The following is not working as intended because the network is forcing a locale
        // change after registering. Need to find some other way to detect if the user manually
        // changed the locale
        if (conf.userSetLocale) return; // Don't change if user set it in the SetupWizard

        final String[] availableLocales = mContext.getAssets().getLocales();
@@ -193,6 +196,14 @@ public class SettingsHelper {
        } catch (RemoteException e) {
            // Intentionally left blank
        }
    }

    /**
     * Informs the audio service of changes to the settings so that
     * they can be re-read and applied.
     */
    void applyAudioSettings() {
        AudioManager am = new AudioManager(mContext);
        am.reloadAudioSettings();
    }
}
+6 −1
Original line number Diff line number Diff line
@@ -126,11 +126,14 @@ public class SettingsProvider extends ContentProvider {
        // a notification and then using the contract class to get their data,
        // the system property will be updated and they'll get the new data.

        boolean backedUpDataChanged = false;
        String property = null, table = uri.getPathSegments().get(0);
        if (table.equals("system")) {
            property = Settings.System.SYS_PROP_SETTING_VERSION;
            backedUpDataChanged = true;
        } else if (table.equals("secure")) {
            property = Settings.Secure.SYS_PROP_SETTING_VERSION;
            backedUpDataChanged = true;
        } else if (table.equals("gservices")) {
            property = Settings.Gservices.SYS_PROP_SETTING_VERSION;
        }
@@ -142,7 +145,9 @@ public class SettingsProvider extends ContentProvider {
        }

        // Inform the backup manager about a data change
        if (backedUpDataChanged) {
            mBackupManager.dataChanged();
        }
        // Now send the notification through the content framework.

        String notify = uri.getQueryParameter("notify");