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

Commit 6a4dfa59 authored by Mao Jinlong's avatar Mao Jinlong Committed by Linux Build Service Account
Browse files

Add support for power off alarm

1. Only install power off alarm apps;
Power off alarm should be least affected when it is firing. There
should be no other applications with notifications and sounds(eg.
phone application and message application). So when it is alarm
boot, we should only install necessary applications for power off
alarm and system's boot-up.

We need to ensure that power off alarm works on both normal status
and encrypt status.

2. Use file in persist folder to save alarm status and instance time;
We need to distinguish power off alarm from other applications which
use RTC_POWEROFF_WAKEUP alarm type. And it should also work when
vold.decrypt property is trigger_restart_min_framework or "1". As
in this state, android system only has temporary data partition.

File in persist folder can be used in any status.

Change-Id: I7f85a2a7e1d06b69ddb74f376435518314105500
parent 2799b392
Loading
Loading
Loading
Loading
+90 −0
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@ import android.util.Log;

import libcore.util.ZoneInfoDB;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
@@ -115,6 +118,42 @@ public class AlarmManager {
     */
    public static final int RTC_POWEROFF_WAKEUP = 5;

    /**
     * File to save value to indicate that power off alarm is set
     * @hide
     */
    public static final String POWER_OFF_ALARM_SET_FILE =
            "/persist/alarm/powerOffAlarmSet";
    /**
     * File to indicate that if power off alarm is handled in
     * encryption status.
     * @hide
     */
    public static final String POWER_OFF_ALARM_HANDLE_FILE =
            "/persist/alarm/powerOffAlarmHandle";
    /**
     * File to save instance time which will handle in encryption status.
     * @hide
     */
    public static final String POWER_OFF_ALARM_INSTANCE_FILE =
            "/persist/alarm/powerOffAlarmInstance";
    /**
     * @hide
     */
    public static final String POWER_OFF_ALARM_SET = "1";
    /**
     * @hide
     */
    public static final String POWER_OFF_ALARM_NOT_SET = "0";
    /**
     * @hide
     */
    public static final String POWER_OFF_ALARM_NOT_HANDLED = "0";
    /**
     * @hide
     */
    public static final String POWER_OFF_ALARM_HANDLED = "1";

    /**
     * Broadcast Action: Sent after the value returned by
     * {@link #getNextAlarmClock()} has changed.
@@ -1040,6 +1079,57 @@ public class AlarmManager {
        }
    }


    /**
     * Read value from power off alarm files
     *
     * @hide
     */
    public static String readPowerOffAlarmFile(String fileName) {
        BufferedReader reader = null;
        String line = null;
        try {
            reader = new BufferedReader(new FileReader(fileName));
            line = reader.readLine();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
        return line;
    }


    /**
     * Write value to power off alarm files
     *
     * @hide
     */
    public static void writePowerOffAlarmFile(String fileName, String value) {
        FileWriter writer = null;
        try {
            writer = new FileWriter(fileName, false);
            writer.write(value);
            writer.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    /**
     * An immutable description of a scheduled "alarm clock" event.
     *
+51 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.app.ActivityManager;
import android.content.Context;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -161,6 +162,8 @@ public class PackageParser {
    private static final String TAG_PACKAGE = "package";
    private static final String TAG_RESTRICT_UPDATE = "restrict-update";

    private Context mContext;

    // These are the tags supported by child packages
    private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
    static {
@@ -254,6 +257,7 @@ public class PackageParser {
    private String[] mSeparateProcesses;
    private boolean mOnlyCoreApps;
    private DisplayMetrics mMetrics;
    private boolean mOnlyPowerOffAlarmApps;

    private static final int SDK_VERSION = Build.VERSION.SDK_INT;
    private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
@@ -426,6 +430,11 @@ public class PackageParser {
        mMetrics.setToDefaults();
    }

    public PackageParser(Context context) {
        this();
        mContext = context;
    }

    public void setSeparateProcesses(String[] procs) {
        mSeparateProcesses = procs;
    }
@@ -443,6 +452,10 @@ public class PackageParser {
        mMetrics = metrics;
    }

    public void setOnlyPowerOffAlarmApps(boolean onlyPowerOffAlarmApps) {
        mOnlyPowerOffAlarmApps = onlyPowerOffAlarmApps;
    }

    public static final boolean isApkFile(File file) {
        return isApkPath(file.getName());
    }
@@ -797,6 +810,27 @@ public class PackageParser {
        }
    }


    /*
     * Check if the package belongs to power off alarm packages
     */
    private boolean isPowerOffAlarmPackage(String packageName) {
        if (mContext != null) {
            String[] packageArray =
                    mContext.getResources().getStringArray(R.array.power_off_alarm_apps);
            if(packageArray.length ==0) {
                Slog.w(TAG, "power off alarm app array is empty " + packageName);
                return false;
            } else {
                List<String> tempList = Arrays.asList(packageArray);
                if (tempList.contains(packageName)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Parse all APKs contained in the given directory, treating them as a
     * single package. This also performs sanity checking, such as requiring
@@ -808,8 +842,15 @@ public class PackageParser {
     */
    private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
        final PackageLite lite = parseClusterPackageLite(packageDir, 0);
        // When mOnlyPowerOffAlarmApps is true, only parse power off alarm packages
        if (mOnlyPowerOffAlarmApps) {
            if (!isPowerOffAlarmPackage(lite.packageName)) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                        "Not a powerOffAlarmApp: " + packageDir);
            }
        }

        if (mOnlyCoreApps && !lite.coreApp) {
        if (!mOnlyPowerOffAlarmApps && mOnlyCoreApps && !lite.coreApp) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                    "Not a coreApp: " + packageDir);
        }
@@ -867,7 +908,15 @@ public class PackageParser {
    @Deprecated
    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
        if (mOnlyCoreApps) {
        // When mOnlyPowerOffAlarmApps is true, only parse power off alarm packages
        if (mOnlyPowerOffAlarmApps) {
            if (!isPowerOffAlarmPackage(lite.packageName)) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                   "Not a powerOffAlarmApp: " + apkFile);
            }
        }

        if (!mOnlyPowerOffAlarmApps && mOnlyCoreApps) {
            if (!lite.coreApp) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                        "Not a coreApp: " + apkFile);
+13 −0
Original line number Diff line number Diff line
@@ -239,4 +239,17 @@
        <item>Trying to enable BT</item>
    </string-array>

    <string-array name="power_off_alarm_apps">
        <item>android</item>
        <item>com.android.location.fused</item>
        <item>com.android.settings</item>
        <item>com.android.defcontainer</item>
        <item>com.android.poweronalert</item>
        <item>com.android.shell</item>
        <item>com.android.deskclock</item>
        <item>com.android.providers.media</item>
        <item>com.android.inputdevices</item>
        <item>com.android.providers.settings</item>
    </string-array>

</resources>
+2 −0
Original line number Diff line number Diff line
@@ -1911,6 +1911,8 @@
  <java-symbol type="integer" name="config_maxResolverActivityColumns" />
  <java-symbol type="array" name="config_notificationSignalExtractors" />

  <java-symbol type="array" name="power_off_alarm_apps" />

  <java-symbol type="layout" name="notification_material_action" />
  <java-symbol type="layout" name="notification_material_action_list" />
  <java-symbol type="layout" name="notification_material_action_tombstone" />
+38 −7
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.app.IAlarmManager;
import android.app.IUidObserver;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentUris;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -120,6 +121,11 @@ class AlarmManagerService extends SystemService {

    final LocalLog mLog = new LocalLog(TAG);

    private static final String DESKCLOCK_PACKAGE_NAME = "com.android.deskclock";

    private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
    private static final String ENCRYPTED_STATE = "1";

    AppOpsManager mAppOps;
    DeviceIdleController.LocalService mLocalDeviceIdleController;

@@ -393,13 +399,14 @@ class AlarmManagerService extends SystemService {
            return alarms.get(index);
        }

        long getWhenByElapsedTime(long whenElapsed) {
        Alarm getAlarmByElapsedTime(long whenElapsed) {
            Alarm alarm = null;
            for(int i=0;i< alarms.size();i++) {
                if(alarms.get(i).whenElapsed == whenElapsed) {
                    return alarms.get(i).when;
                    alarm = alarms.get(i);
                }
            }
            return 0;
            return alarm;
        }

        boolean canHold(long whenElapsed, long maxWhen) {
@@ -1733,7 +1740,6 @@ class AlarmManagerService extends SystemService {
        final int N = mAlarmBatches.size();
        for (int i = 0; i < N; i++) {
            Batch b = mAlarmBatches.get(i);
            long intervalTime  = b.start - SystemClock.elapsedRealtime();
            if (b.isRtcPowerOffWakeup()) {
                return b;
            }
@@ -1895,12 +1901,37 @@ class AlarmManagerService extends SystemService {
                mLastWakeupSet = SystemClock.elapsedRealtime();
                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
            }

            boolean isEncryptStatus = false;
            String cryptState = SystemProperties.get("vold.decrypt");
            if (ENCRYPTING_STATE.equals(cryptState) || ENCRYPTED_STATE.equals(cryptState)) {
                isEncryptStatus = true;
            }

            // Set RTC_POWEROFF type alarm to kernel
            if (firstRtcWakeup != null && mNextRtcWakeup != firstRtcWakeup.start) {
                mNextRtcWakeup = firstRtcWakeup.start;
                long when = firstRtcWakeup.getWhenByElapsedTime(mNextRtcWakeup);
                if (when != 0) {
                    setLocked(RTC_POWEROFF_WAKEUP, when);
                Alarm alarm = firstRtcWakeup.getAlarmByElapsedTime(mNextRtcWakeup);
                if (alarm != null) {
                    // use packageName to check if the alarm is set from deskclock app
                    // (power off alarm)
                    String packageName = alarm.packageName;
                    if (DESKCLOCK_PACKAGE_NAME.equals(packageName)) {
                        AlarmManager.writePowerOffAlarmFile(AlarmManager.POWER_OFF_ALARM_SET_FILE,
                                AlarmManager.POWER_OFF_ALARM_SET);
                        if (!isEncryptStatus) {
                            AlarmManager.writePowerOffAlarmFile(
                                    AlarmManager.POWER_OFF_ALARM_INSTANCE_FILE, "" + alarm.when);
                        }
                    } else {
                        AlarmManager.writePowerOffAlarmFile(AlarmManager.POWER_OFF_ALARM_SET_FILE,
                                AlarmManager.POWER_OFF_ALARM_NOT_SET);
                    }
                    setLocked(RTC_POWEROFF_WAKEUP, alarm.when);
                }
            } else if (firstRtcWakeup == null){
                AlarmManager.writePowerOffAlarmFile(AlarmManager.POWER_OFF_ALARM_SET_FILE,
                        AlarmManager.POWER_OFF_ALARM_NOT_SET);
            }
            if (firstBatch != firstWakeup) {
                nextNonWakeup = firstBatch.start;
Loading