Merge "read and store pb file from assets to CID table"
diff --git a/src/com/android/providers/telephony/CarrierIdProvider.java b/src/com/android/providers/telephony/CarrierIdProvider.java
index 08bb608..3dc1568 100644
--- a/src/com/android/providers/telephony/CarrierIdProvider.java
+++ b/src/com/android/providers/telephony/CarrierIdProvider.java
@@ -20,17 +20,29 @@
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
+import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
+import android.os.FileUtils;
+import android.os.UserHandle;
import android.provider.Telephony.CarrierIdentification;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.nano.CarrierIdProto;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -57,6 +69,43 @@
private static final String DATABASE_NAME = "carrierIdentification.db";
private static final int DATABASE_VERSION = 2;
+
+ private static final String ASSETS_PB_FILE = "carrier_list.pb";
+ private static final String ASSETS_FILE_CHECKSUM_PREF_KEY = "assets_checksum";
+ private static final String PREF_FILE = CarrierIdProvider.class.getSimpleName();
+
+ /**
+ * index 0: {@link CarrierIdentification#MCCMNC}
+ */
+ private static final int MCCMNC_INDEX = 0;
+ /**
+ * index 1: {@link CarrierIdentification#IMSI_PREFIX_XPATTERN}
+ */
+ private static final int IMSI_PREFIX_INDEX = 1;
+ /**
+ * index 2: {@link CarrierIdentification#GID1}
+ */
+ private static final int GID1_INDEX = 2;
+ /**
+ * index 3: {@link CarrierIdentification#GID2}
+ */
+ private static final int GID2_INDEX = 3;
+ /**
+ * index 4: {@link CarrierIdentification#PLMN}
+ */
+ private static final int PLMN_INDEX = 4;
+ /**
+ * index 5: {@link CarrierIdentification#SPN}
+ */
+ private static final int SPN_INDEX = 5;
+ /**
+ * index 6: {@link CarrierIdentification#APN}
+ */
+ private static final int APN_INDEX = 6;
+ /**
+ * ending index of carrier attribute list.
+ */
+ private static final int CARRIER_ATTR_END_IDX = APN_INDEX;
/**
* The authority string for the CarrierIdProvider
*/
@@ -103,6 +152,7 @@
Log.d(TAG, "onCreate");
mDbHelper = new CarrierIdDatabaseHelper(getContext());
mDbHelper.getReadableDatabase();
+ updateFromAssetsIfNeeded(mDbHelper.getWritableDatabase());
return true;
}
@@ -222,4 +272,183 @@
}
}
}
+
+ /**
+ * use check sum to detect assets file update.
+ * update database with data from assets only if checksum has been changed
+ * and OTA update is unavailable.
+ */
+ private void updateFromAssetsIfNeeded(SQLiteDatabase db) {
+ //TODO skip update from assets if OTA update is available.
+ final File assets;
+ try {
+ // create a temp file to compute check sum.
+ assets = new File(getContext().getCacheDir(), ASSETS_PB_FILE);
+ final OutputStream outputStream = new FileOutputStream(assets);
+ final byte[] bytes = readInputStreamToByteArray(
+ getContext().getAssets().open(ASSETS_PB_FILE));
+ outputStream.write(bytes);
+ } catch (IOException ex) {
+ Log.e(TAG, "assets file not found: " + ex);
+ return;
+ }
+ long checkSum = getChecksum(assets);
+ if (checkSum != getAssetsChecksum()) {
+ initDatabaseFromPb(assets, db);
+ setAssetsChecksum(checkSum);
+ }
+ }
+
+ /**
+ * parse and persist pb file as database default values.
+ */
+ private void initDatabaseFromPb(File pb, SQLiteDatabase db) {
+ Log.d(TAG, "init database from pb file");
+ try {
+ byte[] bytes = readInputStreamToByteArray(new FileInputStream(pb));
+ CarrierIdProto.CarrierList carrierList = CarrierIdProto.CarrierList.parseFrom(bytes);
+ List<ContentValues> cvs = new ArrayList<>();
+ for (CarrierIdProto.CarrierId id : carrierList.carrierId) {
+ for (CarrierIdProto.CarrierAttribute attr: id.carrierAttribute) {
+ ContentValues cv = new ContentValues();
+ cv.put(CarrierIdentification.CID, id.canonicalId);
+ cv.put(CarrierIdentification.NAME, id.carrierName);
+ convertCarrierAttrToContentValues(cv, cvs, attr, 0);
+ }
+ }
+ db.delete(CARRIER_ID_TABLE, null, null);
+ int rows = 0;
+ for (ContentValues cv : cvs) {
+ if (db.insertOrThrow(CARRIER_ID_TABLE, null, cv) > 0) rows++;
+ }
+ Log.d(TAG, "init database from pb. inserted rows = " + rows);
+ if (rows > 0) {
+ // Notify listener of DB change
+ getContext().getContentResolver().notifyChange(CarrierIdentification.CONTENT_URI,
+ null);
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "init database from pb failure: " + ex);
+ }
+ }
+
+ /**
+ * recursively loop through carrier attribute list to get all combinations.
+ */
+ private void convertCarrierAttrToContentValues(ContentValues cv, List<ContentValues> cvs,
+ CarrierIdProto.CarrierAttribute attr, int index) {
+ if (index > CARRIER_ATTR_END_IDX) {
+ cvs.add(new ContentValues(cv));
+ return;
+ }
+ boolean found = false;
+ switch(index) {
+ case MCCMNC_INDEX:
+ for (String str : attr.mccmncTuple) {
+ cv.put(CarrierIdentification.MCCMNC, str);
+ convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+ cv.remove(CarrierIdentification.MCCMNC);
+ found = true;
+ }
+ break;
+ case IMSI_PREFIX_INDEX:
+ for (String str : attr.imsiPrefixXpattern) {
+ cv.put(CarrierIdentification.IMSI_PREFIX_XPATTERN, str);
+ convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+ cv.remove(CarrierIdentification.IMSI_PREFIX_XPATTERN);
+ found = true;
+ }
+ break;
+ case GID1_INDEX:
+ for (String str : attr.gid1) {
+ cv.put(CarrierIdentification.GID1, str);
+ convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+ cv.remove(CarrierIdentification.GID1);
+ found = true;
+ }
+ break;
+ case GID2_INDEX:
+ for (String str : attr.gid2) {
+ cv.put(CarrierIdentification.GID2, str);
+ convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+ cv.remove(CarrierIdentification.GID2);
+ found = true;
+ }
+ break;
+ case PLMN_INDEX:
+ for (String str : attr.plmn) {
+ cv.put(CarrierIdentification.PLMN, str);
+ convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+ cv.remove(CarrierIdentification.PLMN);
+ found = true;
+ }
+ break;
+ case SPN_INDEX:
+ for (String str : attr.spn) {
+ cv.put(CarrierIdentification.SPN, str);
+ convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+ cv.remove(CarrierIdentification.SPN);
+ found = true;
+ }
+ break;
+ case APN_INDEX:
+ for (String str : attr.preferredApn) {
+ cv.put(CarrierIdentification.APN, str);
+ convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+ cv.remove(CarrierIdentification.APN);
+ found = true;
+ }
+ break;
+ default:
+ Log.e(TAG, "unsupported index: " + index);
+ break;
+ }
+ // if attribute at index is empty, move forward to the next attribute
+ if (!found) {
+ convertCarrierAttrToContentValues(cv, cvs, attr, index + 1);
+ }
+ }
+
+ /**
+ * util function to convert inputStream to byte array before parsing proto data.
+ */
+ private static byte[] readInputStreamToByteArray(InputStream inputStream) throws IOException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ int nRead;
+ int size = 16 * 1024; // Read 16k chunks
+ byte[] data = new byte[size];
+ while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, nRead);
+ }
+ buffer.flush();
+ return buffer.toByteArray();
+ }
+
+ /**
+ * util function to calculate checksum of a file
+ */
+ private long getChecksum(File file) {
+ long checksum = -1;
+ try {
+ checksum = FileUtils.checksumCrc32(file);
+ if (VDBG) Log.d(TAG, "Checksum for " + file.getAbsolutePath() + " is " + checksum);
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "FileNotFoundException for " + file.getAbsolutePath() + ":" + e);
+ } catch (IOException e) {
+ Log.e(TAG, "IOException for " + file.getAbsolutePath() + ":" + e);
+ }
+ return checksum;
+ }
+
+ private long getAssetsChecksum() {
+ SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
+ return sp.getLong(ASSETS_FILE_CHECKSUM_PREF_KEY, -1);
+ }
+
+ private void setAssetsChecksum(long checksum) {
+ SharedPreferences sp = getContext().getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putLong(ASSETS_FILE_CHECKSUM_PREF_KEY, checksum);
+ editor.apply();
+ }
}
\ No newline at end of file