/** * Saves the settings object fields into DB and into plain text files where applicable. The DB * changes will not be made persistent if saving settings to plain text files fails. * * @param s settings object * @return true if settings were saved successfully, false otherwise */ public synchronized boolean saveSettings(PrivacySettings s) { boolean result = true; String packageName = s.getPackageName(); // Integer uid = s.getUid(); // Log.d(TAG, "saveSettings - settings save request : " + s); if (packageName == null || packageName.isEmpty() /* || uid == null*/) { Log.e(TAG, "saveSettings - either package name, UID or both is missing"); return false; } ContentValues values = new ContentValues(); values.put("packageName", packageName); // values.put("uid", uid); values.put("uid", DUMMY_UID); values.put("deviceIdSetting", s.getDeviceIdSetting()); values.put("deviceId", s.getDeviceId()); values.put("line1NumberSetting", s.getLine1NumberSetting()); values.put("line1Number", s.getLine1Number()); values.put("locationGpsSetting", s.getLocationGpsSetting()); values.put("locationGpsLat", s.getLocationGpsLat()); values.put("locationGpsLon", s.getLocationGpsLon()); values.put("locationNetworkSetting", s.getLocationNetworkSetting()); values.put("locationNetworkLat", s.getLocationNetworkLat()); values.put("locationNetworkLon", s.getLocationNetworkLon()); values.put("networkInfoSetting", s.getNetworkInfoSetting()); values.put("simInfoSetting", s.getSimInfoSetting()); values.put("simSerialNumberSetting", s.getSimSerialNumberSetting()); values.put("simSerialNumber", s.getSimSerialNumber()); values.put("subscriberIdSetting", s.getSubscriberIdSetting()); values.put("subscriberId", s.getSubscriberId()); values.put("accountsSetting", s.getAccountsSetting()); values.put("accountsAuthTokensSetting", s.getAccountsAuthTokensSetting()); values.put("outgoingCallsSetting", s.getOutgoingCallsSetting()); values.put("incomingCallsSetting", s.getIncomingCallsSetting()); values.put("contactsSetting", s.getContactsSetting()); values.put("calendarSetting", s.getCalendarSetting()); values.put("mmsSetting", s.getMmsSetting()); values.put("smsSetting", s.getSmsSetting()); values.put("callLogSetting", s.getCallLogSetting()); values.put("bookmarksSetting", s.getBookmarksSetting()); values.put("systemLogsSetting", s.getSystemLogsSetting()); values.put("notificationSetting", s.getNotificationSetting()); values.put("intentBootCompletedSetting", s.getIntentBootCompletedSetting()); // values.put("externalStorageSetting", s.getExternalStorageSetting()); // values.put("cameraSetting", s.getCameraSetting()); // values.put("recordAudioSetting", s.getRecordAudioSetting()); readingThreads++; SQLiteDatabase db = getWritableDatabase(); db.beginTransaction(); // make sure this ends up in a consistent state (DB and plain text files) Cursor c = null; try { // save settings to the DB // Log.d(TAG, "saveSettings - checking if entry exists already"); Integer id = s.get_id(); if (id != null) { // existing entry -> update // Log.d(TAG, "saveSettings - updating existing entry"); if (db.update(TABLE_SETTINGS, values, "_id=?", new String[] {id.toString()}) < 1) { throw new Exception("saveSettings - failed to update database entry"); } db.delete(TABLE_ALLOWED_CONTACTS, "settings_id=?", new String[] {id.toString()}); int[] allowedContacts = s.getAllowedContacts(); if (allowedContacts != null) { ContentValues contactsValues = new ContentValues(); for (int i = 0; i < allowedContacts.length; i++) { contactsValues.put("settings_id", id); contactsValues.put("contact_id", allowedContacts[i]); if (db.insert(TABLE_ALLOWED_CONTACTS, null, contactsValues) == -1) throw new Exception("saveSettings - failed to update database entry (contacts)"); } } } else { // new entry -> insert if no duplicates exist // Log.d(TAG, "saveSettings - new entry; verifying if duplicates exist"); c = db.query( TABLE_SETTINGS, new String[] {"_id"}, "packageName=?", new String[] {s.getPackageName()}, null, null, null); if (c != null) { if (c.getCount() == 1) { // exactly one entry // exists -> update // Log.d(TAG, "saveSettings - updating existing entry"); if (db.update( TABLE_SETTINGS, values, "packageName=?", new String[] {s.getPackageName()}) < 1) { throw new Exception("saveSettings - failed to update database entry"); } if (c.moveToFirst()) { Integer idAlt = c.getInt(0); // id of the found duplicate entry db.delete(TABLE_ALLOWED_CONTACTS, "settings_id=?", new String[] {idAlt.toString()}); int[] allowedContacts = s.getAllowedContacts(); if (allowedContacts != null) { ContentValues contactsValues = new ContentValues(); for (int i = 0; i < allowedContacts.length; i++) { contactsValues.put("settings_id", idAlt); contactsValues.put("contact_id", allowedContacts[i]); if (db.insert(TABLE_ALLOWED_CONTACTS, null, contactsValues) == -1) throw new Exception( "saveSettings - failed to update database entry (contacts)"); } } } } else if (c.getCount() == 0) { // no entries -> insert // Log.d(TAG, "saveSettings - inserting new entry"); long rowId = db.insert(TABLE_SETTINGS, null, values); if (rowId == -1) { throw new Exception("saveSettings - failed to insert new record into DB"); } db.delete(TABLE_ALLOWED_CONTACTS, "settings_id=?", new String[] {Long.toString(rowId)}); int[] allowedContacts = s.getAllowedContacts(); if (allowedContacts != null) { ContentValues contactsValues = new ContentValues(); for (int i = 0; i < allowedContacts.length; i++) { contactsValues.put("settings_id", rowId); contactsValues.put("contact_id", allowedContacts[i]); if (db.insert(TABLE_ALLOWED_CONTACTS, null, contactsValues) == -1) throw new Exception("saveSettings - failed to update database entry (contacts)"); } } } else { // something went totally wrong and there are multiple entries for same // identifier result = false; throw new Exception("saveSettings - duplicate entries in the privacy.db"); } } else { result = false; // jump to catch block to avoid marking transaction as successful throw new Exception("saveSettings - cursor is null, database access failed"); } } // save settings to plain text file (for access from core libraries) // Log.d(TAG, "saveSettings - saving to plain text file"); // File settingsUidDir = new File("/data/system/privacy/" + packageName + "/" + uid // + "/"); File settingsPackageDir = new File("/data/system/privacy/" + packageName + "/"); File systemLogsSettingFile = new File("/data/system/privacy/" + packageName + "/" + "/systemLogsSetting"); try { // create all parent directories on the file path // settingsUidDir.mkdirs(); // make the directory readable (requires it to be executable as well) // settingsUidDir.setReadable(true, false); // settingsUidDir.setExecutable(true, false); // make the parent directory readable (requires it to be executable as well) settingsPackageDir.mkdirs(); settingsPackageDir.setReadable(true, false); settingsPackageDir.setExecutable(true, false); // create the setting files and make them readable systemLogsSettingFile.createNewFile(); systemLogsSettingFile.setReadable(true, false); // write settings to files // Log.d(TAG, "saveSettings - writing to file"); OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(systemLogsSettingFile)); writer.append(s.getSystemLogsSetting() + ""); writer.flush(); writer.close(); } catch (IOException e) { result = false; // jump to catch block to avoid marking transaction as successful throw new Exception("saveSettings - could not write settings to file", e); } // mark DB transaction successful (commit the changes) db.setTransactionSuccessful(); // Log.d(TAG, "saveSettings - completing transaction"); } catch (Exception e) { result = false; // Log.d(TAG, "saveSettings - could not save settings", e); } finally { db.endTransaction(); if (c != null) c.close(); synchronized (readingThreads) { readingThreads--; // only close DB if no other threads are reading if (readingThreads == 0 && db != null && db.isOpen()) { db.close(); } } } return result; }