summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>2013-11-27 14:38:57 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-01-03 08:58:59 +0100
commit58326e8585ea9fbd168321b5fa3f7d7aec93c924 (patch)
treed256d377d4876f8f79b2d56401dd11ea6aa62fe1 /src
parentf9a47a6aa5a83a872c38173d10f9c29a81a2bd27 (diff)
Android: Overwrite plugin cache when APK is updated
To allow updating APKs with new versions of Qt, we need to delete the old cache when the APK is updated. This patch does two things: 1. Move the plugins (and imports/qml) into a directory called qt-reserved-files/ to better separate the cache from the rest of the application. The first time the files are put here, we will delete the old cache in <datadir>/plugins, <datadir>/imports and <datadir>/qml if they exist to avoid leaving old files around forever. 2. Add versioning to the cache and flush it every time the APK is reinstalled. Potentially, the libraries in the APK can change for every reinstall, so this is the safest approach. Task-number: QTBUG-35129 [ChangeLog][Android][QTBUG-35129] Update deployed plugins and imports when APK is updated on the device. Change-Id: Ie38b639db2cfba8a521acc875c4afd5e07df3efd Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java126
1 files changed, 116 insertions, 10 deletions
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
index a10e58bb87..6762717d91 100644
--- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java
@@ -32,6 +32,8 @@ import java.io.OutputStream;
import java.io.InputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
+import java.io.DataOutputStream;
+import java.io.DataInputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@@ -50,6 +52,7 @@ import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageInfo;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
import android.content.res.AssetManager;
@@ -382,6 +385,9 @@ public class QtActivity extends Activity
InputStream inputStream = assetsManager.open(source);
OutputStream outputStream = new FileOutputStream(destinationFile);
copyFile(inputStream, outputStream);
+
+ inputStream.close();
+ outputStream.close();
}
private static void createBundledBinary(String source, String destination)
@@ -401,13 +407,66 @@ public class QtActivity extends Activity
InputStream inputStream = new FileInputStream(source);
OutputStream outputStream = new FileOutputStream(destinationFile);
copyFile(inputStream, outputStream);
+
+ inputStream.close();
+ outputStream.close();
+ }
+
+ private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion)
+ {
+ File versionFile = new File(pluginsPrefix + "cache.version");
+
+ long cacheVersion = 0;
+ if (versionFile.exists() && versionFile.canRead()) {
+ try {
+ DataInputStream inputStream = new DataInputStream(new FileInputStream(versionFile));
+ cacheVersion = inputStream.readLong();
+ inputStream.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (cacheVersion != packageVersion) {
+ deleteRecursively(new File(pluginsPrefix));
+ return true;
+ } else {
+ return false;
+ }
}
- private void extractBundledPluginsAndImports(String localPrefix)
+ private void extractBundledPluginsAndImports(String pluginsPrefix)
throws IOException
{
ArrayList<String> libs = new ArrayList<String>();
+ String dataDir = getApplicationInfo().dataDir + "/";
+
+ long packageVersion = -1;
+ try {
+ PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
+ packageVersion = packageInfo.lastUpdateTime;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion))
+ return;
+
+ {
+ File versionFile = new File(pluginsPrefix + "cache.version");
+
+ File parentDirectory = versionFile.getParentFile();
+ if (!parentDirectory.exists())
+ parentDirectory.mkdirs();
+
+ versionFile.createNewFile();
+
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(versionFile));
+ outputStream.writeLong(packageVersion);
+ outputStream.close();
+ }
+
{
String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY;
java.util.Set<String> keys = m_activityInfo.metaData.keySet();
@@ -416,8 +475,8 @@ public class QtActivity extends Activity
for (String bundledImportBinary : list) {
String[] split = bundledImportBinary.split(":");
- String sourceFileName = localPrefix + "lib/" + split[0];
- String destinationFileName = localPrefix + split[1];
+ String sourceFileName = dataDir + "lib/" + split[0];
+ String destinationFileName = pluginsPrefix + split[1];
createBundledBinary(sourceFileName, destinationFileName);
}
}
@@ -431,7 +490,7 @@ public class QtActivity extends Activity
for (String fileName : list) {
String[] split = fileName.split(":");
String sourceFileName = split[0];
- String destinationFileName = localPrefix + split[1];
+ String destinationFileName = pluginsPrefix + split[1];
copyAsset(sourceFileName, destinationFileName);
}
}
@@ -439,6 +498,45 @@ public class QtActivity extends Activity
}
}
+ private void deleteRecursively(File directory)
+ {
+ File[] files = directory.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isDirectory())
+ deleteRecursively(file);
+ else
+ file.delete();
+ }
+
+ directory.delete();
+ }
+ }
+
+ private void cleanOldCacheIfNecessary(String oldLocalPrefix, String localPrefix)
+ {
+ File newCache = new File(localPrefix);
+ if (!newCache.exists()) {
+ {
+ File oldPluginsCache = new File(oldLocalPrefix + "plugins/");
+ if (oldPluginsCache.exists() && oldPluginsCache.isDirectory())
+ deleteRecursively(oldPluginsCache);
+ }
+
+ {
+ File oldImportsCache = new File(oldLocalPrefix + "imports/");
+ if (oldImportsCache.exists() && oldImportsCache.isDirectory())
+ deleteRecursively(oldImportsCache);
+ }
+
+ {
+ File oldQmlCache = new File(oldLocalPrefix + "qml/");
+ if (oldQmlCache.exists() && oldQmlCache.isDirectory())
+ deleteRecursively(oldQmlCache);
+ }
+ }
+ }
+
private void startApp(final boolean firstStart)
{
try {
@@ -464,11 +562,15 @@ public class QtActivity extends Activity
if (m_activityInfo.metaData.containsKey("android.app.libs_prefix"))
localPrefix = m_activityInfo.metaData.getString("android.app.libs_prefix");
+ String pluginsPrefix = localPrefix;
+
boolean bundlingQtLibs = false;
if (m_activityInfo.metaData.containsKey("android.app.bundle_local_qt_libs")
&& m_activityInfo.metaData.getInt("android.app.bundle_local_qt_libs") == 1) {
localPrefix = getApplicationInfo().dataDir + "/";
- extractBundledPluginsAndImports(localPrefix);
+ pluginsPrefix = localPrefix + "qt-reserved-files/";
+ cleanOldCacheIfNecessary(localPrefix, pluginsPrefix);
+ extractBundledPluginsAndImports(pluginsPrefix);
bundlingQtLibs = true;
}
@@ -484,8 +586,12 @@ public class QtActivity extends Activity
if (m_activityInfo.metaData.containsKey("android.app.load_local_libs")) {
String[] extraLibs = m_activityInfo.metaData.getString("android.app.load_local_libs").split(":");
for (String lib : extraLibs) {
- if (lib.length() > 0)
- libraryList.add(localPrefix + lib);
+ if (lib.length() > 0) {
+ if (lib.startsWith("lib/"))
+ libraryList.add(localPrefix + lib);
+ else
+ libraryList.add(pluginsPrefix + lib);
+ }
}
}
@@ -513,9 +619,9 @@ public class QtActivity extends Activity
}
loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES
- + "\tQML2_IMPORT_PATH=" + localPrefix + "/qml"
- + "\tQML_IMPORT_PATH=" + localPrefix + "/imports"
- + "\tQT_PLUGIN_PATH=" + localPrefix + "/plugins");
+ + "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml"
+ + "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports"
+ + "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins");
Intent intent = getIntent();
if (intent != null) {