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

Commit cd5a5a60 authored by Philip P. Moltmann's avatar Philip P. Moltmann
Browse files

Clear files (including stale staged apks) on boot

Before the staged apks were never deleted if the installer was killed
during install.

Test: Booted, installed packages, uninstalled packages. Checked that
      files were cleaned correctly.
Change-Id: Ie3fad7e448269eef3b4e85748e67a4c4e318c01b
parent dd467b3e
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -33,6 +33,13 @@
            android:defaultToDeviceProtectedStorage="true"
            android:directBootAware="true">

        <receiver android:name=".TemporaryFileManager"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <activity android:name=".InstallStart"
                android:exported="true"
                android:excludeFromRecents="true">
@@ -73,9 +80,6 @@
            <intent-filter android:priority="1">
                <action android:name="com.android.packageinstaller.ACTION_INSTALL_COMMIT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <activity android:name=".InstallSuccess"
@@ -115,9 +119,6 @@
            <intent-filter android:priority="1">
                <action android:name="com.android.packageinstaller.ACTION_UNINSTALL_COMMIT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <activity android:name=".UninstallUninstalling"
+3 −12
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;

import java.io.File;

/**
 * Receives install events and perists them using a {@link EventResultPersister}.
 */
@@ -38,8 +36,8 @@ public class InstallEventReceiver extends BroadcastReceiver {
    @NonNull private static EventResultPersister getReceiver(@NonNull Context context) {
        synchronized (sLock) {
            if (sReceiver == null) {
                sReceiver = new EventResultPersister(new File(context.getNoBackupFilesDir(),
                        "install_results.xml"));
                sReceiver = new EventResultPersister(
                        TemporaryFileManager.getInstallStateFile(context));
            }
        }

@@ -48,15 +46,8 @@ public class InstallEventReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            // Do not persist installs over reboot
            synchronized (sLock) {
                new File(context.getNoBackupFilesDir(), "install_results.xml").delete();
            }
        } else {
        getReceiver(context).onEventReceived(context, intent);
    }
    }

    /**
     * Add an observer. If there is already an event for this id, call back inside of this call.
+1 −1
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ public class InstallStaging extends Activity {
            if (mStagedFile == null) {
                // Create file delayed to be able to show error
                try {
                    mStagedFile = File.createTempFile("package", ".apk", getCacheDir());
                    mStagedFile = TemporaryFileManager.getStagedFile(this);
                } catch (IOException e) {
                    showError();
                    return;
+95 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.packageinstaller;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.util.Log;

import java.io.File;
import java.io.IOException;

/**
 * Manages files of the package installer and resets state during boot.
 */
public class TemporaryFileManager extends BroadcastReceiver {
    private static final String LOG_TAG = TemporaryFileManager.class.getSimpleName();

    /**
     * Create a new file to hold a staged file.
     *
     * @param context The context of the caller
     *
     * @return A new file
     */
    @NonNull
    public static File getStagedFile(@NonNull Context context) throws IOException {
        return File.createTempFile("package", ".apk", context.getNoBackupFilesDir());
    }

    /**
     * Get the file used to store the results of installs.
     *
     * @param context The context of the caller
     *
     * @return the file used to store the results of installs
     */
    @NonNull
    public static File getInstallStateFile(@NonNull Context context) {
        return new File(context.getNoBackupFilesDir(), "install_results.xml");
    }

    /**
     * Get the file used to store the results of uninstalls.
     *
     * @param context The context of the caller
     *
     * @return the file used to store the results of uninstalls
     */
    @NonNull
    public static File getUninstallStateFile(@NonNull Context context) {
        return new File(context.getNoBackupFilesDir(), "uninstall_results.xml");
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        long systemBootTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();

        File[] filesOnBoot = context.getNoBackupFilesDir().listFiles();

        if (filesOnBoot == null) {
            return;
        }

        for (int i = 0; i < filesOnBoot.length; i++) {
            File fileOnBoot = filesOnBoot[i];

            if (systemBootTime > fileOnBoot.lastModified()) {
                boolean wasDeleted = fileOnBoot.delete();
                if (!wasDeleted) {
                    Log.w(LOG_TAG, "Could not delete " + fileOnBoot.getName() + " onBoot");
                }
            } else {
                Log.w(LOG_TAG, fileOnBoot.getName() + " was created before onBoot broadcast was "
                        + "received");
            }
        }
    }
}
+3 −12
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;

import java.io.File;

/**
 * Receives uninstall events and persists them using a {@link EventResultPersister}.
 */
@@ -38,8 +36,8 @@ public class UninstallEventReceiver extends BroadcastReceiver {
    @NonNull private static EventResultPersister getReceiver(@NonNull Context context) {
        synchronized (sLock) {
            if (sReceiver == null) {
                sReceiver = new EventResultPersister(new File(context.getNoBackupFilesDir(),
                        "uninstall_results.xml"));
                sReceiver = new EventResultPersister(
                        TemporaryFileManager.getUninstallStateFile(context));
            }
        }

@@ -48,15 +46,8 @@ public class UninstallEventReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            // Do not persist uninstalls over reboot
            synchronized (sLock) {
                new File(context.getNoBackupFilesDir(), "uninstall_results.xml").delete();
            }
        } else {
        getReceiver(context).onEventReceived(context, intent);
    }
    }

    /**
     * Add an observer. If there is already an event for this id, call back inside of this call.