We WON!!
Sorry guys, everything I wrote before - is a bull****.
Here is right way and explanation.
So, how did I find where is this damn problem.
First of all, I turned ON adb debug on my phone and started investigation with logcat.
When going to Settings -> Accounts and Sync -> Add an account, i observed these lines
Code:
I/ActivityManager( 1803): START intent from pid 6695
I/HTCActionBar( 6695): enableHTCActionBar()
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.viber.voip.account
D/ChooseAccountActivity( 6695): accounts.length=0
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.dropbox.android.account
D/ChooseAccountActivity( 6695): accounts.length=1
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.htc.android.mail.eas
D/ChooseAccountActivity( 6695): accounts.length=0
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.whatsapp
D/ChooseAccountActivity( 6695): accounts.length=1
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.skype.contacts.sync
D/ChooseAccountActivity( 6695): accounts.length=1
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.htc.sync.provider.weather
D/ChooseAccountActivity( 6695): accounts.length=1
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
D/ChooseAccountActivity( 6695): MLongin=false
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.htc.android.windowslive
D/ChooseAccountActivity( 6695): accounts.length=0
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.htc.android.mail
D/ChooseAccountActivity( 6695): accounts.length=0
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.google
D/ChooseAccountActivity( 6695): accounts.length=3
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
D/skia ( 6695): Decode special JPEG file
D/skia ( 6695): Decode special JPEG file
I/[PP_CIME_PROVIDER]( 2018): release OK..........
I/ActivityManager( 1803): Displayed com.android.settings/.accounts.ChooseAccountActivity: +248ms (total +274ms)
first of all look at these lines
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.htc.sync.provider.weather
D/ChooseAccountActivity( 6695): accounts.length=1
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
D/ChooseAccountActivity( 6695): MLongin=false
D/ChooseAccountActivity( 6695): addAccountPrefQ accountType=com.google
D/ChooseAccountActivity( 6695): accounts.length=3
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
W/AccountManagerService( 1803): calling uid equals android.os.Process.SYSTEM_UID, ignore check hasAuthenticatorUid()
That was very strange for me why Google account can not be Multiple. OK.
I decompiled Settings.apk and found where this debugging is happening.
Function, which triggers logcat is following
Code:
private boolean addAccountPrefQ(String paramString)
{
Log.d("ChooseAccountActivity", "addAccountPrefQ accountType=" + paramString);
Account[] arrayOfAccount = AccountManager.get(this).getAccountsByType(paramString);
if (arrayOfAccount != null)
{
Log.d("ChooseAccountActivity", "accounts.length=" + arrayOfAccount.length);
int i = arrayOfAccount.length;
for (int j = 0; ; j++)
{
String str;
if (j < i)
{
Account localAccount = arrayOfAccount[j];
str = AccountManager.get(this).getUserData(localAccount, "MultipleLogin");
if (str != null)
Log.d("ChooseAccountActivity", "MLongin=" + str);
}
else
{
return str.equals("true");
}
}
}
return false;
}
If this function is private, that is mean we must have parent invoker. Yes, parent function is following
Code:
private void onAuthDescriptionsUpdated()
{
this.mProviderList.clear();
int i = 0;
if (i < this.mAuthDescs.length)
{
String str = this.mAuthDescs[i].type;
CharSequence localCharSequence = getLabelForType(str);
ArrayList localArrayList1 = getAuthoritiesForAccountType(str);
int m = 1;
int n;
if ((this.mAuthorities != null) && (this.mAuthorities.length > 0) && (localArrayList1 != null))
{
n = 0;
label71: int i1 = this.mAuthorities.length;
m = 0;
if (n < i1)
{
if (!localArrayList1.contains(this.mAuthorities[n]))
break label203;
m = 1;
}
}
if ((m != 0) && (this.mAccountTypesFilter != null) && (!this.mAccountTypesFilter.contains(str)))
m = 0;
boolean bool = addAccountPrefQ(str);
if ((str.equals("com.google")) && (BuildUtils.Customization.isChina()))
m = 0;
if ((m != 0) && (bool))
{
ArrayList localArrayList2 = this.mProviderList;
ProviderEntry localProviderEntry2 = new ProviderEntry(localCharSequence, str);
localArrayList2.add(localProviderEntry2);
}
while (true)
{
i++;
break;
label203: n++;
break label71;
if (Log.isLoggable("ChooseAccountActivity", 2))
Log.v("ChooseAccountActivity", "Skipped pref " + localCharSequence + ": has no authority we need");
}
}
if (this.mProviderList.size() == 1)
addAccount(((ProviderEntry)this.mProviderList.get(0)).type);
while (true)
{
return;
if (this.mProviderList.size() <= 0)
break;
Collections.sort(this.mProviderList);
if (this.mAddAccountGroup != null)
this.mAddAccountGroup.removeAll();
Iterator localIterator = this.mProviderList.iterator();
while (localIterator.hasNext())
{
ProviderEntry localProviderEntry1 = (ProviderEntry)localIterator.next();
Drawable localDrawable = getDrawableForType(localProviderEntry1.type);
ProviderPreference localProviderPreference = new ProviderPreference(this, localProviderEntry1.type, localDrawable, localProviderEntry1.name);
this.mAddAccountGroup.addPreference(localProviderPreference);
}
}
if (Log.isLoggable("ChooseAccountActivity", 2))
{
StringBuilder localStringBuilder = new StringBuilder();
String[] arrayOfString = this.mAuthorities;
int j = arrayOfString.length;
for (int k = 0; k < j; k++)
{
localStringBuilder.append(arrayOfString[k]);
localStringBuilder.append(' ');
}
Log.v("ChooseAccountActivity", "No providers found for authorities: " + localStringBuilder);
}
setResult(0);
finish();
}
If you deeply look at this code, you will find something interesting
boolean bool = addAccountPrefQ(str);
if ((str.equals("com.google")) && (BuildUtils.Customization.isChina()))
m = 0;
Ok, I took smali file of this package and changed code a little bit
BEFORE
Code:
.line 191
invoke-static {}, Lcom/htc/util/contacts/BuildUtils$Customization;->isChina()Z
move-result v18
if-eqz v18, :cond_2
AFTER
Code:
.line 191
invoke-static {}, Lcom/htc/util/contacts/BuildUtils$Customization;->isChina()Z
move-result v18
if-nez v18, :cond_2
difference on last line, I changed if-eqz to if-nez.
Then I pushed patched Settings.apk to my phone and checked Add new account menu.
Yahoooooo!!! It works. I see Google account!! But unfortunately only for viewing. It is read only because not everywhere patch applied. Ok, I continued my investigation.
I decompiled framework completely and found such function in two jars (com.htc.android.bluetooth.jar and HTCExtension.src).
Code:
public static boolean isChina()
{
if ((HtcBuildFlag.Htc_PROJECT_flag == 216) || (HtcBuildFlag.Htc_PROJECT_flag == 218) || (HtcBuildFlag.Htc_PROJECT_flag == 23));
while (((HtcBuildFlag.Htc_PROJECT_flag == 1) && (2 == HtcBuildFlag.Htc_LANGUAGE_flag)) || (HtcBuildFlag.Htc_PROJECT_flag == 27))
return true;
return false;
}
Ok. It is not efficient to change standard function, let's find where
Htc_PROJECT_flag is located.
Grepping through the source code I found it in two jars (framework2.jar and ext.jar)
Code:
package com.htc.htcjavaflag.HtcDebugFlag;
public static final short Htc_PROJECT_flag = getHtc_PROJECT_flag();
public static final short getHtc_PROJECT_flag()
{
return 23;
}
Ok, Good! It is hard coded and can be changed. But what value put there? I took another rom from the simmilar dual sim device with working rom and found that this package returns 52.
Ok, taking smali from both jars and looking at this code
Code:
.method public static final getHtc_PROJECT_flag()S
.registers 1
.prologue
.line 1799
const/16 v0, 0x17
return v0
.end method
(HEX) 0x17 = (DEC) 23
so changing to 0x34
Code:
.method public static final getHtc_PROJECT_flag()S
.registers 1
.prologue
.line 1799
const/16 v0, 0x34
return v0
.end method
deodexing both jars, backsmaling, patching, smaling back, replacing on the phone and .... brick
May be because system framework must be fully odexed or fully deodexed, but not partly. In my case I put deodexed jars to odexed rom.
Ok. restoring from last and not fresh backup
Let's try another way: we will reodex our patched jar, then will make binary comparison between our patched and stock odex files to be sure everything is ok and no need to deodex some of framework jars. This will be usefull to apply patch after OTA updates and do not assemble/disassemble each time.
to be continued.