@@ -137,16 +137,15 @@ public int hashCode() {
137137 }
138138 }
139139
140- private final SQLiteStatement createModulesTable = db . compileStatement ( "CREATE TABLE IF NOT EXISTS modules (" +
140+ private static final String CREATE_MODULES_TABLE = "CREATE TABLE IF NOT EXISTS modules (" +
141141 "mid integer PRIMARY KEY AUTOINCREMENT," +
142142 "module_pkg_name text NOT NULL UNIQUE," +
143143 "apk_path text NOT NULL, " +
144144 "enabled BOOLEAN DEFAULT 0 " +
145- "CHECK (enabled IN (0, 1))," +
146- "auto_include BOOLEAN DEFAULT 0 " +
147- "CHECK (auto_include IN (0, 1))" +
148- ");" );
149- private final SQLiteStatement createScopeTable = db .compileStatement ("CREATE TABLE IF NOT EXISTS scope (" +
145+ "CHECK (enabled IN (0, 1))" +
146+ ");" ;
147+
148+ private static final String CREATE_SCOPE_TABLE = "CREATE TABLE IF NOT EXISTS scope (" +
150149 "mid integer," +
151150 "app_pkg_name text NOT NULL," +
152151 "user_id integer NOT NULL," +
@@ -155,8 +154,9 @@ public int hashCode() {
155154 " FOREIGN KEY (mid)" +
156155 " REFERENCES modules (mid)" +
157156 " ON DELETE CASCADE" +
158- ");" );
159- private final SQLiteStatement createConfigTable = db .compileStatement ("CREATE TABLE IF NOT EXISTS configs (" +
157+ ");" ;
158+
159+ private static final String CREATE_CONFIG_TABLE = "CREATE TABLE IF NOT EXISTS configs (" +
160160 "module_pkg_name text NOT NULL," +
161161 "user_id integer NOT NULL," +
162162 "`group` text NOT NULL," +
@@ -167,7 +167,7 @@ public int hashCode() {
167167 " FOREIGN KEY (module_pkg_name)" +
168168 " REFERENCES modules (module_pkg_name)" +
169169 " ON DELETE CASCADE" +
170- ");" ) ;
170+ ");" ;
171171
172172 private final Map <ProcessScope , List <Module >> cachedScope = new ConcurrentHashMap <>();
173173
@@ -376,74 +376,73 @@ private void executeInTransaction(Runnable execution) {
376376 }
377377
378378 private void initDB () {
379+ db .setForeignKeyConstraintsEnabled (true );
380+ int oldVersion = db .getVersion ();
381+ if (oldVersion >= 4 ) {
382+ // Database is already up to date.
383+ return ;
384+ }
385+
386+ Log .i (TAG , "Initializing/Upgrading database from version " + oldVersion + " to 4" );
387+ db .beginTransaction ();
379388 try {
380- db .setForeignKeyConstraintsEnabled (true );
381- switch (db .getVersion ()) {
382- case 0 :
383- executeInTransaction (() -> {
384- createModulesTable .execute ();
385- createScopeTable .execute ();
386- createConfigTable .execute ();
387- var values = new ContentValues ();
388- values .put ("module_pkg_name" , "lspd" );
389- values .put ("apk_path" , ConfigFileManager .managerApkPath .toString ());
390- // dummy module for config
391- db .insertWithOnConflict ("modules" , null , values , SQLiteDatabase .CONFLICT_IGNORE );
392- db .setVersion (1 );
393- });
394- case 1 :
395- executeInTransaction (() -> {
396- db .compileStatement ("DROP INDEX IF EXISTS configs_idx;" ).execute ();
397- db .compileStatement ("DROP TABLE IF EXISTS config;" ).execute ();
398- db .compileStatement ("ALTER TABLE scope RENAME TO old_scope;" ).execute ();
399- db .compileStatement ("ALTER TABLE configs RENAME TO old_configs;" ).execute ();
400- createConfigTable .execute ();
401- createScopeTable .execute ();
402- db .compileStatement ("CREATE INDEX IF NOT EXISTS configs_idx ON configs (module_pkg_name, user_id);" ).execute ();
403- executeInTransaction (() -> {
404- try {
405- db .compileStatement ("INSERT INTO scope SELECT * FROM old_scope;" ).execute ();
406- } catch (Throwable e ) {
407- Log .w (TAG , "migrate scope" , e );
408- }
409- });
410- executeInTransaction (() -> {
411- try {
412- executeInTransaction (() -> db .compileStatement ("INSERT INTO configs SELECT * FROM old_configs;" ).execute ());
413- } catch (Throwable e ) {
414- Log .w (TAG , "migrate config" , e );
415- }
416- });
417- db .compileStatement ("DROP TABLE old_scope;" ).execute ();
418- db .compileStatement ("DROP TABLE old_configs;" ).execute ();
419- db .setVersion (2 );
420- });
421- case 2 :
422- executeInTransaction (() -> {
423- db .compileStatement ("UPDATE scope SET app_pkg_name = 'system' WHERE app_pkg_name = 'android';" ).execute ();
424- db .setVersion (3 );
425- });
426- case 3 :
427- try {
428- executeInTransaction (() -> {
429- db .compileStatement ("ALTER TABLE modules ADD COLUMN auto_include BOOLEAN DEFAULT 0 CHECK (auto_include IN (0, 1));" ).execute ();
430- db .setVersion (4 );
431- });
432- } catch (SQLiteException ex ) {
433- // Fix wrong init code for new column auto_include
434- if (ex .getMessage ().startsWith ("duplicate column name: auto_include" )) {
435- db .setVersion (4 );
436- } else {
437- throw ex ;
438- }
439- }
440- default :
441- break ;
389+ if (oldVersion == 0 ) {
390+ db .execSQL (CREATE_MODULES_TABLE );
391+ db .execSQL (CREATE_SCOPE_TABLE );
392+ db .execSQL (CREATE_CONFIG_TABLE );
393+
394+ var values = new ContentValues ();
395+ values .put ("module_pkg_name" , "lspd" );
396+ values .put ("apk_path" , ConfigFileManager .managerApkPath .toString ());
397+ db .insertWithOnConflict ("modules" , null , values , SQLiteDatabase .CONFLICT_IGNORE );
398+ oldVersion = 1 ;
442399 }
400+ if (oldVersion < 2 ) {
401+ // Upgrade from 1 to 2: Recreate tables to enforce constraints and clean up.
402+ db .compileStatement ("DROP INDEX IF EXISTS configs_idx;" ).execute ();
403+ db .compileStatement ("DROP TABLE IF EXISTS config;" ).execute ();
404+ db .compileStatement ("ALTER TABLE scope RENAME TO old_scope;" ).execute ();
405+ db .compileStatement ("ALTER TABLE configs RENAME TO old_configs;" ).execute ();
406+
407+ db .execSQL (CREATE_SCOPE_TABLE );
408+ db .execSQL (CREATE_CONFIG_TABLE );
409+
410+ try {
411+ db .compileStatement ("INSERT INTO scope SELECT * FROM old_scope;" ).execute ();
412+ } catch (Throwable e ) {
413+ Log .w (TAG , "Failed to migrate scope data" , e );
414+ }
415+ try {
416+ db .compileStatement ("INSERT INTO configs SELECT * FROM old_configs;" ).execute ();
417+ } catch (Throwable e ) {
418+ Log .w (TAG , "Failed to migrate config data" , e );
419+ }
420+
421+ db .compileStatement ("DROP TABLE old_scope;" ).execute ();
422+ db .compileStatement ("DROP TABLE old_configs;" ).execute ();
423+ db .compileStatement ("CREATE INDEX IF NOT EXISTS configs_idx ON configs (module_pkg_name, user_id);" ).execute ();
424+ }
425+ if (oldVersion < 3 ) {
426+ // Upgrade from 2 to 3: Rename 'android' scope to 'system'.
427+ db .compileStatement ("UPDATE scope SET app_pkg_name = 'system' WHERE app_pkg_name = 'android';" ).execute ();
428+ }
429+ if (oldVersion < 4 ) {
430+ // Upgrade from 3 to 4: Add the 'auto_include' column to the modules table.
431+ try {
432+ db .compileStatement ("ALTER TABLE modules ADD COLUMN auto_include BOOLEAN DEFAULT 0 CHECK (auto_include IN (0, 1));" ).execute ();
433+ } catch (SQLiteException ex ) {
434+ // This might happen if the column already exists from a previous buggy run.
435+ Log .w (TAG , "Could not add auto_include column, it may already exist." , ex );
436+ }
437+ }
438+ db .setVersion (4 );
439+ db .setTransactionSuccessful ();
440+ Log .i (TAG , "Database upgrade to version 4 successful." );
443441 } catch (Throwable e ) {
444- Log .e (TAG , "init db" , e );
442+ Log .e (TAG , "Failed to initialize or upgrade database, transaction rolled back." , e );
443+ } finally {
444+ db .endTransaction ();
445445 }
446-
447446 }
448447
449448 private List <ProcessScope > getAssociatedProcesses (Application app ) throws RemoteException {
0 commit comments