[Android] Handle DB corruption

Nicolas Pomepuy git at videolan.org
Wed Sep 4 15:39:10 CEST 2019


vlc-android | branch: 3.2.x | Nicolas Pomepuy <nicolas.pomepuy at gmail.com> | Fri Aug 30 06:53:34 2019 +0200| [29eeed20d1a1a80925e05b89997feb532debdfe4] | committer: Nicolas Pomepuy

Handle DB corruption

(cherry picked from commit ef6be71af96ea6623ff4b25242b47684da1c689b)

> https://code.videolan.org/videolan/vlc-android/commit/29eeed20d1a1a80925e05b89997feb532debdfe4
---

 compile-medialibrary.sh                            |  4 ++--
 medialibrary/jni/AndroidMediaLibrary.cpp           |  6 ++++++
 medialibrary/jni/AndroidMediaLibrary.h             |  1 +
 medialibrary/jni/medialibrary.cpp                  |  6 ++++++
 .../org/videolan/medialibrary/Medialibrary.java    | 25 ++++++++++++++++++++--
 .../interfaces/AbstractMedialibrary.java           |  4 ++--
 .../src/org/videolan/vlc/MediaParsingService.kt    | 11 +++++++---
 7 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/compile-medialibrary.sh b/compile-medialibrary.sh
index 146ae38df..31db34122 100755
--- a/compile-medialibrary.sh
+++ b/compile-medialibrary.sh
@@ -4,7 +4,7 @@
 # ARGUMENTS #
 #############
 
-MEDIALIBRARY_HASH=862ceb5
+MEDIALIBRARY_HASH=f748def6
 
 while [ $# -gt 0 ]; do
     case $1 in
@@ -89,7 +89,7 @@ if [ ! -d "${MEDIALIBRARY_MODULE_DIR}/medialibrary" ]; then
     git clone http://code.videolan.org/videolan/medialibrary.git "${SRC_DIR}/medialibrary/medialibrary"
     avlc_checkfail "medialibrary source: git clone failed"
     cd ${MEDIALIBRARY_MODULE_DIR}/medialibrary
-    git checkout 0.5.x
+#    git checkout 0.5.x
     git submodule update --init libvlcpp
 else
     cd ${MEDIALIBRARY_MODULE_DIR}/medialibrary
diff --git a/medialibrary/jni/AndroidMediaLibrary.cpp b/medialibrary/jni/AndroidMediaLibrary.cpp
index 8b45eae63..28c4b272e 100644
--- a/medialibrary/jni/AndroidMediaLibrary.cpp
+++ b/medialibrary/jni/AndroidMediaLibrary.cpp
@@ -60,6 +60,12 @@ AndroidMediaLibrary::start()
     m_started = true;
 }
 
+
+void
+AndroidMediaLibrary::clearDatabase(bool restorePlaylists) {
+    p_ml->clearDatabase(restorePlaylists);
+}
+
 bool
 AndroidMediaLibrary::addDevice(const std::string& uuid, const std::string& path, bool removable)
 {
diff --git a/medialibrary/jni/AndroidMediaLibrary.h b/medialibrary/jni/AndroidMediaLibrary.h
index 7eced7c62..0847d7d82 100644
--- a/medialibrary/jni/AndroidMediaLibrary.h
+++ b/medialibrary/jni/AndroidMediaLibrary.h
@@ -32,6 +32,7 @@ public:
     medialibrary::InitializeResult initML(const std::string& dbPath, const std::string& thumbsPath);
     void start();
     bool addDevice(const std::string& uuid, const std::string& path, bool removable);
+    void clearDatabase(bool restorePlaylists);
     std::vector<std::tuple<std::string, std::string, bool>> devices();
     bool removeDevice(const std::string& uuid, const std::string& path);
     void banFolder(const std::string& path);
diff --git a/medialibrary/jni/medialibrary.cpp b/medialibrary/jni/medialibrary.cpp
index 3e43cde13..943b4b5bf 100644
--- a/medialibrary/jni/medialibrary.cpp
+++ b/medialibrary/jni/medialibrary.cpp
@@ -54,6 +54,11 @@ release(JNIEnv* env, jobject thiz)
     MediaLibrary_setInstance(env, thiz, NULL);
 }
 
+void
+clearDatabase(JNIEnv* env, jobject thiz, jboolean restorePlaylists) {
+    MediaLibrary_getInstance(env, thiz)->clearDatabase(restorePlaylists);
+}
+
 void
 banFolder(JNIEnv* env, jobject thiz, jstring folderPath)
 {
@@ -1729,6 +1734,7 @@ static JNINativeMethod methods[] = {
     {"nativeInit", "(Ljava/lang/String;Ljava/lang/String;)I", (void*)init },
     {"nativeStart", "()V", (void*)start },
     {"nativeRelease", "()V", (void*)release },
+    {"nativeClearDatabase", "(Z)V", (void*)clearDatabase },
     {"nativeAddDevice", "(Ljava/lang/String;Ljava/lang/String;Z)Z", (void*)addDevice },
     {"nativeDevices", "()[Ljava/lang/String;", (void*)devices },
     {"nativeDiscover", "(Ljava/lang/String;)V", (void*)discover },
diff --git a/medialibrary/src/org/videolan/medialibrary/Medialibrary.java b/medialibrary/src/org/videolan/medialibrary/Medialibrary.java
index 2d66f6451..ff7a33d9e 100644
--- a/medialibrary/src/org/videolan/medialibrary/Medialibrary.java
+++ b/medialibrary/src/org/videolan/medialibrary/Medialibrary.java
@@ -49,7 +49,7 @@ public class Medialibrary extends AbstractMedialibrary {
     public int init(Context context) {
         if (context == null) return ML_INIT_FAILED;
         sContext = context;
-        File extFilesDir = context.getExternalFilesDir(null);
+        final File extFilesDir = context.getExternalFilesDir(null);
         File dbDirectory = context.getDir("db", Context.MODE_PRIVATE);
         if (extFilesDir == null || !extFilesDir.exists()
                 || dbDirectory == null || !dbDirectory.canWrite())
@@ -63,8 +63,27 @@ public class Medialibrary extends AbstractMedialibrary {
             Log.e(TAG, "Can't load mla: " + ule);
             return ML_INIT_FAILED;
         }
-        int initCode = nativeInit(dbDirectory+ VLC_MEDIA_DB_NAME, extFilesDir+ THUMBS_FOLDER_NAME);
+        //remove old thumbnails directory
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                final File oldDir = new File(extFilesDir + THUMBS_FOLDER_NAME);
+                if (oldDir.isDirectory()) {
+                    String[] children = oldDir.list();
+                    for (String child : children) {
+                        new File(oldDir, child).delete();
+                    }
+                    oldDir.delete();
+                }
+            }
+        }).start();
+
+        int initCode = nativeInit(dbDirectory + VLC_MEDIA_DB_NAME, extFilesDir + MEDIALIB_FOLDER_NAME);
         mIsInitiated = initCode != ML_INIT_FAILED;
+        if (initCode == ML_INIT_DB_CORRUPTED) {
+            Log.e(TAG, "Medialib database is corrupted. Clearing it and try to restore playlists");
+            nativeClearDatabase(true);
+        }
         return initCode;
     }
 
@@ -482,6 +501,8 @@ public class Medialibrary extends AbstractMedialibrary {
     private native int nativeInit(String dbPath, String thumbsPath);
     private native void nativeStart();
     private native void nativeRelease();
+
+    private native void nativeClearDatabase(boolean keepPlaylist);
     private native void nativeBanFolder(String path);
     private native void nativeUnbanFolder(String path);
     private native boolean nativeAddDevice(String uuid, String path, boolean removable);
diff --git a/medialibrary/src/org/videolan/medialibrary/interfaces/AbstractMedialibrary.java b/medialibrary/src/org/videolan/medialibrary/interfaces/AbstractMedialibrary.java
index 93bac0c4b..cbeae4fb8 100644
--- a/medialibrary/src/org/videolan/medialibrary/interfaces/AbstractMedialibrary.java
+++ b/medialibrary/src/org/videolan/medialibrary/interfaces/AbstractMedialibrary.java
@@ -2,7 +2,6 @@ package org.videolan.medialibrary.interfaces;
 
 import android.Manifest;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Build;
@@ -13,7 +12,6 @@ import androidx.annotation.NonNull;
 import androidx.core.content.ContextCompat;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 
 import org.videolan.medialibrary.MLServiceLocator;
 import org.videolan.medialibrary.SingleEvent;
@@ -60,10 +58,12 @@ abstract public class AbstractMedialibrary {
     public static final int ML_INIT_ALREADY_INITIALIZED = 1;
     public static final int ML_INIT_FAILED = 2;
     public static final int ML_INIT_DB_RESET = 3;
+    public static final int ML_INIT_DB_CORRUPTED = 4;
 
     public static final AbstractMediaWrapper[] EMPTY_COLLECTION = {};
     public static final String VLC_MEDIA_DB_NAME = "/vlc_media.db";
     public static final String THUMBS_FOLDER_NAME = "/thumbs";
+    public static final String MEDIALIB_FOLDER_NAME = "/medialib";
 
     protected volatile boolean mIsInitiated = false;
     protected volatile boolean mIsWorking = false;
diff --git a/vlc-android/src/org/videolan/vlc/MediaParsingService.kt b/vlc-android/src/org/videolan/vlc/MediaParsingService.kt
index 487d8d8bd..ded84faaa 100644
--- a/vlc-android/src/org/videolan/vlc/MediaParsingService.kt
+++ b/vlc-android/src/org/videolan/vlc/MediaParsingService.kt
@@ -243,9 +243,14 @@ class MediaParsingService : Service(), DevicesDiscoveryCb, CoroutineScope, Lifec
             shouldInit -> {
                 for (folder in AbstractMedialibrary.getBlackList())
                     medialibrary.banFolder(AndroidDevices.EXTERNAL_PUBLIC_DIRECTORY + folder)
-                if (preselectedStorages.isEmpty()) medialibrary.discover(AndroidDevices.EXTERNAL_PUBLIC_DIRECTORY)
+                if (preselectedStorages.isEmpty()) {
+                    medialibrary.discover(AndroidDevices.EXTERNAL_PUBLIC_DIRECTORY)
+                }
                 else {
-                    for (folder in preselectedStorages) medialibrary.discover(folder)
+
+                    for (folder in preselectedStorages) {
+                        medialibrary.discover(folder)
+                    }
                     preselectedStorages.clear()
                 }
             }
@@ -395,7 +400,7 @@ class MediaParsingService : Service(), DevicesDiscoveryCb, CoroutineScope, Lifec
                 val context = this at MediaParsingService
                 var shouldInit = !dbExists()
                 val initCode = medialibrary.init(context)
-                shouldInit = shouldInit or (initCode == AbstractMedialibrary.ML_INIT_DB_RESET)
+                shouldInit = shouldInit or (initCode == AbstractMedialibrary.ML_INIT_DB_RESET) or (initCode == AbstractMedialibrary.ML_INIT_DB_CORRUPTED)
                 if (initCode != AbstractMedialibrary.ML_INIT_FAILED) initMedialib(action.parse, context, shouldInit, action.upgrade)
                 else exitCommand()
             }



More information about the Android mailing list