diff --git a/res/values/strings.xml b/res/values/strings.xml
index 94e844f0..0b6ae93f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -48,6 +48,8 @@
Update installed
Finalizing package installation
Preparing for first boot
+ Preliminary update preparation
+ Could not prepare update
Reboot
diff --git a/src/org/lineageos/updater/controller/UpdaterService.java b/src/org/lineageos/updater/controller/UpdaterService.java
index 57e23712..c3600329 100644
--- a/src/org/lineageos/updater/controller/UpdaterService.java
+++ b/src/org/lineageos/updater/controller/UpdaterService.java
@@ -34,11 +34,14 @@ import org.lineageos.updater.R;
import org.lineageos.updater.UpdaterReceiver;
import org.lineageos.updater.UpdatesActivity;
import org.lineageos.updater.misc.BuildInfoUtils;
+import org.lineageos.updater.misc.Constants;
+import org.lineageos.updater.misc.FileUtils;
import org.lineageos.updater.misc.StringGenerator;
import org.lineageos.updater.misc.Utils;
import org.lineageos.updater.model.UpdateInfo;
import org.lineageos.updater.model.UpdateStatus;
+import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.NumberFormat;
@@ -169,7 +172,22 @@ public class UpdaterService extends Service {
if (Utils.isABUpdate(update.getFile())) {
ABUpdateInstaller.start(mUpdaterController, downloadId);
} else {
- android.os.RecoverySystem.installPackage(this, update.getFile());
+ if (update.getFile().getAbsolutePath().startsWith("/data/") &&
+ Utils.isDeviceEncrypted(this)) {
+ // uncrypt rewrites the file so that it can be read without mounting
+ // the filesystem, so create a copy of it.
+ File uncrytpFile = new File(
+ update.getFile().getAbsolutePath() + Constants.UNCRYPT_FILE_EXT);
+ FileUtils.prepareForUncrypt(this, update.getFile(), uncrytpFile,
+ new Runnable() {
+ @Override
+ public void run() {
+ installPackage(uncrytpFile);
+ }
+ });
+ } else {
+ installPackage(update.getFile());
+ }
}
} catch (IOException e) {
Log.e(TAG, "Could not install update", e);
@@ -180,6 +198,15 @@ public class UpdaterService extends Service {
return START_NOT_STICKY;
}
+ private void installPackage(File update) {
+ try {
+ android.os.RecoverySystem.installPackage(this, update);
+ } catch (IOException e) {
+ // TODO: show error message
+ Log.e(TAG, "Could not install update", e);
+ }
+ }
+
public Controller getUpdaterController() {
return mUpdaterController;
}
diff --git a/src/org/lineageos/updater/misc/Constants.java b/src/org/lineageos/updater/misc/Constants.java
index 570fd4be..5b27bb27 100644
--- a/src/org/lineageos/updater/misc/Constants.java
+++ b/src/org/lineageos/updater/misc/Constants.java
@@ -26,6 +26,8 @@ public final class Constants {
public static final String PREF_LAST_UPDATE_CHECK = "last_update_check";
public static final String PREF_AUTO_UPDATES_CHECK = "auto_updates_check";
+ public static final String UNCRYPT_FILE_EXT = ".uncrypt";
+
public static final String PROP_BUILD_DATE = "ro.build.date.utc";
public static final String PROP_BUILD_VERSION = "ro.cm.build.version";
public static final String PROP_BUILD_VERSION_INCREMENTAL = "ro.build.version.incremental";
diff --git a/src/org/lineageos/updater/misc/FileUtils.java b/src/org/lineageos/updater/misc/FileUtils.java
index c6f7f444..0cfbf933 100644
--- a/src/org/lineageos/updater/misc/FileUtils.java
+++ b/src/org/lineageos/updater/misc/FileUtils.java
@@ -22,6 +22,7 @@ import android.content.DialogInterface;
import android.os.AsyncTask;
import android.support.v7.app.NotificationCompat;
import android.util.Log;
+import android.view.WindowManager;
import org.lineageos.updater.R;
@@ -177,4 +178,79 @@ public class FileUtils {
}
}.execute();
}
+
+ public static void prepareForUncrypt(Context context, File updateFile, File uncryptFile,
+ Runnable callback) {
+
+ final int NOTIFICATION_ID = 12;
+
+ new AsyncTask() {
+
+ private ProgressDialog mProgressDialog;
+ private boolean mCancelled;
+ private ProgressCallBack mProgressCallBack;
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ Log.d(TAG, "Preparing update");
+ mProgressDialog = new ProgressDialog(context);
+ mProgressDialog.setTitle(R.string.app_name);
+ mProgressDialog.setMessage(context.getString(R.string.dialog_prepare_zip_message));
+ mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ mProgressDialog.setCancelable(true);
+ mProgressDialog.setProgressNumberFormat(null);
+ mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ cancel(true);
+ }
+ });
+ mProgressDialog.setCanceledOnTouchOutside(false);
+ mProgressCallBack = new ProgressCallBack() {
+ @Override
+ public void update(int progress) {
+ mProgressDialog.setProgress(progress);
+ }
+ };
+ mProgressDialog.show();
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... voids) {
+ try {
+ copyFile(updateFile, uncryptFile, mProgressCallBack);
+ } catch (IOException e) {
+ Log.e(TAG, "Error while copying the file", e);
+ }
+ return !mCancelled;
+ }
+
+ @Override
+ protected void onCancelled() {
+ mCancelled = true;
+ uncryptFile.delete();
+ }
+
+ @Override
+ protected void onPostExecute(Boolean success) {
+ if (!success || mCancelled) {
+ Log.e(TAG, "Could not prepare the update, cancelled=" + mCancelled);
+ uncryptFile.delete();
+ NotificationManager nm = (NotificationManager) context.getSystemService(
+ Context.NOTIFICATION_SERVICE);
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
+ builder.setSmallIcon(R.drawable.ic_system_update);
+ builder.setContentTitle(
+ context.getString(R.string.notification_prepare_zip_error_title));
+ final String notificationTag = updateFile.getAbsolutePath();
+ nm.notify(notificationTag, NOTIFICATION_ID, builder.build());
+ } else {
+ callback.run();
+ }
+ mProgressDialog.dismiss();
+ }
+ }.execute();
+ }
}
diff --git a/src/org/lineageos/updater/misc/Utils.java b/src/org/lineageos/updater/misc/Utils.java
index 74b55ce5..0426f110 100644
--- a/src/org/lineageos/updater/misc/Utils.java
+++ b/src/org/lineageos/updater/misc/Utils.java
@@ -15,6 +15,7 @@
*/
package org.lineageos.updater.misc;
+import android.app.admin.DevicePolicyManager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
@@ -42,6 +43,7 @@ import org.lineageos.updater.model.UpdateInfo;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
+import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
@@ -222,6 +224,21 @@ public class Utils {
throw new IllegalArgumentException("The given entry was not found");
}
+ public static void removeUncryptFiles(File downloadPath) {
+ File[] uncryptFiles = downloadPath.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(Constants.UNCRYPT_FILE_EXT);
+ }
+ });
+ if (uncryptFiles == null) {
+ return;
+ }
+ for (File file : uncryptFiles) {
+ file.delete();
+ }
+ }
+
/**
* Cleanup the download directory, which is assumed to be a privileged location
* the user can't access and that might have stale files. This can happen if
@@ -230,14 +247,16 @@ public class Utils {
* @param context
*/
public static void cleanupDownloadsDir(Context context) {
- final String DOWNLOADS_CLEANUP_DONE = "cleanup_done";
+ File downloadPath = getDownloadPath(context);
+ removeUncryptFiles(downloadPath);
+
+ final String DOWNLOADS_CLEANUP_DONE = "cleanup_done";
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (preferences.getBoolean(DOWNLOADS_CLEANUP_DONE, false)) {
return;
}
- File downloadPath = getDownloadPath(context);
Log.d(TAG, "Cleaning " + downloadPath);
if (!downloadPath.isDirectory()) {
return;
@@ -307,4 +326,11 @@ public class Utils {
clipboard.setPrimaryClip(clip);
Toast.makeText(context, toastMessage, Toast.LENGTH_SHORT).show();
}
+
+ public static boolean isDeviceEncrypted(Context context) {
+ DevicePolicyManager dpm =
+ (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ int status = dpm.getStorageEncryptionStatus();
+ return status == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
+ }
}