summaryrefslogtreecommitdiffstats
path: root/src/android
diff options
context:
space:
mode:
authorRob Samblanet <rob.samblanet@garmin.com>2018-10-23 12:52:06 -0500
committerCorey Pendleton <corey.pendleton@garmin.com>2019-04-15 17:08:54 +0000
commit327c8a805e508303c245020123ec3ecbfd2c898b (patch)
tree119e80472de1a8029342754b4cc23bb05d8dedae /src/android
parent093a1a6232083e5b9c18a9e85e5759ba3ce280fb (diff)
android: Properly indicate successful Qt install
This patch ensures that installed files are written to physical disk before the 'cache.version' file is written. QtLoader.java uses the 'cache.version' file written during self-installation to indicate whether re-installation is necessary. The 'cache.version' file, however, was being written at the start of installation, so its existence merely indicated that the installation was attempted. In the case of power loss during installation, the existence of 'cache.version' would prevent retrying installation on the next launch, so the bad installation was irrecoverable. [ChangeLog][Android] Fixed an issue where an application installation would be irrecoverably broken if power loss or a crash occurred during its first initialization run. Fixes: QTBUG-71523 Change-Id: If771b223a0a709a994c766eea5a4ba14ae95201e Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Diffstat (limited to 'src/android')
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java100
1 files changed, 75 insertions, 25 deletions
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java
index 9d5578ed6d..d3b0600b2f 100644
--- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java
@@ -159,6 +159,9 @@ public abstract class QtLoader {
protected ComponentInfo m_contextInfo;
private Class<?> m_delegateClass;
+ private static ArrayList<FileOutputStream> m_fileOutputStreams = new ArrayList<FileOutputStream>();
+ // List of open file streams associated with files copied during installation.
+
QtLoader(ContextWrapper context, Class<?> clazz) {
m_context = context;
m_delegateClass = clazz;
@@ -357,7 +360,7 @@ public abstract class QtLoader {
AssetManager assetsManager = m_context.getAssets();
InputStream inputStream = null;
- OutputStream outputStream = null;
+ FileOutputStream outputStream = null;
try {
inputStream = assetsManager.open(source);
outputStream = new FileOutputStream(destinationFile);
@@ -369,8 +372,12 @@ public abstract class QtLoader {
inputStream.close();
if (outputStream != null)
- outputStream.close();
+ // Ensure that the buffered data is flushed to the OS for writing.
+ outputStream.flush();
}
+ // Mark the output stream as still needing to be written to physical disk.
+ // The output stream will be closed after this sync completes.
+ m_fileOutputStreams.add(outputStream);
}
private static void createBundledBinary(String source, String destination)
@@ -388,7 +395,7 @@ public abstract class QtLoader {
destinationFile.createNewFile();
InputStream inputStream = null;
- OutputStream outputStream = null;
+ FileOutputStream outputStream = null;
try {
inputStream = new FileInputStream(source);
outputStream = new FileOutputStream(destinationFile);
@@ -400,8 +407,12 @@ public abstract class QtLoader {
inputStream.close();
if (outputStream != null)
- outputStream.close();
+ // Ensure that the buffered data is flushed to the OS for writing.
+ outputStream.flush();
}
+ // Mark the output stream as still needing to be written to physical disk.
+ // The output stream will be closed after this sync completes.
+ m_fileOutputStreams.add(outputStream);
}
private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion)
@@ -450,27 +461,6 @@ public abstract class QtLoader {
return;
{
- File versionFile = new File(pluginsPrefix + "cache.version");
-
- File parentDirectory = versionFile.getParentFile();
- if (!parentDirectory.exists())
- parentDirectory.mkdirs();
-
- versionFile.createNewFile();
-
- DataOutputStream outputStream = null;
- try {
- outputStream = new DataOutputStream(new FileOutputStream(versionFile));
- outputStream.writeLong(packageVersion);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (outputStream != null)
- outputStream.close();
- }
- }
-
- {
// why can't we load the plugins directly from libs ?!?!
String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY;
if (m_contextInfo.metaData.containsKey(key)) {
@@ -499,6 +489,66 @@ public abstract class QtLoader {
}
}
+
+ // The Java compiler must be assured that variables belonging to this parent thread will not
+ // go out of scope during the runtime of the spawned thread (since in general spawned
+ // threads can outlive their parent threads). Copy variables and declare as 'final' before
+ // passing into the spawned thread.
+ final String pluginsPrefixFinal = pluginsPrefix;
+ final long packageVersionFinal = packageVersion;
+
+ // Spawn a worker thread to write all installed files to physical disk and indicate
+ // successful installation by creating the 'cache.version' file.
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ finalizeInstallation(pluginsPrefixFinal, packageVersionFinal);
+ } catch (Exception e) {
+ Log.e(QtApplication.QtTAG, e.getMessage());
+ e.printStackTrace();
+ return;
+ }
+ }
+ }).start();
+ }
+
+ private void finalizeInstallation(String pluginsPrefix, long packageVersion)
+ throws IOException
+ {
+ {
+ // Write all installed files to physical disk and close each output stream
+ for (FileOutputStream fileOutputStream : m_fileOutputStreams) {
+ fileOutputStream.getFD().sync();
+ fileOutputStream.close();
+ }
+
+ m_fileOutputStreams.clear();
+ }
+
+ {
+ // Create 'cache.version' file
+
+ File versionFile = new File(pluginsPrefix + "cache.version");
+
+ File parentDirectory = versionFile.getParentFile();
+ if (!parentDirectory.exists())
+ parentDirectory.mkdirs();
+
+ versionFile.createNewFile();
+
+ DataOutputStream outputStream = null;
+ try {
+ outputStream = new DataOutputStream(new FileOutputStream(versionFile));
+ outputStream.writeLong(packageVersion);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (outputStream != null)
+ outputStream.close();
+ }
+ }
+
}
private void deleteRecursively(File directory)