@@ -140,16 +140,15 @@ public int hashCode() {
140140 }
141141 }
142142
143- private final SQLiteStatement createModulesTable = db . compileStatement ( "CREATE TABLE IF NOT EXISTS modules (" +
143+ private static final String CREATE_MODULES_TABLE = "CREATE TABLE IF NOT EXISTS modules (" +
144144 "mid integer PRIMARY KEY AUTOINCREMENT," +
145145 "module_pkg_name text NOT NULL UNIQUE," +
146146 "apk_path text NOT NULL, " +
147147 "enabled BOOLEAN DEFAULT 0 " +
148- "CHECK (enabled IN (0, 1))," +
149- "auto_include BOOLEAN DEFAULT 0 " +
150- "CHECK (auto_include IN (0, 1))" +
151- ");" );
152- private final SQLiteStatement createScopeTable = db .compileStatement ("CREATE TABLE IF NOT EXISTS scope (" +
148+ "CHECK (enabled IN (0, 1))" +
149+ ");" ;
150+
151+ private static final String CREATE_SCOPE_TABLE = "CREATE TABLE IF NOT EXISTS scope (" +
153152 "mid integer," +
154153 "app_pkg_name text NOT NULL," +
155154 "user_id integer NOT NULL," +
@@ -158,8 +157,9 @@ public int hashCode() {
158157 " FOREIGN KEY (mid)" +
159158 " REFERENCES modules (mid)" +
160159 " ON DELETE CASCADE" +
161- ");" );
162- private final SQLiteStatement createConfigTable = db .compileStatement ("CREATE TABLE IF NOT EXISTS configs (" +
160+ ");" ;
161+
162+ private static final String CREATE_CONFIG_TABLE = "CREATE TABLE IF NOT EXISTS configs (" +
163163 "module_pkg_name text NOT NULL," +
164164 "user_id integer NOT NULL," +
165165 "`group` text NOT NULL," +
@@ -170,7 +170,7 @@ public int hashCode() {
170170 " FOREIGN KEY (module_pkg_name)" +
171171 " REFERENCES modules (module_pkg_name)" +
172172 " ON DELETE CASCADE" +
173- ");" ) ;
173+ ");" ;
174174
175175 private final Map <ProcessScope , List <Module >> cachedScope = new ConcurrentHashMap <>();
176176
@@ -382,74 +382,73 @@ private void executeInTransaction(Runnable execution) {
382382 }
383383
384384 private void initDB () {
385+ db .setForeignKeyConstraintsEnabled (true );
386+ int oldVersion = db .getVersion ();
387+ if (oldVersion >= 4 ) {
388+ // Database is already up to date.
389+ return ;
390+ }
391+
392+ Log .i (TAG , "Initializing/Upgrading database from version " + oldVersion + " to 4" );
393+ db .beginTransaction ();
385394 try {
386- db .setForeignKeyConstraintsEnabled (true );
387- switch (db .getVersion ()) {
388- case 0 :
389- executeInTransaction (() -> {
390- createModulesTable .execute ();
391- createScopeTable .execute ();
392- createConfigTable .execute ();
393- var values = new ContentValues ();
394- values .put ("module_pkg_name" , "lspd" );
395- values .put ("apk_path" , ConfigFileManager .managerApkPath .toString ());
396- // dummy module for config
397- db .insertWithOnConflict ("modules" , null , values , SQLiteDatabase .CONFLICT_IGNORE );
398- db .setVersion (1 );
399- });
400- case 1 :
401- executeInTransaction (() -> {
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- createConfigTable .execute ();
407- createScopeTable .execute ();
408- db .compileStatement ("CREATE INDEX IF NOT EXISTS configs_idx ON configs (module_pkg_name, user_id);" ).execute ();
409- executeInTransaction (() -> {
410- try {
411- db .compileStatement ("INSERT INTO scope SELECT * FROM old_scope;" ).execute ();
412- } catch (Throwable e ) {
413- Log .w (TAG , "migrate scope" , e );
414- }
415- });
416- executeInTransaction (() -> {
417- try {
418- executeInTransaction (() -> db .compileStatement ("INSERT INTO configs SELECT * FROM old_configs;" ).execute ());
419- } catch (Throwable e ) {
420- Log .w (TAG , "migrate config" , e );
421- }
422- });
423- db .compileStatement ("DROP TABLE old_scope;" ).execute ();
424- db .compileStatement ("DROP TABLE old_configs;" ).execute ();
425- db .setVersion (2 );
426- });
427- case 2 :
428- executeInTransaction (() -> {
429- db .compileStatement ("UPDATE scope SET app_pkg_name = 'system' WHERE app_pkg_name = 'android';" ).execute ();
430- db .setVersion (3 );
431- });
432- case 3 :
433- try {
434- executeInTransaction (() -> {
435- db .compileStatement ("ALTER TABLE modules ADD COLUMN auto_include BOOLEAN DEFAULT 0 CHECK (auto_include IN (0, 1));" ).execute ();
436- db .setVersion (4 );
437- });
438- } catch (SQLiteException ex ) {
439- // Fix wrong init code for new column auto_include
440- if (ex .getMessage ().startsWith ("duplicate column name: auto_include" )) {
441- db .setVersion (4 );
442- } else {
443- throw ex ;
444- }
445- }
446- default :
447- break ;
395+ if (oldVersion == 0 ) {
396+ db .execSQL (CREATE_MODULES_TABLE );
397+ db .execSQL (CREATE_SCOPE_TABLE );
398+ db .execSQL (CREATE_CONFIG_TABLE );
399+
400+ var values = new ContentValues ();
401+ values .put ("module_pkg_name" , "lspd" );
402+ values .put ("apk_path" , ConfigFileManager .managerApkPath .toString ());
403+ db .insertWithOnConflict ("modules" , null , values , SQLiteDatabase .CONFLICT_IGNORE );
404+ oldVersion = 1 ;
448405 }
406+ if (oldVersion < 2 ) {
407+ // Upgrade from 1 to 2: Recreate tables to enforce constraints and clean up.
408+ db .compileStatement ("DROP INDEX IF EXISTS configs_idx;" ).execute ();
409+ db .compileStatement ("DROP TABLE IF EXISTS config;" ).execute ();
410+ db .compileStatement ("ALTER TABLE scope RENAME TO old_scope;" ).execute ();
411+ db .compileStatement ("ALTER TABLE configs RENAME TO old_configs;" ).execute ();
412+
413+ db .execSQL (CREATE_SCOPE_TABLE );
414+ db .execSQL (CREATE_CONFIG_TABLE );
415+
416+ try {
417+ db .compileStatement ("INSERT INTO scope SELECT * FROM old_scope;" ).execute ();
418+ } catch (Throwable e ) {
419+ Log .w (TAG , "Failed to migrate scope data" , e );
420+ }
421+ try {
422+ db .compileStatement ("INSERT INTO configs SELECT * FROM old_configs;" ).execute ();
423+ } catch (Throwable e ) {
424+ Log .w (TAG , "Failed to migrate config data" , e );
425+ }
426+
427+ db .compileStatement ("DROP TABLE old_scope;" ).execute ();
428+ db .compileStatement ("DROP TABLE old_configs;" ).execute ();
429+ db .compileStatement ("CREATE INDEX IF NOT EXISTS configs_idx ON configs (module_pkg_name, user_id);" ).execute ();
430+ }
431+ if (oldVersion < 3 ) {
432+ // Upgrade from 2 to 3: Rename 'android' scope to 'system'.
433+ db .compileStatement ("UPDATE scope SET app_pkg_name = 'system' WHERE app_pkg_name = 'android';" ).execute ();
434+ }
435+ if (oldVersion < 4 ) {
436+ // Upgrade from 3 to 4: Add the 'auto_include' column to the modules table.
437+ try {
438+ db .compileStatement ("ALTER TABLE modules ADD COLUMN auto_include BOOLEAN DEFAULT 0 CHECK (auto_include IN (0, 1));" ).execute ();
439+ } catch (SQLiteException ex ) {
440+ // This might happen if the column already exists from a previous buggy run.
441+ Log .w (TAG , "Could not add auto_include column, it may already exist." , ex );
442+ }
443+ }
444+ db .setVersion (4 );
445+ db .setTransactionSuccessful ();
446+ Log .i (TAG , "Database upgrade to version 4 successful." );
449447 } catch (Throwable e ) {
450- Log .e (TAG , "init db" , e );
448+ Log .e (TAG , "Failed to initialize or upgrade database, transaction rolled back." , e );
449+ } finally {
450+ db .endTransaction ();
451451 }
452-
453452 }
454453
455454 private List <ProcessScope > getAssociatedProcesses (Application app ) throws RemoteException {
0 commit comments