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

Commit 4a025d30 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Teach DeskClock about file-based encryption.

When running on a device that supports FBE, all persisted data is
stored in the device-encrypted area.  Also mark core components as
being encryption-aware so we can schedule and trigger alarms while
the user is still locked.

Bug: 25860525
Change-Id: I7517be716468b09eed0c007600abd1937e203449
parent 942b3a39
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -48,7 +48,8 @@

        <provider android:name=".provider.ClockProvider"
                android:authorities="com.android.deskclock"
                android:exported="false" />
                android:exported="false"
                android:encryptionAware="true" />

        <activity android:name="DeskClock"
                android:label="@string/app_label"
@@ -105,7 +106,8 @@
                android:excludeFromRecents="true"
                android:theme="@style/AlarmAlertFullScreenTheme"
                android:windowSoftInputMode="stateAlwaysHidden"
                android:showOnLockScreen="true" />
                android:showOnLockScreen="true"
                android:encryptionAware="true" />

        <activity android:name="ScreensaverActivity"
                android:excludeFromRecents="true"
@@ -114,11 +116,13 @@
                android:configChanges="orientation|screenSize|keyboardHidden|keyboard" />

        <receiver android:name=".alarms.AlarmStateManager"
                  android:exported="false">
                  android:exported="false"
                  android:encryptionAware="true">
        </receiver>

        <service android:name=".alarms.AlarmService"
                 android:exported="false">
                 android:exported="false"
                 android:encryptionAware="true">
        </service>

        <activity android:name="HandleApiCalls"
@@ -232,8 +236,10 @@
            </intent-filter>
        </activity>

        <receiver android:name="AlarmInitReceiver">
        <receiver android:name="AlarmInitReceiver"
                android:encryptionAware="true">
            <intent-filter>
                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.TIME_SET" />
                <action android:name="android.intent.action.TIMEZONE_CHANGED" />
+11 −3
Original line number Diff line number Diff line
@@ -21,10 +21,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.PowerManager.WakeLock;
import android.preference.PreferenceManager;

import com.android.deskclock.alarms.AlarmStateManager;

import com.android.deskclock.timer.TimerObj;

public class AlarmInitReceiver extends BroadcastReceiver {
@@ -58,8 +56,18 @@ public class AlarmInitReceiver extends BroadcastReceiver {

        AsyncHandler.post(new Runnable() {
            @Override public void run() {
                // When running on N devices, we're interested in the boot
                // completed event that is sent while the user is still locked,
                // so that we can schedule alarms.
                final boolean bootCompleted;
                if (Utils.isNOrLater()) {
                    bootCompleted = Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action);
                } else {
                    bootCompleted = Intent.ACTION_BOOT_COMPLETED.equals(action);
                }

                try {
                    if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
                    if (bootCompleted) {
                        // Clear stopwatch and timers data
                        final SharedPreferences prefs =
                                Utils.getDefaultSharedPreferences(context);
+5 −11
Original line number Diff line number Diff line
@@ -83,21 +83,15 @@ public class DeskClockBackupAgent extends BackupAgent {
     */
    @Override
    public void onRestoreFinished() {
        if (Utils.isNOrLater()) {
            // TODO: migrate restored database and preferences over into
            // the device-encrypted storage area
        }

        // Write a preference to indicate a data restore has been completed.
        final SharedPreferences prefs = Utils.getDefaultSharedPreferences(this);
        prefs.edit().putBoolean(KEY_RESTORE_FINISHED, true).apply();

        // If device boot is not yet completed, use ACTION_BOOT_COMPLETED to trigger completion of
        // the data restore process at a safer time.
        if (registerReceiver(null, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)) != null) {
            LogUtils.i(TAG, "Waiting for %s to complete the data restore",
                    Intent.ACTION_BOOT_COMPLETED);
            return;
        }

        // Otherwise, the device is already booted, so schedule a custom broadcast to start the
        // application in 10 seconds.

        // Create an Intent to send into DeskClock indicating restore is complete.
        final PendingIntent restoreIntent = PendingIntent.getBroadcast(this, 0,
                new Intent(ACTION_COMPLETE_RESTORE).setClass(this, AlarmInitReceiver.class),
+30 −1
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ import android.os.Handler;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.v4.content.ContextCompat;
import android.support.v4.os.BuildCompat;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -48,6 +50,7 @@ import android.text.format.Time;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
@@ -61,6 +64,7 @@ import com.android.deskclock.stopwatch.Stopwatches;
import com.android.deskclock.timer.Timers;
import com.android.deskclock.worldclock.CityObj;

import java.io.File;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -171,6 +175,13 @@ public class Utils {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }

    /**
     * @return {@code true} if the device is {@link Build.VERSION_CODES#N} or later
     */
    public static boolean isNOrLater() {
        return BuildCompat.isAtLeastN();
    }

    public static void prepareHelpMenuItem(Context context, MenuItem helpMenuItem) {
        String helpUrlString = context.getResources().getString(R.string.desk_clock_help_url);
        if (TextUtils.isEmpty(helpUrlString)) {
@@ -816,7 +827,25 @@ public class Utils {
        return context.getResources().getQuantityString(id, quantity, localizedQuantity);
    }

    /**
     * Return the default shared preferences.
     */
    public static SharedPreferences getDefaultSharedPreferences(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context);
        final Context storageContext;
        if (isNOrLater()) {
            // All N devices have split storage areas, but we may need to
            // migrate existing preferences into the new device encrypted
            // storage area, which is where our data lives from now on.
            final Context deviceContext = context.createDeviceEncryptedStorageContext();
            if (!deviceContext.migrateSharedPreferencesFrom(context,
                    PreferenceManager.getDefaultSharedPreferencesName(context))) {
                LogUtils.wtf("Failed to migrate shared preferences");
            }
            storageContext = deviceContext;
        } else {
            storageContext = context;
        }

        return PreferenceManager.getDefaultSharedPreferences(storageContext);
    }
}
+19 −1
Original line number Diff line number Diff line
@@ -19,14 +19,17 @@ package com.android.deskclock.provider;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.text.TextUtils;

import com.android.deskclock.LogUtils;
import com.android.deskclock.Utils;

public class ClockProvider extends ContentProvider {
    private ClockDatabaseHelper mOpenHelper;
@@ -53,7 +56,22 @@ public class ClockProvider extends ContentProvider {

    @Override
    public boolean onCreate() {
        mOpenHelper = new ClockDatabaseHelper(getContext());
        final Context context = getContext();
        final Context storageContext;
        if (Utils.isNOrLater()) {
            // All N devices have split storage areas, but we may need to
            // migrate existing database into the new device encrypted
            // storage area, which is where our data lives from now on.
            final Context deviceContext = context.createDeviceEncryptedStorageContext();
            if (!deviceContext.migrateDatabaseFrom(context, ClockDatabaseHelper.DATABASE_NAME)) {
                LogUtils.wtf("Failed to migrate database");
            }
            storageContext = deviceContext;
        } else {
            storageContext = context;
        }

        mOpenHelper = new ClockDatabaseHelper(storageContext);
        return true;
    }