Home | History | Annotate | Download | only in service
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.omadm.service;
     18 
     19 import android.content.ComponentName;
     20 import android.content.ContentValues;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.ServiceConnection;
     24 import android.content.SharedPreferences;
     25 import android.content.res.Resources;
     26 import android.database.Cursor;
     27 import android.database.sqlite.SQLiteDatabase;
     28 import android.os.IBinder;
     29 import android.text.TextUtils;
     30 import android.util.Log;
     31 
     32 import com.android.omadm.plugin.IDmtPlugin;
     33 
     34 import org.xmlpull.v1.XmlPullParser;
     35 import org.xmlpull.v1.XmlPullParserException;
     36 import org.xmlpull.v1.XmlPullParserFactory;
     37 
     38 import java.io.BufferedInputStream;
     39 import java.io.File;
     40 import java.io.FileInputStream;
     41 import java.io.IOException;
     42 import java.io.InputStream;
     43 
     44 public class DMConfigureDB {
     45     private static final String TAG = "DMConfigureDB";
     46     private static final boolean DBG = DMClientService.DBG;
     47 
     48     private final DMClientService mContext;
     49 
     50     private static final String DATABASE_NAME = "DMConfigure.db";
     51 
     52     private final SQLiteDatabase mdb;
     53 
     54     private IDmtPlugin mPluginConnection;
     55 
     56     private String isBoundTo = null;
     57 
     58     protected final Object mLock = new Object();
     59 
     60     private ServiceConnection mConnection = new ServiceConnection() {
     61 
     62         @Override
     63         public void onServiceConnected(ComponentName className,
     64                                        IBinder service) {
     65             logd("onServiceConnected");
     66             synchronized (mLock) {
     67                 // this gets an instance of the IRemoteInterface, which we can use to call on the service
     68                 mPluginConnection = IDmtPlugin.Stub.asInterface(service);
     69                 mLock.notifyAll();
     70             }
     71         }
     72 
     73         @Override
     74         public void onServiceDisconnected(ComponentName arg0) {
     75             logd("onServiceDisconnected");
     76             synchronized (mLock) {
     77                 mPluginConnection = null;
     78             }
     79         }
     80     };
     81 
     82     static final class AccountInfo {
     83         public String acctName;     // DM server account name
     84         public String serverID;     // DM server ID
     85         public String addr;         // DM server URL
     86         public String addrType;     // e.g. "URI"
     87         public String portNbr;      // DM server port, e.g. "443"
     88         public String conRef;       // e.g. ""
     89         public String serverName;   // DM server name
     90         public String authPref;     // e.g. "HMAC"
     91         public String serverPW;     // HMAC server password
     92         public String serverNonce;  // HMAC server nonce
     93         public String userName;     // DM username (e.g. IMSI or MEID)
     94         public String clientPW;     // HMAC client password
     95         public String clientNonce;  // HMAC client nonce
     96         public String proxyAddr;    // HTTP proxy address
     97         public String proxyPortNbr; // HTTP proxy port, e.g. "80"
     98     }
     99 
    100     public DMConfigureDB(DMClientService context) {
    101         mContext = context;
    102         mdb = mContext.openOrCreateDatabase(DATABASE_NAME, 0, null);
    103         Cursor cur = null;
    104         try {
    105             cur = mdb.rawQuery("PRAGMA table_info( dmAccounts )", null);
    106             int cnt = cur.getCount();
    107             if (DBG) logd("Cursor count for table dmAccounts is " + cnt);
    108             // TODO: we need a way for plugins to populate an empty table
    109             if (cnt == 0) {
    110                 onCreate(mdb);
    111             }
    112             // NOTE: always update all the account info in DM tree
    113             loadDmConfig();
    114             loadDmAccount(mdb);
    115 
    116         } catch (Exception e) {
    117             loge("exception in DMConfigureDB", e);
    118         } finally {
    119             if (cur != null) {
    120                 cur.close();
    121             }
    122         }
    123     }
    124 
    125     public void closeDatabase() {
    126         mdb.close();
    127         unbind();
    128     }
    129 
    130     void onCreate(SQLiteDatabase db) {
    131         logd("onCreate");
    132 
    133         db.execSQL("CREATE TABLE dmAccounts (" +
    134                 "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
    135                 "ServerID TEXT UNIQUE ON CONFLICT REPLACE," +
    136                 "AccName TEXT," +
    137                 "Addr TEXT," +
    138                 "AddrType TEXT," +
    139                 "PortNbr TEXT," +
    140                 "ConRef TEXT," +
    141                 "Name TEXT," +
    142                 "AuthPref TEXT," +
    143                 "ServerPW TEXT," +
    144                 "ServerNonce TEXT," +
    145                 "UserName TEXT," +
    146                 "ClientPW TEXT," +
    147                 "ClientNonce TEXT," +
    148                 "ProxyAddr TEXT," +
    149                 "ProxyPortNbr TEXT" +
    150                 ");");
    151 
    152         db.execSQL("CREATE TABLE dmFlexs (" +
    153                 "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
    154                 "name TEXT UNIQUE ON CONFLICT REPLACE," +
    155                 "value TEXT" +
    156                 ");");
    157     }
    158 
    159     public String getFotaServerID() {
    160         String id = getConfigField("PreferredServerID");
    161 
    162         if (id != null && !id.isEmpty()) {
    163             return id;
    164         }
    165 
    166         return getConfigField("FOTAServerID");
    167     }
    168 
    169     public boolean isDmAlertEnabled() {
    170         String value = getConfigField("DmAlertEnabled");
    171         return null == value || "true".equalsIgnoreCase(value);
    172     }
    173 
    174     public boolean isDmNonceResyncEnabled() {
    175         String value = getConfigField("DmNonceResyncEnabled");
    176         return null != value && "true".equalsIgnoreCase(value);
    177     }
    178 
    179     /*
    180      * Returns SyncML logging level
    181      * 0 = do not log syncml messages
    182      * 1 = log messages received as is
    183      * 2 = convert wbxml to xml messages and log it
    184      */
    185     public int getSyncMLLogLevel() {
    186         return 1;
    187 
    188 //        String value = getConfigField("DmSyncMLLogLevel");
    189 //        if (null == value) {
    190 //            return 0;
    191 //        }
    192 //        return Integer.parseInt(value);
    193     }
    194 
    195     private String getConfigField(String field) {
    196         String value = null;
    197 
    198         Cursor cr = mdb.query("dmFlexs", null, "name='" + field + '\'', null, null, null, null);
    199 
    200         if (cr != null) {
    201             if (cr.moveToFirst()) {
    202                 int index = cr.getColumnIndex("value");
    203                 value = cr.getString(index);
    204             }
    205             cr.close();
    206         }
    207 
    208         if (DBG) logd("get field '" + field + "'=" + value);
    209         return value;
    210     }
    211 
    212     public void setFotaServerID(String serverID) {
    213         ContentValues values = new ContentValues(1);
    214 
    215         //values.put("Name", "FOTAServerID");
    216         values.put("value", serverID);
    217 
    218         mdb.update("dmFlexs", values, "name='FOTAServerID'", null);
    219     }
    220 
    221     void setGsmImei(String imei) {
    222         ContentValues values = new ContentValues();
    223         values.put("name", "gsmImei");
    224         values.put("value", imei);
    225         mdb.insert("dmFlexs", null, values);
    226 
    227     }
    228 
    229     private void loadDmConfig() {
    230         //following statements just for debug print
    231         getConfigField("CarrierName");
    232         getConfigField("AdditionalCharge");
    233         getConfigField("PreferredServerID");
    234 
    235         // FIXME: this should be removed along with get/setGsmImei()
    236         if (DMSettingsHelper.isPhoneTypeLTE()) {
    237             SharedPreferences p = mContext.getSharedPreferences(DMHelper.IMEI_PREFERENCE_KEY, 0);
    238             String gsmImei = p.getString(DMHelper.IMEI_VALUE_KEY, null);
    239             logd("gsmImei in loadDmConfig is " + gsmImei);
    240             //ed.clear();
    241             if (null == gsmImei || gsmImei.isEmpty()) {
    242                 // this is needed to avoid showing DMService app force close
    243                 logd("set the imei value to zero");
    244                 gsmImei = "0";
    245             } else if (gsmImei.length() > 15) {
    246                 logd("imei length exceeding 15 digits so trim it to 15");
    247                 gsmImei = gsmImei.substring(0, 15);
    248             }
    249             setGsmImei(gsmImei);
    250         }
    251         ///////////////////////////////////////////
    252 
    253     }
    254 
    255     private void loadDmAccount(SQLiteDatabase db) {
    256         AccountInfo ai = new AccountInfo();
    257         boolean isFirst = true;
    258 
    259         Cursor cr = db.rawQuery("SELECT * FROM dmAccounts", null);
    260 
    261         if (cr != null) {
    262             if (cr.moveToFirst()) {
    263                 do {
    264                     ai.acctName = cr.getString(cr.getColumnIndex("AccName"));
    265                     logd("[Factory]account=" + ai.acctName);
    266 
    267                     ai.serverID = cr.getString(cr.getColumnIndex("ServerID"));
    268                     if (DBG) logd("[Factory]serverID=" + ai.serverID);
    269 
    270                     ai.addr = cr.getString(cr.getColumnIndex("Addr"));
    271                     if (DBG) logd("[Factory]addr=" + ai.addr);
    272 
    273                     ai.addrType = cr.getString(cr.getColumnIndex("AddrType"));
    274                     if (DBG) logd("[Factory]addrType=" + ai.addrType);
    275 
    276                     ai.portNbr = cr.getString(cr.getColumnIndex("PortNbr"));
    277                     if (DBG) logd("[Factory]portNbr=" + ai.portNbr);
    278 
    279                     ai.conRef = cr.getString(cr.getColumnIndex("ConRef"));
    280                     if (DBG) logd("[Factory]conRef=" + ai.conRef);
    281 
    282                     ai.serverName = cr.getString(cr.getColumnIndex("Name"));
    283                     if (DBG) logd("[Factory]serverName=" + ai.serverName);
    284 
    285                     ai.authPref = cr.getString(cr.getColumnIndex("AuthPref"));
    286                     if (DBG) logd("[Factory]authPref=" + ai.authPref);
    287 
    288                     ai.serverPW = cr.getString(cr.getColumnIndex("ServerPW"));
    289                     if (DBG) logd("[Factory]serverPW=" + ai.serverPW);
    290 
    291                     ai.serverNonce = cr.getString(cr.getColumnIndex("ServerNonce"));
    292                     if (DBG) logd("[Factory]serverNonce=" + ai.serverNonce);
    293 
    294                     ai.userName = cr.getString(cr.getColumnIndex("UserName"));
    295                     if (DBG) logd("[Factory]userName=" + ai.userName);
    296 
    297                     ai.clientPW = cr.getString(cr.getColumnIndex("ClientPW"));
    298                     if (DBG) logd("[Factory]clientPW=" + ai.clientPW);
    299 
    300                     ai.clientNonce = cr.getString(cr.getColumnIndex("ClientNonce"));
    301                     if (DBG) logd("[Factory]clientNonce=" + ai.clientNonce);
    302 
    303                     ai.proxyAddr = cr.getString(cr.getColumnIndex("ProxyAddr"));
    304                     if (DBG) logd("[Factory]proxyAddr=" + ai.proxyAddr);
    305 
    306                     ai.proxyPortNbr = cr.getString(cr.getColumnIndex("ProxyPortNbr"));
    307                     if (DBG) logd("[Factory]proxyPortNbr=" + ai.proxyPortNbr);
    308 
    309                     if (writeAccount2Dmt(ai) && isFirst) {
    310                         if (DBG) logd("[Factory]setFotaServerID: " + ai.serverID);
    311 
    312                         ContentValues values = new ContentValues();
    313                         values.put("name", "FOTAServerID");
    314                         values.put("value", ai.serverID);
    315                         db.insert("dmFlexs", null, values);
    316 
    317                         isFirst = false;
    318                     }
    319 
    320                 } while (cr.moveToNext());
    321 
    322                 cr.close();
    323                 return;
    324             }
    325             cr.close();
    326         }
    327 
    328         try {
    329             XmlPullParser xpp = null;
    330             String[] accountInfo = null;
    331             int eventType = 0;
    332             int num_accounts = 0;
    333             InputStream in = getDMAccXmlInput();
    334 
    335             if (in != null) {
    336                 XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
    337                 factory.setNamespaceAware(true);
    338                 xpp = factory.newPullParser();
    339                 xpp.setInput(in, null);
    340                 eventType = xpp.getEventType();
    341             } else {
    342                 logd("Reading dmAccounts from res");
    343                 Resources res = mContext.getResources();
    344                 accountInfo = res.getStringArray(R.array.dm_account_info);
    345                 if (accountInfo == null) {
    346                     if (DBG) logd("accountInfo == null");
    347                     return;
    348                 } else {
    349                     logd("Number of accounts = " + accountInfo.length);
    350                 }
    351             }
    352 
    353             while ((in != null && eventType != XmlPullParser.END_DOCUMENT) ||
    354                     (in == null && num_accounts < accountInfo.length)) {
    355                 if (in == null ||
    356                         (eventType == XmlPullParser.START_TAG && "Account".equals(xpp.getName()))) {
    357                     String[] account = null;
    358                     if (in == null) {
    359                         account = accountInfo[num_accounts].split(", ");
    360                         if (account == null) {
    361                             loge("account == null; invalid account info");
    362                         } else {
    363                             if (DBG) logd("Account # " + (num_accounts + 1) +
    364                                     "; number of fields = " + account.length);
    365                         }
    366                     }
    367 
    368                     ai.acctName = getAttributeValue(xpp, "AccName", account, 0);
    369                     logd("account=" + ai.acctName);
    370 
    371                     ai.serverID = getAttributeValue(xpp, "ServerID", account, 1);
    372                     if (DBG) logd("serverID=" + ai.serverID);
    373 
    374                     ai.addr = getRealString(getAttributeValue(xpp, "Addr", account, 2));
    375                     if (DBG) logd("addr=" + ai.addr);
    376 
    377                     ai.addrType = getAttributeValue(xpp, "AddrType", account, 3);
    378                     if (DBG) logd("addrType=" + ai.addrType);
    379 
    380                     ai.portNbr = getAttributeValue(xpp, "PortNbr", account, 4);
    381                     if (DBG) logd("portNbr=" + ai.portNbr);
    382 
    383                     ai.conRef = getAttributeValue(xpp, "ConRef", account, 5);
    384                     if (DBG) logd("conRef=" + ai.conRef);
    385 
    386                     ai.serverName = getAttributeValue(xpp, "ServerName", account, 6);
    387                     if (DBG) logd("serverName=" + ai.serverName);
    388 
    389                     ai.authPref = getAttributeValue(xpp, "AuthPref", account, 7);
    390                     if (DBG) logd("authPref=" + ai.authPref);
    391 
    392                     ai.serverPW = getAttributeValue(xpp, "ServerPW", account, 8);
    393                     if (DBG) logd("serverPW=" + ai.serverPW);
    394 
    395                     ai.serverNonce = getAttributeValue(xpp, "ServerNonce", account, 9);
    396                     if (DBG) logd("serverNonce=" + ai.serverNonce);
    397 
    398                     ai.userName = getAttributeValue(xpp, "UserName", account, 10);
    399                     if (DBG) logd("userName=" + ai.userName);
    400 
    401                     ai.clientPW = getAttributeValue(xpp, "ClientPW", account, 11);
    402                     if (DBG) logd("clientPW=" + ai.clientPW);
    403 
    404                     ai.clientNonce = getAttributeValue(xpp, "ClientNonce", account, 12);
    405                     if (DBG) logd("clientNonce=" + ai.clientNonce);
    406 
    407                     ai.proxyAddr = getRealString(getAttributeValue(xpp, "ProxyAddr", account, 13));
    408                     if (DBG) logd("proxyAddr=" + ai.proxyAddr);
    409 
    410                     ai.proxyPortNbr = getRealString(getAttributeValue(xpp, "ProxyPortNbr", account, 14));
    411                     if (DBG) logd("addr=" + ai.proxyPortNbr);
    412 
    413                     // FIXME: check should be on account name instead of isFirst
    414                     if (writeAccount2Dmt(ai) && isFirst) {
    415                         if (DBG) logd("setFotaServerID: " + ai.serverID);
    416 
    417                         ContentValues values = new ContentValues();
    418                         values.put("name", "FOTAServerID");
    419                         values.put("value", ai.serverID);
    420                         db.insert("dmFlexs", null, values);
    421                         isFirst = false;
    422                     }
    423                 }
    424 
    425                 if (in != null) {
    426                     eventType = xpp.next();
    427                 } else {
    428                     num_accounts++;
    429                 }
    430             }
    431 
    432             if (in != null) {
    433                 in.close();
    434             }
    435 
    436         } catch (IOException e) {
    437             loge("IOException in loadDmAccount", e);
    438         } catch (XmlPullParserException e) {
    439             loge("XmlPullParserException in loadDmAccount", e);
    440         }
    441     }
    442 
    443     private String getAttributeValue(XmlPullParser xpp, String attribute, String[] account, int idx) {
    444         if (xpp != null) {
    445             return xpp.getAttributeValue(null, attribute);
    446         } else if (account != null && idx < account.length) {
    447             return account[idx];
    448         } else {
    449             return null;
    450         }
    451     }
    452 
    453     private boolean writeAccount2Dmt(AccountInfo ai) {
    454         if (DBG) logd("enter writeAccount2Dmt");
    455 
    456         String acctName = ai.serverID;     // e.g. "sprint"; this is also the value for ServerID
    457         String dmServerNodePath = "./DMAcc/" + acctName;
    458 
    459         logd("XXX DELETING old server node path: " + dmServerNodePath);
    460         NativeDM.deleteNode(dmServerNodePath);
    461 
    462         if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) {
    463             loge("createInterior '" + acctName + "' Error");
    464             return false;
    465         }
    466 
    467         if (NativeDM.createLeaf(dmServerNodePath + "/ServerID", ai.serverID)
    468                 != DMResult.SYNCML_DM_SUCCESS) {
    469             loge("createInterior '" + dmServerNodePath + "/ServerId' Error");
    470             return false;
    471         }
    472 
    473         if (NativeDM.createLeaf(dmServerNodePath + "/AppID", "w7") != DMResult.SYNCML_DM_SUCCESS) {
    474             loge("createInterior '" + dmServerNodePath + "/AppID' Error");
    475             return false;
    476         }
    477 
    478         if (NativeDM.createLeaf(dmServerNodePath + "/Name", ai.serverName)
    479                 != DMResult.SYNCML_DM_SUCCESS) {
    480             loge("createLeaf '" + dmServerNodePath + "/Name' Error");
    481             return false;
    482         }
    483 
    484         if (NativeDM.createLeaf(dmServerNodePath + "/PrefConRef", ai.conRef)
    485                 != DMResult.SYNCML_DM_SUCCESS) {
    486             loge("createLeaf '" + dmServerNodePath + "/ConRef' Error");
    487             return false;
    488         }
    489 
    490         if (NativeDM.createLeaf(dmServerNodePath + "/AAuthPref", ai.authPref)
    491                 != DMResult.SYNCML_DM_SUCCESS) {
    492             loge("createLeaf '" + dmServerNodePath + "/AAuthPref' Error");
    493             return false;
    494         }
    495 
    496         dmServerNodePath += "/AppAddr";
    497         if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) {
    498             loge("createInterior '" + dmServerNodePath + "' Error");
    499             return false;
    500         }
    501 
    502         dmServerNodePath += "/1";   // limited to one server address per account
    503 
    504         if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) {
    505             loge("createInterior '" + dmServerNodePath + "' Error");
    506             return false;
    507         }
    508 
    509         if ("sprint".equalsIgnoreCase(ai.serverID)) {
    510             String address = DMHelper.getServerUrl(mContext);
    511             if (!TextUtils.isEmpty(address)) {
    512                 logd("Overriding server URL to: " + address);
    513                 ai.addr = address;
    514             }
    515         }
    516 
    517         if (NativeDM.createLeaf(dmServerNodePath + "/Addr", ai.addr)
    518                 != DMResult.SYNCML_DM_SUCCESS) {
    519             loge("createLeaf '" + dmServerNodePath + "/Addr' Error");
    520             return false;
    521         }
    522 
    523         if (NativeDM.createLeaf(dmServerNodePath + "/AddrType", ai.addrType)
    524                 != DMResult.SYNCML_DM_SUCCESS) {
    525             loge("createLeaf '" + dmServerNodePath + "/AddrType' Error");
    526             return false;
    527         }
    528 
    529         dmServerNodePath += "/Port";
    530         if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) {
    531             loge("createInterior '" + dmServerNodePath + "' Error");
    532             return false;
    533         }
    534 
    535         dmServerNodePath += "/1";   // limited to one port number per server address
    536 
    537         if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) {
    538             loge("createInterior '" + dmServerNodePath + "' Error");
    539             return false;
    540         }
    541 
    542         if (NativeDM.createLeaf(dmServerNodePath + "/PortNbr", ai.portNbr)
    543                 != DMResult.SYNCML_DM_SUCCESS) {
    544             loge("createLeaf '" + dmServerNodePath + "/PortNbr' Error");
    545             return false;
    546         }
    547 
    548         // collection of authentication credentials
    549         dmServerNodePath = "./DMAcc/" + acctName + "/AppAuth";
    550 
    551         if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) {
    552             loge("createInterior '" + dmServerNodePath + "' Error");
    553             return false;
    554         }
    555 
    556         // server credentials for authenticating the server from the OMA DM client
    557         dmServerNodePath += "/Server";
    558 
    559         if (NativeDM.createInterior(dmServerNodePath) != DMResult.SYNCML_DM_SUCCESS) {
    560             loge("createInterior '" + dmServerNodePath + "' Error");
    561             return false;
    562         }
    563 
    564         String authLevel = "SRVCRED";
    565 
    566         if (NativeDM.createLeaf(dmServerNodePath + "/AAuthLevel", authLevel)
    567                 != DMResult.SYNCML_DM_SUCCESS) {
    568             loge("createLeaf '" + dmServerNodePath + "/AAuthLevel' Error");
    569             return false;
    570         }
    571 
    572         if (NativeDM.createLeaf(dmServerNodePath + "/AAuthType", ai.authPref)
    573                 != DMResult.SYNCML_DM_SUCCESS) {
    574             loge("createLeaf '" + dmServerNodePath + "/AAuthType' Error");
    575             return false;
    576         }
    577 
    578         if (NativeDM.createLeaf(dmServerNodePath + "/AAuthName", acctName)
    579                 != DMResult.SYNCML_DM_SUCCESS) {
    580             loge("createLeaf '" + dmServerNodePath + "/AAuthName' Error");
    581             return false;
    582         }
    583 
    584         if (ai.serverID.equalsIgnoreCase("sprint") ||
    585                 ai.serverID.equalsIgnoreCase("com.vzwdmserver")) {
    586             String intentName;
    587             String serviceName;
    588             if (ai.serverID.equalsIgnoreCase("sprint")) {
    589                 intentName = "com.android.sdm.plugins.sprintdm.SprintDMPlugin";
    590                 serviceName = "SprintDMService";
    591             } else {
    592                 intentName = "com.android.sdm.plugins.connmo.ConnmoPlugin";
    593                 serviceName = "ConnmoService";
    594             }
    595             logd("ServerID is " + ai.serverID);
    596             if (isBoundTo == null || !isBoundTo.equalsIgnoreCase(ai.serverID)) {
    597                 unbind();
    598                 Intent intent = new Intent(intentName);
    599                 if (mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
    600                     isBoundTo = ai.serverID;
    601                     synchronized (mLock) {
    602                         if (mPluginConnection == null) {
    603                             logd("Waiting for binding to " + serviceName);
    604                             try {
    605                                 mLock.wait();
    606                             } catch (Exception e) {
    607                                 loge("Exception in writeAccount2Dmt->wait: ", e);
    608                             }
    609                         }
    610                     }
    611                 }
    612             } else {
    613                 logd("Already bound to " + serviceName);
    614             }
    615         } else {
    616             unbind();
    617         }
    618 
    619         boolean hasWriteServerPW = false;
    620         try {
    621             if (mPluginConnection != null) {
    622                 String serverPW = mPluginConnection.getServerPW(ai.serverPW);
    623                 if (serverPW != null) {
    624                     ai.serverPW = serverPW;
    625                     logd("ServerPW from plugin: " + serverPW);
    626                 } else {
    627                     // This must be for vzw
    628                     byte[] svrPasswd = hexStringToBytes(ai.serverPW);
    629                     if (NativeDM.createLeaf(dmServerNodePath + "/AAuthSecret", svrPasswd)
    630                             != DMResult.SYNCML_DM_SUCCESS) {
    631                         loge("CreateLeaf '"+dmServerNodePath + "/AAuthSecret' Error");
    632                         return false;
    633                     }
    634                     hasWriteServerPW = true;
    635                 }
    636             } else {
    637                 logd("Using default ServerPW from dmAccounts: " + ai.serverPW);
    638             }
    639         } catch (Exception e) {
    640             loge("Exception in writeAccount2Dmt->getServerPW", e);
    641         }
    642 
    643         if (!hasWriteServerPW && NativeDM.createLeaf(dmServerNodePath + "/AAuthSecret", ai.serverPW)
    644                 != DMResult.SYNCML_DM_SUCCESS) {
    645             loge("createLeaf '" + dmServerNodePath + "/AAuthSecret' Error");
    646             return false;
    647         }
    648 
    649         if (NativeDM.createLeaf(dmServerNodePath + "/AAuthData", ai.serverNonce)
    650                 != DMResult.SYNCML_DM_SUCCESS) {
    651             loge("createLeaf '" + dmServerNodePath + "/AAuthData' Error");
    652             return false;
    653         }
    654 
    655         // client credentials for authenticating ourselves to the OMA DM server
    656         String dmClientNodePath = "./DMAcc/" + acctName + "/AppAuth/Client";
    657 
    658         if (NativeDM.createInterior(dmClientNodePath) != DMResult.SYNCML_DM_SUCCESS) {
    659             loge("createInterior '" + dmServerNodePath + "' Error");
    660             return false;
    661         }
    662 
    663         String clientAuthLevel = "CLCRED";
    664 
    665         if (NativeDM.createLeaf(dmClientNodePath + "/AAuthLevel", clientAuthLevel)
    666                 != DMResult.SYNCML_DM_SUCCESS) {
    667             loge("createLeaf '" + dmClientNodePath + "/AAuthLevel' Error");
    668             return false;
    669         }
    670 
    671         String clientAuthType = ai.authPref;
    672         if (NativeDM.createLeaf(dmClientNodePath + "/AAuthType", clientAuthType)
    673                 != DMResult.SYNCML_DM_SUCCESS) {
    674             loge("createLeaf '" + dmClientNodePath + "/AAuthType' Error");
    675             return false;
    676         }
    677 
    678         boolean hasWriteUserName = false;
    679         try {
    680             if (mPluginConnection != null) {
    681                 String username = mPluginConnection.getUsername(ai.userName);
    682                 if (username != null) {
    683                     ai.userName = username;
    684                     logd("Username from plugin: " + username);
    685                 } else {
    686                     // This must be for vzw
    687                     byte[] clientName = hexStringToBytes(ai.userName);//"e0e5e7eaebeb");
    688                     if (NativeDM.createLeaf(dmClientNodePath + "/AAuthName", clientName)
    689                             != DMResult.SYNCML_DM_SUCCESS) {
    690                         loge("CreateLeaf '"+dmClientNodePath + "/AAuthName' Error");
    691                         return false;
    692                     }
    693                     hasWriteUserName = true;
    694                 }
    695             } else {
    696                 logd("Using default username from dmAccounts: " + ai.userName);
    697             }
    698         } catch (Exception e) {
    699             loge("Exception in writeAccount2Dmt->getUsername", e);
    700         }
    701 
    702         if (!hasWriteUserName && NativeDM.createLeaf(dmClientNodePath + "/AAuthName", ai.userName)
    703                 != DMResult.SYNCML_DM_SUCCESS) {
    704             loge("createLeaf '" + dmClientNodePath + "/AAuthName' Error");
    705             return false;
    706         }
    707 
    708         boolean hasWriteClientPW = false;
    709         try {
    710             if (mPluginConnection != null) {
    711                 String clientPW = mPluginConnection.getClientPW(ai.clientPW);
    712                 if (clientPW != null) {
    713                     ai.clientPW = clientPW;
    714                     logd("ClientPW from plugin: " + clientPW);
    715                 } else {
    716                     // This must be for vzw
    717                     byte[] clientPasswd=hexStringToBytes(ai.clientPW);//"ebe8efeeecec");
    718                     if (NativeDM.createLeaf(dmClientNodePath + "/AAuthSecret", clientPasswd) !=
    719                             DMResult.SYNCML_DM_SUCCESS) {
    720                         loge("CreateLeaf '" + dmClientNodePath + "/AAuthSecret' Error");
    721                         return false;
    722                     }
    723                     hasWriteClientPW = true;
    724                 }
    725             } else  {
    726                 logd("Using default ClientPW from dmAccounts: " + ai.clientPW);
    727             }
    728         } catch (Exception e) {
    729             loge("Exception in writeAccount2Dmt->getClientPW", e);
    730         }
    731 
    732         if (!hasWriteClientPW && NativeDM.createLeaf(dmClientNodePath + "/AAuthSecret", ai.clientPW)
    733                     != DMResult.SYNCML_DM_SUCCESS) {
    734             loge("createLeaf '" + dmClientNodePath + "/AAuthSecret' Error");
    735             return false;
    736         }
    737 
    738         String clientNonce = ai.clientNonce;
    739         if (NativeDM.createLeaf(dmClientNodePath + "/AAuthData", clientNonce)
    740                 != DMResult.SYNCML_DM_SUCCESS) {
    741             loge("createLeaf '" + dmClientNodePath + "/AAuthData' Error");
    742             return false;
    743         }
    744 
    745         logd("leave writeAccount2Dmt: success");
    746         return true;
    747     }
    748 
    749     private InputStream getDMAccXmlInput() {
    750         try {
    751             File file = new File("/system/etc/", "dmAccounts.xml");
    752             if (file.exists()) {
    753                 InputStream in = new BufferedInputStream(new FileInputStream(file));
    754                 logd("Load config from /system/etc/dmAccounts.xml");
    755                 return in;
    756             } else {
    757                 return null;
    758             }
    759         } catch (IOException e) {
    760             loge("IOException in getDMAccXmlInput", e);
    761             return null;
    762         }
    763     }
    764 
    765     private String getRealString(String ins) {
    766         if (ins != null && !ins.isEmpty() && ins.charAt(0) == '$') {
    767             SharedPreferences prefs = mContext.getSharedPreferences("dmconfig", 0);
    768             String key = ins.substring(1);
    769             if (prefs.contains(key)) {
    770                 return prefs.getString(key, "unknown");
    771             }
    772         }
    773         return ins;
    774     }
    775 
    776     private void unbind() {
    777         if (isBoundTo != null) {
    778             logd("Unbinding from " + isBoundTo);
    779             mContext.unbindService(mConnection);
    780             isBoundTo = null;
    781             synchronized (mLock) {
    782                 mPluginConnection = null;
    783             }
    784         }
    785     }
    786 
    787     private static byte[] hexStringToBytes(String s) {
    788         byte[] ret;
    789 
    790         if (s == null) return null;
    791 
    792         int sz = s.length();
    793 
    794         ret = new byte[sz/2];
    795 
    796         for (int i=0 ; i <sz ; i+=2) {
    797             ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4)
    798                     | hexCharToInt(s.charAt(i+1)));
    799         }
    800 
    801         return ret;
    802     }
    803 
    804     private static int hexCharToInt(char c) {
    805         if (c >= '0' && c <= '9') return (c - '0');
    806         if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
    807         if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
    808 
    809         throw new RuntimeException ("invalid hex char '" + c + "'");
    810     }
    811 
    812 //    private static void testSprintHashGenerator() {
    813 //        String equip = "A000001A2B3C4F";
    814 //        String server = "sprint";
    815 //        String secret = "foobar";
    816 //
    817 //        logd("XXXXX B64(MD5(\"foobar\") = " + sprintHashGenerator("foobar"));
    818 //        logd("XXXXX f(equip,server,secret) = " + sprintHashGenerator(equip + server + secret));
    819 //        logd("XXXXX f(server,equip,secret) = " + sprintHashGenerator(server + equip + secret));
    820 //    }
    821 
    822     private static void logd(String msg) {
    823         Log.d(TAG, msg);
    824     }
    825 
    826     private static void loge(String msg) {
    827         Log.e(TAG, msg);
    828     }
    829 
    830     private static void loge(String msg, Throwable tr) {
    831         Log.d(TAG, msg, tr);
    832     }
    833 }
    834