am d2a0d233
: Use consistent device-id even the device is wiped.
Merge commit 'd2a0d23380a2751d82f9d1f955a812f94a301e2a' into froyo-plus-aosp * commit 'd2a0d23380a2751d82f9d1f955a812f94a301e2a': Use consistent device-id even the device is wiped.
This commit is contained in:
commit
ad383ff123
@ -32,8 +32,11 @@ import android.content.res.TypedArray;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.security.MessageDigest;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.Editable;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -43,6 +46,7 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
@ -527,4 +531,45 @@ public class Utility {
|
||||
task.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Device's unique ID if available. null if the device has no unique ID.
|
||||
*/
|
||||
public static String getConsistentDeviceId(Context context) {
|
||||
final String deviceId;
|
||||
try {
|
||||
TelephonyManager tm =
|
||||
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (tm == null) {
|
||||
return null;
|
||||
}
|
||||
deviceId = tm.getDeviceId();
|
||||
if (deviceId == null) {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(Email.LOG_TAG, "Error in TelephonyManager.getDeviceId(): " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
final MessageDigest sha;
|
||||
try {
|
||||
sha = MessageDigest.getInstance("SHA-1");
|
||||
} catch (NoSuchAlgorithmException impossible) {
|
||||
return null;
|
||||
}
|
||||
sha.update(Utility.toUtf8(deviceId));
|
||||
final int hash = getSmallHashFromSha1(sha.digest());
|
||||
return Integer.toString(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a non-negative integer generated from 20 byte SHA-1 hash.
|
||||
*/
|
||||
/* package for testing */ static int getSmallHashFromSha1(byte[] sha1) {
|
||||
final int offset = sha1[19] & 0xf; // SHA1 is 20 bytes.
|
||||
return ((sha1[offset] & 0x7f) << 24)
|
||||
| ((sha1[offset + 1] & 0xff) << 16)
|
||||
| ((sha1[offset + 2] & 0xff) << 8)
|
||||
| ((sha1[offset + 3] & 0xff));
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ package com.android.exchange;
|
||||
import com.android.email.AccountBackupRestore;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.SecurityPolicy;
|
||||
import com.android.email.Utility;
|
||||
import com.android.email.mail.MessagingException;
|
||||
import com.android.email.mail.transport.SSLUtils;
|
||||
import com.android.email.provider.EmailContent;
|
||||
@ -968,16 +969,19 @@ public class SyncManager extends Service implements Runnable {
|
||||
}
|
||||
|
||||
static public synchronized String getDeviceId(Context context) throws IOException {
|
||||
SyncManager syncManager = INSTANCE;
|
||||
if (sDeviceId != null) {
|
||||
return sDeviceId;
|
||||
} else if (syncManager == null && context == null) {
|
||||
if (sDeviceId == null) {
|
||||
sDeviceId = getDeviceIdInternal(context);
|
||||
}
|
||||
return sDeviceId;
|
||||
}
|
||||
|
||||
static private String getDeviceIdInternal(Context context) throws IOException {
|
||||
if (INSTANCE == null && context == null) {
|
||||
throw new IOException("No context for getDeviceId");
|
||||
} else if (context == null) {
|
||||
context = syncManager;
|
||||
context = INSTANCE;
|
||||
}
|
||||
|
||||
// Otherwise, we'll read the id file or create one if it's not found
|
||||
try {
|
||||
File f = context.getFileStreamPath("deviceName");
|
||||
BufferedReader rdr = null;
|
||||
@ -986,14 +990,18 @@ public class SyncManager extends Service implements Runnable {
|
||||
rdr = new BufferedReader(new FileReader(f), 128);
|
||||
id = rdr.readLine();
|
||||
rdr.close();
|
||||
sDeviceId = id;
|
||||
return id;
|
||||
} else if (f.createNewFile()) {
|
||||
BufferedWriter w = new BufferedWriter(new FileWriter(f), 128);
|
||||
id = "android" + System.currentTimeMillis();
|
||||
final String consistentDeviceId = Utility.getConsistentDeviceId(context);
|
||||
if (consistentDeviceId != null) {
|
||||
// Use different prefix from random IDs.
|
||||
id = "androidc" + consistentDeviceId;
|
||||
} else {
|
||||
id = "android" + System.currentTimeMillis();
|
||||
}
|
||||
w.write(id);
|
||||
w.close();
|
||||
sDeviceId = id;
|
||||
return id;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
@ -20,9 +20,11 @@ import com.android.email.provider.EmailContent.Mailbox;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.MoreAsserts;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@ -170,4 +172,37 @@ public class UtilityUnitTests extends AndroidTestCase {
|
||||
assertEquals("\r\n\r\n\r\n", Utility.replaceBareLfWithCrlf("\n\n\n"));
|
||||
assertEquals("A\r\nB\r\nC\r\nD", Utility.replaceBareLfWithCrlf("A\nB\r\nC\nD"));
|
||||
}
|
||||
|
||||
public void testGetConsistentDeviceId() {
|
||||
TelephonyManager tm =
|
||||
(TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
|
||||
if (tm == null) {
|
||||
Log.w(Email.LOG_TAG, "TelephonyManager not supported. Skipping.");
|
||||
return;
|
||||
}
|
||||
final String deviceId = Utility.getConsistentDeviceId(getContext());
|
||||
assertNotNull(deviceId);
|
||||
|
||||
final String deviceId2 = Utility.getConsistentDeviceId(getContext());
|
||||
// Should be consistent.
|
||||
assertEquals(deviceId, deviceId2);
|
||||
}
|
||||
|
||||
public void testGetSmallSha1() {
|
||||
byte[] sha1 = new byte[20];
|
||||
|
||||
// White box test. Not so great, but to make sure it may detect careless mistakes...
|
||||
assertEquals(0, Utility.getSmallHashFromSha1(sha1));
|
||||
|
||||
for (int i = 0; i < sha1.length; i++) {
|
||||
sha1[i] = (byte) 0xFF;
|
||||
}
|
||||
assertEquals(Integer.MAX_VALUE, Utility.getSmallHashFromSha1(sha1));
|
||||
|
||||
// Boundary check
|
||||
for (int i = 0; i < 16; i++) {
|
||||
sha1[19] = (byte) i;
|
||||
Utility.getSmallHashFromSha1(sha1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user