<facet type="android-gradle" name="Android-Gradle">\r
<configuration>\r
<option name="GRADLE_PROJECT_PATH" value=":app" />\r
- <option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.5.0" />\r
- <option name="LAST_KNOWN_AGP_VERSION" value="3.5.0" />\r
+ <option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.5.3" />\r
+ <option name="LAST_KNOWN_AGP_VERSION" value="3.5.3" />\r
</configuration>\r
</facet>\r
<facet type="android" name="Android">\r
<orderEntry type="library" name="Gradle: com.android.support:support-compat:25.1.0@aar" level="project" />\r
<orderEntry type="library" name="Gradle: com.kymjs.rxvolley:rxvolley:1.1.3@aar" level="project" />\r
<orderEntry type="library" name="Gradle: io.reactivex:rxandroid:1.1.0@aar" level="project" />\r
+ <orderEntry type="module" module-name="dNSCache" />\r
+ <orderEntry type="module" module-name="dNSCache" />\r
+ <orderEntry type="module" module-name="dNSCache" />\r
+ <orderEntry type="module" module-name="dNSCache" />\r
+ <orderEntry type="module" module-name="dNSCache" />\r
+ <orderEntry type="module" module-name="dNSCache" />\r
</component>\r
</module>
\ No newline at end of file
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
+
signingConfigs {
key {
storeFile file("EQC_G5.jks")
// }
}
dependencies {
- compile fileTree(include: ['*.jar'], dir: 'libs')
+ compile fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.1.0'
compile 'com.github.ChestnutPlus:TestModules:v1.0.16'
testCompile 'junit:junit:4.12'
+ implementation project(path: ':dNSCache')
}
def getVersionCode() {
def releaseTime() {
- return new Date().format("yyyyMMddHHmm", TimeZone.getTimeZone("GMT+08:00"))
+ return new Date().format("yyMMddHHmm", TimeZone.getTimeZone("GMT+08:00"))
}
\ No newline at end of file
import android.text.TextUtils;\r
\r
import com.enqualcomm.support.bean.ICLocation;\r
+import com.enqualcomm.support.bean.Runtime;\r
import com.enqualcomm.support.utils.SharPreferenceUtil;\r
\r
import org.json.JSONException;\r
}\r
\r
final static String KeyProtocolServerIP="ProtocolServerIP";\r
+ final static String KeyProtocolServerHOST="ProtocolServerHOST";\r
final static String KeyProtocolServerPort="ProtoclServerPort";;\r
final static String KeyFotaServerIP="FotaServerIP";\r
final static String KeyFotaServerPort="FotaServerPort";\r
\r
final static String KeyContactsList="ContactsList";\r
final static String KeySOSNumbersList="SOSNumbersList";\r
+ final static String KeyIMEI="IMEI";\r
\r
-\r
+ final static String KeyHeartBeatCycle="ServerHeartBeatCycle";\r
\r
public static void setAlarmCycle(Context context, int cycle){\r
SharPreferenceUtil.setPrefInt(context,KeyAlarmCycle,cycle);\r
return SharPreferenceUtil.getPrefString(context,KeyProtocolServerIP,"118.178.155.223");\r
}\r
\r
+ public static void loadModCycleSettings(Runtime runtime){\r
+ runtime.setPpgTestCycle(Config.getPPGTestCycle(runtime.getContextProxy().context));\r
+ runtime.getLocationInstance().setLocation_cycle(Config.getLocationCycle(runtime.getContextProxy().context));\r
+ runtime.getLocationInstance().setWorkingMod(Config.getLocationMode(runtime.getContextProxy().context));\r
+ }\r
+\r
+ public static void loadHearBeatSetting(Runtime runtime){\r
+ runtime.setHeartBeatCycle(Config.getHeartBeatCycle(runtime.getContextProxy().context));\r
+ }\r
+ public static void loadServerSettings(Runtime runtime){\r
+ runtime.setHostAndPort(Config.getProtocolServerHost(runtime.getContextProxy().context),Config.getProtocolServerPort(runtime.getContextProxy().context));\r
+ }\r
+\r
+ public static void setIMEI(Context context, String imei){\r
+ SharPreferenceUtil.setPrefString(context,KeyIMEI,imei);\r
+ }\r
+\r
+ public static String getIMEI(Context context){\r
+ return SharPreferenceUtil.getPrefString(context,KeyIMEI,"");\r
+ }\r
+\r
+ public static String getProtocolServerHost(Context context){\r
+ return SharPreferenceUtil.getPrefString(context,KeyProtocolServerHOST,"watch.jiai.pro");\r
+ }\r
+\r
+ public static void setProtocolServerHost(Context context,String host){\r
+ SharPreferenceUtil.setPrefString(context,KeyProtocolServerHOST,host);\r
+ }\r
public static int getProtocolServerPort(Context context){\r
return SharPreferenceUtil.getPrefInt(context,KeyProtocolServerPort,8090);\r
}\r
return SharPreferenceUtil.getPrefInt(context,KeyPpgTestCycle,30);\r
}\r
\r
+\r
+ public static int getHeartBeatCycle(Context context){\r
+ return SharPreferenceUtil.getPrefInt(context,KeyHeartBeatCycle,6);\r
+ }\r
+\r
+ public static void setHeartBeatCycle(Context context,int cycle){\r
+ SharPreferenceUtil.setPrefInt(context,KeyHeartBeatCycle,cycle);\r
+ }\r
public static void setLocationCycle(Context context,int cycle){\r
SharPreferenceUtil.setPrefInt(context,KeyLocationCycle,cycle);\r
}\r
import android.net.Uri;\r
\r
public interface Constants {\r
+\r
+ public static final String ACTION_BROADCAST_PPG = "com.enqualcomm.support.ACTION_BROADCAST_PPG";\r
public static final String ACTION_ADDTEST_CONTACTS = "com.enqualcomm.imessage.ACTION_ADDTEST_CONTACTS";\r
\r
public static final String ACTION_ALARM_ADD_DATAPOINTS = "com.enqualcomm.support.ADD_DATAPOINTS";\r
if (coreService == null)\r
return;\r
Logger.i("onConnectionClose++ retry to connect again!");\r
-// startConnectionRetryTimer();\r
- String ip=Util.parseHostGetIPAddress(coreService.runtime.getHost());\r
- if ( ip !=null && ! ip.equals(coreService.runtime.getSrvIP())){\r
- Logger.i("HostName "+coreService.runtime.getHost()+ " IP changed from "+coreService.runtime.getSrvIP()+" to "+ip);\r
- coreService.runtime.setSrvIP(ip);\r
- }\r
coreService.connectionServiceChain.processConnectionClose(coreService.connection, coreService.runtime);\r
}\r
\r
\r
\r
private AbstractConnectionService getConnectionServiceChain() {\r
- Initialize initialize = new Initialize();\r
+// Initialize initialize = new Initialize();\r
CheckSIM checkSIM = new CheckSIM();\r
this.mKeepAlive = new KeepAlive();\r
this.mDeliver = new Deliver(this.connection,this.runtime);\r
- initialize.setNext(checkSIM);\r
+// initialize.setNext(checkSIM);\r
checkSIM.setNext(this.mKeepAlive);\r
this.mKeepAlive.setNext(this.mDeliver);\r
- return initialize;\r
+ return checkSIM;\r
}\r
\r
private void getDBFile() {\r
return sendChatMessage;\r
}\r
\r
- private void loadSettings(){\r
- this.runtime.setPpgTestCycle(Config.getPPGTestCycle(this));\r
- this.runtime.getLocationInstance().setLocation_cycle(Config.getLocationCycle(this));\r
- this.runtime.getLocationInstance().setWorkingMod(Config.getLocationMode(this));\r
- }\r
-\r
private void loadStepCount() {\r
int i = SharPreferenceUtil.getPrefInt(this, KEY_STEP_COUNT, 0);\r
int j = SharPreferenceUtil.getPrefInt(this, KEY_SAVE_STEP_COUNT, 0);\r
this.runtime.setDBHelper(new DBHelper(getContentResolver(), this));\r
this.runtime.setContextProxy(new ContextProxy(this));\r
this.runtime.setLbsHelper(new LBSHelper(this,this.runtime.getContextProxy().getWifiManager(), this.runtime));\r
- this.runtime.setImeiAndCid(PhoneUtils.getIMEI(this),"");\r
+\r
+ if (Config.getIMEI(runtime.getContextProxy().context).isEmpty()){\r
+ //如果配置里有IMEI,优先选配置里的,没有则选择系统的\r
+ runtime.setImeiAndCid(PhoneUtils.getIMEI(this),"");\r
+ } else{\r
+ runtime.setImeiAndCid(Config.getIMEI(runtime.getContextProxy().context),"");\r
+ }\r
this.runtime.setHRS(new heartRateStatus());\r
this.runtime.setUseQueue(true);\r
+ this.runtime.initDnsUtil(this.getApplicationContext());\r
this.connectionServiceChain = getConnectionServiceChain();\r
this.invokeHandlerServiceChain = getInvokeHandlerServiceChain();\r
if (cmcm_call_eiot_into_powersave_mode() == 1) {\r
\r
//保证获取正确的计步数据及其他参数初始化\r
loadStepCount();\r
- loadSettings();\r
+ //初始化ServerHeartBeat Cycle\r
+ Config.loadHearBeatSetting(runtime);\r
+ //初始化PPG,LocationMod,LocationCycle\r
+ Config.loadModCycleSettings(runtime);\r
+ //初始化IP\r
+ Config.loadServerSettings(runtime);\r
+\r
\r
this.connectionServiceChain.processAttach(this.connection, this.runtime);\r
this.invokeHandlerServiceChain.processAttach(this.connection, this.runtime);\r
if (Config.LOG_TOFILE) FileOutputUtil.fileOutput(runtime.getCacheDir(), "alarmCycle", "设置闹钟服务 alarmCycle");\r
this.locationClient = new LocationClient(this.connection, this.runtime);\r
this.connection.open();\r
- this.connection.connect(this.runtime.getSrvIP(), this.runtime.getPort());\r
- this.locationClient.start();\r
\r
//启动inner Service\r
startService(new Intent(this, InnerService.class));\r
\r
+ ReConnectToServer();\r
+ this.locationClient.start();\r
+\r
\r
//设置本service为前台运行,不被会被清理\r
Notification notification = new Notification();\r
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;\r
startForeground(GRAY_SERVICE_ID, notification);\r
\r
-\r
//注册接收 时间和tiimezone 变更消息\r
IntentFilter intentFilter = new IntentFilter();\r
// intentFilter.addAction("android.intent.action.TIME_SET");\r
\r
}else if(ACTION_SEND_EMEGENCY_LOCATION_STOP.equals(paramIntent.getAction())){\r
//stop Emegency location Stop\r
- loadSettings(); //回复之前的 工作模式即可\r
+ Config.loadModCycleSettings(runtime); //回复之前的 工作模式即可\r
}else if (ACTION_BATTERY_LOW_MSG.equals(paramIntent.getAction())){\r
\r
runtime.setAlarmType(false,runtime.getBatteryLow(),false,false);\r
public void setHeartAlarm(){\r
// int mod=runtime.getLocationInstance().getWorkingMod();\r
StringBuilder sb=new StringBuilder();\r
- int cycle=3;\r
-// switch(mod){\r
-// case EMERGNECY_MOD:\r
-// case REALTIME_MOD:\r
-// cycle=1;\r
-// break;\r
-// case NORMAL_MOD:\r
-// cycle=15;\r
-// break;\r
-// case LOWPOWER_MOD:\r
-// cycle=60;\r
-// break;\r
-// }\r
+ int cycle=runtime.getHeartBeatCycle();\r
+\r
+ //心跳指令默认设置为3分钟\r
AlarmHelper.setRealTimeAlarm(runtime.getContextProxy().context,cycle, HEART_ALARM);\r
sb.append(" setHeartAlarm "+HEART_ALARM+", cycle "+cycle);\r
\r
}\r
\r
public void startConnectionRetryTimer(){\r
- if (mTimer_retry_connect == null) {\r
- mTimer_retry_connect = new Timer();\r
- }\r
-\r
- //如果开始进行连接重试,证明网络断开的,那么KeepAlive也需要重连(心跳包)\r
-\r
- KeepAlive.isConnected=false;\r
- if (mTimer_retry_connect !=null){\r
- mTimer_retry_connect.schedule(new TimerTask() {\r
- @Override\r
- public void run() {\r
- do_timer_task();\r
- }\r
- },0,5000); //每5秒重试一次\r
+ //联网再重试连接服务器\r
+ if (SimSignalUtil.checkNet(runtime.getContextProxy().context) ) {\r
+ stopConnectionRetryTimer();\r
+ if (mTimer_retry_connect == null) {\r
+ mTimer_retry_connect = new Timer();\r
+ }\r
+ //如果开始进行连接重\r
+ // {\r
+ // 试,证明网络断开的,那么KeepAlive也需要重连(心跳包)\r
+\r
+ KeepAlive.isConnected = false;\r
+ if (mTimer_retry_connect != null) {\r
+ mTimer_retry_connect.schedule(new TimerTask() {\r
+ @Override\r
+ public void run() {\r
+ ReConnectToServer();\r
+ }\r
+ }, 0, 5000); //每5秒重试一次\r
+ }\r
}\r
}\r
\r
- public void do_timer_task(){\r
-\r
+ public void ReConnectToServer(){\r
\r
- this.connection.connect(this.runtime.getSrvIP(), this.runtime.getPort());\r
+ if (SimSignalUtil.checkNet(runtime.getContextProxy().context) ) {\r
+ String ip=runtime.getDnsUtil().getServerIP_ByDNSCache(runtime.getHost());\r
+ if (null != ip && !ip.equals(runtime.getSrvIP())) {\r
+ runtime.setSrvIP(ip);\r
+ }\r
+ this.connection.connect(this.runtime.getSrvIP(), this.runtime.getPort());\r
\r
- //里面如果连接成功 connectionOpen 会先发送 AP00 登录包 和发送AP03 心跳包 ,都成功则停止重试\r
- if (connection.isServerConnected() && KeepAlive.isConnected)\r
- {\r
- stopConnectionRetryTimer();\r
- }\r
+ //里面如果连接成功 connectionOpen 会先发送 AP00 登录包 和发送AP03 心跳包 ,都成功则停止重试\r
+ if (connection.isServerConnected() && KeepAlive.isConnected) {\r
+ stopConnectionRetryTimer();\r
+ }\r
+ }else{\r
+ //没有网络就不用重新尝试连接网络了。网络连接后再重新尝试联网\r
+ stopConnectionRetryTimer();\r
+ }\r
}\r
\r
public void stopConnectionRetryTimer(){\r
\r
}\r
\r
+ public void disconnect_server(){\r
+ this.connection.close();\r
+ }\r
+\r
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {\r
@Override\r
public void onReceive(Context context, Intent intent) {\r
\r
\r
import com.enqualcomm.support.BuildConfig;\r
+import com.sina.util.dnscache.DNSCache;\r
\r
import java.util.HashMap;\r
\r
import com.enqualcomm.support.bean.Runtime;\r
import com.enqualcomm.support.utils.DeviceInfoUtil;\r
import com.enqualcomm.support.utils.Logger;\r
+import com.enqualcomm.support.utils.ServiceUtil;\r
\r
import java.util.ArrayList;\r
import java.util.Iterator;\r
\r
+import chestnut.utils.PhoneUtils;\r
+\r
\r
public class ICSmsManager {\r
private static String mNumber;\r
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");\r
intentFilter.setPriority(2147483647);\r
this.mContext.registerReceiver(this.smsReceiver, intentFilter);\r
-\r
-\r
- //处理返回的发送状态\r
- String SENT_SMS_ACTION = "SENT_SMS_ACTION";\r
- Intent sentIntent = new Intent(SENT_SMS_ACTION);\r
- PendingIntent sentPI = PendingIntent.getBroadcast(mContext, 0, sentIntent,\r
- 0);\r
-// register the Broadcast Receivers\r
- mContext.registerReceiver(new BroadcastReceiver() {\r
- @Override\r
- public void onReceive(Context _context, Intent _intent) {\r
- switch (getResultCode()) {\r
- case Activity.RESULT_OK:\r
- Toast.makeText(mContext,\r
- "短信发送成功", Toast.LENGTH_SHORT)\r
- .show();\r
- break;\r
- case SmsManager.RESULT_ERROR_GENERIC_FAILURE:\r
- break;\r
- case SmsManager.RESULT_ERROR_RADIO_OFF:\r
- break;\r
- case SmsManager.RESULT_ERROR_NULL_PDU:\r
- break;\r
- }\r
- }\r
- }, new IntentFilter(SENT_SMS_ACTION));\r
-\r
-\r
- //处理返回的接收状态\r
- String DELIVERED_SMS_ACTION = "DELIVERED_SMS_ACTION";\r
-// create the deilverIntent parameter\r
- Intent deliverIntent = new Intent(DELIVERED_SMS_ACTION);\r
- PendingIntent deliverPI = PendingIntent.getBroadcast(mContext, 0,\r
- deliverIntent, 0);\r
- mContext.registerReceiver(new BroadcastReceiver() {\r
- @Override\r
- public void onReceive(Context _context, Intent _intent) {\r
- Toast.makeText(mContext,\r
- "收信人已经成功接收", Toast.LENGTH_SHORT)\r
- .show();\r
- }\r
- }, new IntentFilter(DELIVERED_SMS_ACTION));\r
-\r
-\r
}\r
\r
public void sendSMS(String phonenumber, String msg) {\r
\r
return true;\r
}\r
+\r
+ //1:短信设置服务器\r
+ //#ip#=198.11.183.28,5088#\r
+ //回复 ip set ok\r
+ //\r
+ //2:短信写IMEI\r
+ //#imei:108111804000475\r
+ //回复 imri write ok\r
+ //\r
+ //3: 短信增加APN\r
+ //#apn#=MCC,MNC,apn name,apn name,user name,password#\r
+ //回复 APN set ok\r
+ //\r
+ //4:远程查询软件版本和IMEI号码\r
+ //#status#\r
+ //回复\r
+ //IMEI: 353503535035350\r
+ //SW: L02_20200208_V1\r
public void handleSMS_CMD(String phonenumber, String sms){\r
if (isAdminNumber(phonenumber)) {\r
- if (sms.startsWith("GetDeviceInfo")) {\r
- sendSMS(phonenumber,DeviceInfoUtil.getDeviceInfo(runtime));\r
+ if (sms.startsWith("#deviceinfo#")) {\r
+ Logger.i("SMS "+sms+" reply "+DeviceInfoUtil.getShortDeviceInfo(runtime));\r
+ sendSMS(phonenumber,DeviceInfoUtil.getShortDeviceInfo(runtime));\r
+ }else if (sms.startsWith("#status#")) {\r
+ String reply="IMEI="+runtime.IMEI()+"\nSW:"+DeviceInfoUtil.getVersionCode(runtime.getContextProxy().context)+" "+DeviceInfoUtil.getSWVersionDisplayName();\r
+ Logger.i("SMS "+sms+" reply \n"+reply);\r
+ sendSMS(phonenumber,reply);\r
+ }else if (sms.startsWith("#imei:")) {\r
+ String imei=sms.substring(6);\r
+ Logger.i("SMS "+sms+" imei="+imei);\r
+ if (imei.length()==15 ) {\r
+ Config.setIMEI(runtime.getContextProxy().context, imei);\r
+ runtime.setImeiAndCid(imei, "");\r
+ sendSMS(phonenumber, "set IMEI " + imei + " sucess !");\r
+ CoreService.getInstance().disconnect_server();\r
+ CoreService.getInstance().ReConnectToServer();\r
+ }else if (imei.equals("reset")) {\r
+ Config.setIMEI(runtime.getContextProxy().context, "");\r
+ runtime.setImeiAndCid(PhoneUtils.getIMEI(runtime.getContextProxy().context), "");\r
+ sendSMS(phonenumber, "reset IMEI to " + PhoneUtils.getIMEI(runtime.getContextProxy().context) + " sucess !");\r
+ CoreService.getInstance().disconnect_server();\r
+ CoreService.getInstance().ReConnectToServer();\r
+ }else{\r
+ sendSMS(phonenumber, "set IMEI " + imei + " failed ! len!=15");\r
+ }\r
+ }else if (sms.startsWith("#ip#=") && sms.endsWith("#")) {\r
+ String tmp[]=sms.split("=");\r
+ String reply="";\r
+ Logger.i(sms+" len "+tmp.length);\r
+ if (tmp.length==2)\r
+ {\r
+ //分析 以 , 为分界的格式\r
+ String[] ipstr = tmp[1].split(",");\r
+ if (ipstr[0].equals("reset#")) {\r
+ Config.setProtocolServerHost(runtime.getContextProxy().context, Runtime.DefaultHost);\r
+ Config.setProtocolServerAddr(runtime.getContextProxy().context, "", Runtime.DefaultPort);\r
+ reply = "reset ServerIP to " + Runtime.DefaultHost + ":" + Runtime.DefaultPort + " success! ";\r
+ Config.loadServerSettings(runtime);\r
+ CoreService.getInstance().disconnect_server();\r
+ CoreService.getInstance().ReConnectToServer();\r
+ }else if (ipstr.length==2){\r
+ String ip=ipstr[0];\r
+ int port=Integer.valueOf(ipstr[1].replace("#",""));\r
+ Config.setProtocolServerHost(runtime.getContextProxy().context,ip);\r
+ Config.setProtocolServerAddr(runtime.getContextProxy().context,"",port);\r
+ reply = sms+" success! ";\r
+ Config.loadServerSettings(runtime);\r
+ CoreService.getInstance().disconnect_server();\r
+ CoreService.getInstance().ReConnectToServer();\r
+ }else{\r
+ //分析以 : 为分界的格式\r
+ ipstr = tmp[1].split(":");\r
+\r
+ if (ipstr[0].equals("reset#")) {\r
+ Config.setProtocolServerHost(runtime.getContextProxy().context, Runtime.DefaultHost);\r
+ Config.setProtocolServerAddr(runtime.getContextProxy().context, "", Runtime.DefaultPort);\r
+ reply = "reset ServerIP to " + Runtime.DefaultHost + ":" + Runtime.DefaultPort + " success! ";\r
+ Config.loadServerSettings(runtime);\r
+ CoreService.getInstance().disconnect_server();\r
+ CoreService.getInstance().ReConnectToServer();\r
+ } else if (ipstr.length == 2) {\r
+ String ip = ipstr[0];\r
+ int port = Integer.valueOf(ipstr[1].replace("#", ""));\r
+ Config.setProtocolServerHost(runtime.getContextProxy().context, ip);\r
+ Config.setProtocolServerAddr(runtime.getContextProxy().context, "", port);\r
+ reply = sms + " success! ";\r
+ Config.loadServerSettings(runtime);\r
+ CoreService.getInstance().disconnect_server();\r
+ CoreService.getInstance().ReConnectToServer();\r
+ } else {\r
+ reply = sms + " falied! ";\r
+ }\r
+ }\r
+ }else{\r
+ reply = sms + " falied! ";\r
+ }\r
+ sendSMS(phonenumber, reply);\r
}\r
-\r
}\r
}\r
\r
import android.widget.ToggleButton;
import com.enqualcomm.support.R;
+import com.enqualcomm.support.utils.DeviceInfoUtil;
import com.ic.jni.ICJniUtils;
import com.enqualcomm.support.CoreService;
import com.enqualcomm.support.utils.Logger;
TextView tv_version=(TextView)findViewById(R.id.textViewVersion);
- tv_version.setText( getVersionName(this));
+ tv_version.setText(DeviceInfoUtil.getVersionName(this));
}
}
- /**
- * 得到当前应用版本名称的方法
- *
- * @param context
- * :上下文
- * @throws Exception
- */
- public static String getVersionName(Context context) {
- // 获取packagemanager的实例
- PackageManager packageManager = context.getPackageManager();
- // getPackageName()是你当前类的包名
- PackageInfo packInfo = null;
- String version="V001";
- try {
- packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
- version = packInfo.versionName;
- } catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
- }
- return version;
- }
-
-
-
private View.OnClickListener clickListener = new View.OnClickListener() {
@Override
--- /dev/null
+package com.enqualcomm.support.bean;
+
+import com.sina.util.dnscache.DomainInfo;
+
+public class DNSTaskModel {
+
+
+ //---------------任务---------------
+
+ public long taskID = 0 ;
+
+ public int status = 0 ; //状态:(完成\错误)
+
+ public long taskStartTime = 0 ; //开始时间:
+
+ public long taskStopTime = 0 ;//结束时间:
+
+ public long taskExpendTime = 0 ;//消耗时间:
+
+ public String url = "" ; //任务传入URL
+
+ //-------------HTTPDNS库-------------
+
+ public String httpDnsResult = "" ; //返回结果:
+
+ public long httpDnsExpendTime = 0 ; //响应耗时:
+
+
+
+ //------------IP+HOST请求------------
+
+ public String hostUrl = "" ; //访问URL:
+
+ public String hostIp = "" ; //访问服务器IP:
+
+ public int hostCode = 0 ; //服务器返回CODE:
+
+ public byte[] hostInputStreamResult = null ;
+
+ public String hostResult = "" ; //服务器返回结果:(可点击看详情)
+
+ public long hostExpendTime = 0 ; //请求耗时:
+
+
+
+ //------------域名直接请求------------
+
+ public String domainUrl = "" ; //访问URL:
+
+ public String domainIp = "" ; //访问服务器IP:
+
+ public int domainCode = 0 ; //服务器返回CODE:
+
+ public byte[] domainInputStreamResult = null ;
+
+ public String domainResult = "" ; //服务器返回结果:(可点击看详情)
+
+ public long domainExpendTime = 0 ; //请求耗时:
+
+
+
+ //------------设备环境信息------------
+
+ public String netType = ""; //网络环境(WIFI\2G\3G\4G\未知)
+
+ public String spName = "" ; //运营商:(WIFI名字\手机卡运营商\未知)
+
+
+
+
+ //------------HttpDns返回相关信息------------
+
+ public DomainInfo[] domainInfo = null ;
+
+
+}
package com.enqualcomm.support.bean;\r
\r
\r
+import android.content.Context;\r
+\r
import com.enqualcomm.support.adapter.LBSHelper;\r
import com.enqualcomm.support.utils.ContextProxy;\r
import com.enqualcomm.support.utils.DBHelper;\r
+import com.enqualcomm.support.utils.DnsUtil;\r
import com.enqualcomm.support.utils.Logger;\r
\r
import java.io.File;\r
private String haveBuy;\r
\r
private String haveTry;\r
- \r
+\r
+ public static final String DefaultHost="watch.jiai.pro";\r
+ public static final int DefaultPort=8090;\r
+\r
private String host = "watch.jiai.pro"; //118.178.155.223\r
\r
private String srvIP = "118.178.155.223";//"39.98.94.164";\r
\r
private int port = 8090;//20048;//8888;//8090;\r
\r
+\r
private boolean testServerProp=false;\r
\r
private String imei_cid = "";\r
private boolean shutdown;\r
\r
\r
+\r
+ private DnsUtil dnsUtil=null;\r
+\r
+ public void initDnsUtil(Context context){\r
+ if (dnsUtil==null)\r
+ dnsUtil=new DnsUtil(5,context);\r
+ }\r
+ public DnsUtil getDnsUtil(){\r
+ return dnsUtil;\r
+ }\r
private int lastStepCount=0;\r
private long timestamp;\r
\r
public int totalStepCount;\r
\r
+ private int heartbeatCycle;\r
+\r
\r
+ public int getHeartBeatCycle()\r
+ {\r
+ return heartbeatCycle;\r
+ }\r
+ public void setHeartBeatCycle(int cycle){\r
+ heartbeatCycle=cycle;\r
+ }\r
public heartRateStatus getHRS(){\r
return HRS;\r
}\r
\r
public void setHaveBatteryChange(boolean paramBoolean) { this.haveBatteryChange = paramBoolean; }\r
\r
+ public void setHost(String _host){\r
+ host=_host;\r
+ }\r
public void setHostAndPort(String paramString, int paramInt) {\r
this.host = paramString;\r
this.port = paramInt;\r
}\r
- \r
+ public void setPort(int _port){\r
+ port=_port;\r
+ }\r
public void setImeiAndCid(String paramString1, String paramString2) {\r
this.imei = paramString1;\r
this.cid = paramString2;\r
import java.util.Timer;\r
import java.util.TimerTask;\r
\r
+import static com.enqualcomm.support.Constants.ACTION_BROADCAST_PPG;\r
import static com.enqualcomm.support.Constants.ACTION_HEATR_RATE_START;\r
import static com.enqualcomm.support.Constants.MSG_WHAT_PPG;\r
import static com.enqualcomm.support.Constants.key_bph;\r
case 100: {\r
//只有检测PPG成功,且网络连接中才发送数据\r
if (runtime.getHRS().getHeartrateWorkingStat() == heartRateStatus.HEARTRATE_WORKINGSTAT.HEARTRATE_TEST_SUCCESS) {\r
- runtime.getHRS().setLastTestTime(TimeUtil.getLocalTime());\r
+ runtime.getHRS().setLastTestTime(TimeUtil.getSystemTime3());\r
String PPGDATA = protocolAPIHelper.APHT(runtime);\r
+ sendBroadcastPPGResult();\r
+ //因为协议中没有时间变量,所以只能实时传输,如果恰巧没有网络也只能丢弃,有时间变量的话,可以考虑通过deliver的buffer来进行缓存发送\r
if (connection.isServerConnected()) {\r
connection.send(protocolAPIHelper.genStringMessage("APHT", PPGDATA));\r
Logger.i("Send PPG " + PPGDATA);\r
}\r
};\r
\r
+ private void sendBroadcastPPGResult(){\r
+ Intent intent=new Intent(ACTION_BROADCAST_PPG);\r
+ intent.putExtra("ppg",runtime.getHRS().getPPG());\r
+ intent.putExtra("bph",runtime.getHRS().getBPH());\r
+ intent.putExtra("bpl",runtime.getHRS().getBPL());\r
+ intent.putExtra("time",runtime.getHRS().getTestTime());\r
+ runtime.getContextProxy().context.sendBroadcast(intent);\r
+ }\r
public void regReceiver(){\r
//注册“网络变化”的广播接收器\r
IntentFilter intentFilter = new IntentFilter();\r
if (this.initOK)\r
return false; \r
\r
- if (paramRuntime.IMSI() != null && !paramRuntime.IMSI().startsWith("46001"))\r
- paramRuntime.IMSI().startsWith("46006");\r
+// if (paramRuntime.IMSI() != null && !paramRuntime.IMSI().startsWith("46001"))\r
+// paramRuntime.IMSI().startsWith("46006");\r
\r
//区分联通、移动、电信 号码的策略\r
//1 通过IMSI号前5位判断\r
//ICCID前六位运营商代码:中国移动的为:898600;898602 ,中国联通的为:898601,中国电信898603\r
\r
\r
- int i = SharPreferenceUtil.getPrefInt((paramRuntime.getContextProxy()).context, "location_mode", 2);\r
- int j = SharPreferenceUtil.getPrefInt((paramRuntime.getContextProxy()).context, "location_cycle", 3);\r
- StringBuilder stringBuilder = new StringBuilder();\r
- stringBuilder.append(i);\r
- stringBuilder.append("@");\r
- stringBuilder.append(j);\r
- Config.work_mode = stringBuilder.toString();\r
- stringBuilder = new StringBuilder();\r
- stringBuilder.append(" antioff =");\r
- stringBuilder.append(Config.antioff);\r
- Logger.i(stringBuilder.toString());\r
- Config.sw_release_no = DeviceInfoUtil.getCustomId();\r
+ Config.loadServerSettings(paramRuntime);\r
+\r
//发送登录包\r
paramConnection.send(new StringMessage(protocolAPIHelper.AP00(paramRuntime)));\r
-// paramConnection.send(new StringMessage(protocolAPIHelper.AP00(paramRuntime)));\r
-// paramConnection.send(new StringMessage(protocolAPIHelper.AP00(paramRuntime)));\r
+\r
+\r
return false;\r
}\r
- \r
+\r
+\r
public void onDetach(Connection paramConnection, Runtime paramRuntime) { this.initOK = false; }\r
\r
\r
this.reConnectionNumber++;\r
this.firstReConnected = false;\r
} \r
- if (paramRuntime.getLockSimInfo()) {\r
- paramConnection.disconnect();\r
- return;\r
- } \r
- paramConnection.connect(paramRuntime.getSrvIP(), paramRuntime.getPort());\r
+// if (paramRuntime.getLockSimInfo()) {\r
+// paramConnection.disconnect();\r
+// return;\r
+// }\r
+ CoreService.getInstance().ReConnectToServer();\r
} \r
}\r
\r
if (this.first) {\r
this.first = false;\r
return;\r
- } \r
- connection.connect(runtime.getSrvIP(), runtime.getPort());\r
+ }\r
+ CoreService.getInstance().ReConnectToServer();\r
} \r
}\r
});\r
stringBuilder.append(",set KeepAlive isConnected = true");\r
Logger.i(stringBuilder.toString());\r
// if (!connectionError) {\r
- connectionError = false;\r
-// connection.send(protocolAPIHelper.genStringMessage("AP00",protocolAPIHelper.AP00(paramRuntime)));\r
+ connectionError = false;\r
+\r
+ //发送登录包\r
+ connection.send(protocolAPIHelper.genStringMessage("AP00",protocolAPIHelper.AP00(paramRuntime)));\r
+ //发送心跳包\r
connection.send(protocolAPIHelper.genStringMessage("heart",protocolAPIHelper.AP03(paramRuntime)));\r
-// connection.send(protocolAPIHelper.genStringMessage("heart",protocolAPIHelper.AP03(paramRuntime)));\r
-// connection.send(protocolAPIHelper.genStringMessage("heart",protocolAPIHelper.AP03(paramRuntime)));\r
-// if (Deliver.haveSendH42) {\r
-// ServiceUtil.offerQueue(new StringMessage(protocolAPIHelper.AP03(paramRuntime)));\r
-// Deliver.haveSendH42 = false;\r
-// }\r
-// }\r
\r
isConnected = true;\r
this.firstReConnected = true;\r
\r
import android.app.ActivityManager;\r
import android.content.Context;\r
+import android.content.pm.PackageInfo;\r
+import android.content.pm.PackageManager;\r
import android.database.Cursor;\r
import android.net.Uri;\r
import android.os.Build;\r
str2 = "0"; \r
return str2;\r
}\r
- \r
+\r
+ /**\r
+ * 得到当前应用版本名称的方法\r
+ *\r
+ * @param context\r
+ * :上下文\r
+ * @throws Exception\r
+ */\r
+ public static String getVersionName(Context context) {\r
+ // 获取packagemanager的实例\r
+ PackageManager packageManager = context.getPackageManager();\r
+ // getPackageName()是你当前类的包名\r
+ try {\r
+ PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);\r
+ String version = packInfo.versionName;\r
+ return version;\r
+\r
+ }catch (Exception e){\r
+ e.printStackTrace();\r
+ }\r
+ return "";\r
+ }\r
+\r
+ public static String getVersionCode(Context context) {\r
+ // 获取packagemanager的实例\r
+ PackageManager packageManager = context.getPackageManager();\r
+ // getPackageName()是你当前类的包名\r
+ try {\r
+ PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);\r
+ String version = "V"+packInfo.versionCode;\r
+ return version;\r
+\r
+ }catch (Exception e){\r
+ e.printStackTrace();\r
+ }\r
+ return "";\r
+ }\r
public static int getCustomId() {\r
int i = -1;\r
try {\r
\r
public static String getDeviceInfo(Runtime runtime){\r
\r
- int ppg= ICJniUtils.getPPG();\r
SimSignalUtil sim=SimSignalUtil.getInstance(runtime.getContextProxy().context);\r
return new StringBuilder()\r
- .append(TimeUtil.getSystemTime3())\r
- .append(SimSignalUtil.hasSimCard(runtime.getContextProxy().context)?" SIM ":" NoSIM ")\r
+ .append(TimeUtil.getLocalTime2()).append(" ").append(DeviceInfoUtil.getVersionCode(runtime.getContextProxy().context))\r
+ .append(SimSignalUtil.hasSimCard(runtime.getContextProxy().context)?"\n SIM ":" NoSIM ")\r
.append(sim.getNetworkType()==SimSignalUtil.IS_2G?"2G":(sim.getNetworkType()==SimSignalUtil.IS_3G)?"3G":(sim.getNetworkType()==SimSignalUtil.IS_4G?"4G":"unknown"))\r
- .append(" [").append(runtime.getSignalStrength()+100).append(",Mini:").append(SimSignalUtil.getMinSignalStrength(sim.getNetworkType())).append("]")\r
- .append("\n KeepAlive ").append(KeepAlive.isConnected)\r
+ .append(" [").append(runtime.getSignalStrength()).append(",Mini:").append(SimSignalUtil.getMinSignalStrength(sim.getNetworkType())).append("]")\r
+ .append("\n KeepAlive ").append(KeepAlive.isConnected).append(" , HBcycle ").append(runtime.getHeartBeatCycle())\r
.append("\n ServerConnected is ").append(runtime.isServerProtocolConnected())\r
.append(" \n Bat ").append(runtime.getBattery())\r
.append(" StepCount ").append(runtime.getTotalStepCount())\r
.append(" \n LocationType ").append(runtime.getLocationInstance().getLocationType())\r
.append(" at ").append(runtime.getLocationInstance().getLocationTime())\r
.append(" \n PPGTestCycle ").append(runtime.getPpgTestCycle())\r
- .append("\n PPGStarted ").append(ICJniUtils.isPPGStarted())\r
- .append(",weared ").append(ICJniUtils.isWeared())\r
- .append(",ppg ").append(ppg)\r
- .append(",bph ").append(ICJniUtils.getHighBloodPressure())\r
- .append(",bpl ").append(ICJniUtils.getLowBloodPressure())\r
+ .append("\n LastPPG ").append(runtime.getHRS().getPPG())\r
+ .append(",bph ").append(runtime.getHRS().getBPH())\r
+ .append(",bpl ").append(runtime.getHRS().getBPL())\r
+ .append(" at ").append(runtime.getHRS().getTestTime())\r
+ .toString();\r
+ }\r
+ public static String getShortDeviceInfo(Runtime runtime){\r
+\r
+ SimSignalUtil sim=SimSignalUtil.getInstance(runtime.getContextProxy().context);\r
+ return new StringBuilder()\r
+ .append(DeviceInfoUtil.getVersionCode(runtime.getContextProxy().context))\r
+ .append(SimSignalUtil.hasSimCard(runtime.getContextProxy().context)?" ":" NoSIM ")\r
+ .append(sim.getNetworkType()==SimSignalUtil.IS_2G?"2G":(sim.getNetworkType()==SimSignalUtil.IS_3G)?"3G":(sim.getNetworkType()==SimSignalUtil.IS_4G?"4G":"unknown"))\r
+ .append("[").append(runtime.getSignalStrength()).append("]")\r
+ .append("\nHeartbeat[").append(runtime.getSrvIP()).append(":").append(runtime.getPort()).append(",").append(runtime.isServerProtocolConnected()).append(",").append(runtime.getHeartBeatCycle())\r
+ .append("]\nBat").append(runtime.getBattery())\r
+ .append(",Step").append(runtime.getTotalStepCount())\r
+ .append( "\nLocation[M").append(runtime.getLocationInstance().getWorkingMod())\r
+ .append(",C").append(runtime.getLocationInstance().getLocation_cycle())\r
+ .append(",T").append(runtime.getLocationInstance().getLocationType())\r
+ .append(",").append(runtime.getLocationInstance().getLocationTime())\r
+ .append("]\nPPG[C").append(runtime.getPpgTestCycle())\r
+ .append(",P").append(runtime.getHRS().getPPG())\r
+ .append(",H").append(runtime.getHRS().getBPH())\r
+ .append(",L").append(runtime.getHRS().getBPL())\r
+ .append(",").append(runtime.getHRS().getTestTime()).append("]")\r
.toString();\r
}\r
\r
--- /dev/null
+package com.enqualcomm.support.utils;\r
+\r
+\r
+import android.content.Context;\r
+import android.os.Handler;\r
+import android.os.Message;\r
+\r
+import com.enqualcomm.support.Config;\r
+import com.enqualcomm.support.bean.DNSTaskModel;\r
+import com.sina.util.dnscache.DNSCache;\r
+import com.sina.util.dnscache.DomainInfo;\r
+import com.sina.util.dnscache.Tools;\r
+import com.sina.util.dnscache.net.ApacheHttpClientNetworkRequests;\r
+import com.sina.util.dnscache.net.INetworkRequests;\r
+import com.sina.util.dnscache.net.networktype.NetworkManager;\r
+\r
+import java.util.HashMap;\r
+import java.util.concurrent.Callable;\r
+import java.util.concurrent.ExecutorService;\r
+import java.util.concurrent.Executors;\r
+\r
+import static com.sina.util.dnscache.AppConfigUtil.getApplicationContext;\r
+\r
+public class DnsUtil {\r
+\r
+ public long ID_NUMBER = 0 ;\r
+\r
+\r
+ public final ExecutorService fixedThreadPool;\r
+\r
+ public DnsUtil(int size, Context context){\r
+\r
+ DNSCache.Init(context);\r
+ DNSCache.getInstance().preLoadDomains(new String[]{Config.getProtocolServerHost(context)});\r
+\r
+ fixedThreadPool = Executors.newFixedThreadPool(size);\r
+ }\r
+\r
+ public void runTask(final DNSTaskModel model, final Callable<DNSTaskModel> call){\r
+\r
+ fixedThreadPool.execute( new Runnable() {\r
+ @Override\r
+ public void run() {\r
+\r
+ try {\r
+\r
+ Thread.currentThread().setName("Task Pool");\r
+\r
+ Logger.log("TAG", "任务开始");\r
+\r
+ model.taskStartTime = System.currentTimeMillis();\r
+ model.taskID = ++ID_NUMBER;\r
+\r
+\r
+ model.domainUrl = model.url ;\r
+ model.domainIp = java.net.InetAddress.getByName(Tools.getHostName(model.domainUrl)).getHostAddress();\r
+ INetworkRequests domainNetRequests = new ApacheHttpClientNetworkRequests() ;\r
+ HashMap<String, String> lmapKey = null ;\r
+ lmapKey = new HashMap<String, String>();\r
+ lmapKey.put("Connection", "keep-alive");\r
+\r
+// long startDomainRequests = System.currentTimeMillis();\r
+// model.domainInputStreamResult = domainNetRequests.requestsByteArr(model.domainUrl,lmapKey) ;\r
+// model.domainResult = byteToString(model.domainInputStreamResult) ;\r
+// model.domainExpendTime = System.currentTimeMillis() - startDomainRequests ;\r
+// model.domainCode = model.domainResult == null ? 500 : 200 ;\r
+\r
+ try {\r
+ long startHttpDns = System.currentTimeMillis();\r
+ DomainInfo[] infoList = DNSCache.getInstance().getDomainServerIp(model.url) ;\r
+// model.httpDnsExpendTime = System.currentTimeMillis() - startHttpDns ;\r
+ if( infoList == null || infoList.length == 0 ){\r
+ model.httpDnsResult = "null" ;\r
+ }else{\r
+ model.domainInfo = infoList;\r
+// for( DomainInfo info : infoList ) model.httpDnsResult += Tools.getHostName(info.url) + "、" ;\r
+//\r
+// HashMap<String, String> hmapKey = null ;\r
+// hmapKey = new HashMap<String, String>();\r
+// hmapKey.put("host", infoList[0].host);\r
+\r
+\r
+ model.hostUrl = infoList[0].url ;\r
+ model.hostIp = Tools.getHostName(infoList[0].url) ;\r
+// INetworkRequests hostNetRequests = new ApacheHttpClientNetworkRequests() ;\r
+// long startHostRequests = System.currentTimeMillis();\r
+//\r
+// model.hostInputStreamResult = hostNetRequests.requestsByteArr(infoList[0].url, hmapKey) ;\r
+// model.hostResult = byteToString(model.hostInputStreamResult) ;\r
+//\r
+// model.hostExpendTime = System.currentTimeMillis() - startHostRequests ;\r
+// model.hostCode = model.hostResult == null ? 0 : 200 ;\r
+\r
+ }\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+\r
+ try {\r
+\r
+ // 反馈任务\r
+// model.domainInfo[0].code = String.valueOf(model.domainCode) ;\r
+// model.domainInfo[0].data = model.domainResult ;\r
+// model.domainInfo[0].startTime = String.valueOf(startDomainRequests) ;\r
+//// DNSCache.getInstance().setDomainServerIpInfo( model.domainInfo[0] );\r
+//\r
+// model.netType = NetworkManager.getInstance().NETWORK_TYPE_STR ;\r
+// model.spName = NetworkManager.getInstance().SP_TYPE_STR ;\r
+//\r
+// model.status = 1 ;\r
+// model.taskStopTime = System.currentTimeMillis();\r
+// model.taskExpendTime = model.taskStopTime - model.taskStartTime ;\r
+\r
+ Logger.log("TAG", "任务结束");\r
+ call.call();\r
+\r
+ } catch (Exception e) {\r
+ // TODO: handle exception\r
+ e.printStackTrace();\r
+ }\r
+\r
+\r
+ } catch (Exception e) {\r
+ Logger.log("TAG", "任务失败");\r
+ e.printStackTrace();\r
+ }\r
+\r
+// try {\r
+// Thread.sleep( (int) (Math.random() * 1000) );\r
+// } catch (InterruptedException e) {\r
+// e.printStackTrace();\r
+// }\r
+ }\r
+ } );\r
+ }\r
+\r
+\r
+ private String byteToString(byte[] data){\r
+ return new String(data) ;\r
+ }\r
+\r
+ public void reset(){\r
+ ID_NUMBER = 0;\r
+ }\r
+\r
+ public boolean isShutdown() {\r
+ return fixedThreadPool.isShutdown();\r
+ }\r
+\r
+ public void shutdownNow() {\r
+ fixedThreadPool.shutdownNow();\r
+ }\r
+\r
+ public void shutdown() {\r
+ fixedThreadPool.shutdown();\r
+ }\r
+\r
+\r
+\r
+\r
+ // ///////////////////////////////////////////////////////////////\r
+\r
+ int finishTag = 0;\r
+\r
+ public String getServerIP_ByDNSCache(String host) {\r
+\r
+\r
+ DNSTaskModel temp=new DNSTaskModel();\r
+ if (host.toLowerCase().startsWith("http://")) {\r
+ temp.url = host;\r
+ }else{\r
+ temp.url = "http://"+host;\r
+ }\r
+ temp.hostIp=null;\r
+ temp.domainIp=null;\r
+\r
+ Callable<DNSTaskModel> call = new Callable<DNSTaskModel>() {\r
+ @Override\r
+ public DNSTaskModel call() throws Exception {\r
+ Logger.i("get "+temp.url+" "+temp.domainIp+" , DnsCacheIP "+temp.hostIp);\r
+\r
+ return temp;\r
+ }\r
+ };\r
+ runTask(temp, call);\r
+ String ip;\r
+// Logger.i(temp.toString());\r
+ if (temp.domainIp!=null){\r
+ if (temp.hostIp!=null){\r
+ ip=temp.hostIp.toString();\r
+ }else{\r
+ ip=temp.domainIp.toString();\r
+ }\r
+ }else{\r
+ if(temp.hostIp!=null){\r
+ ip=temp.hostIp.toString();\r
+ }else {\r
+ ip=null;\r
+ }\r
+ }\r
+ return ip;\r
+ }\r
+\r
+}\r
--- /dev/null
+package com.enqualcomm.support.utils;
+
+
+
+import com.enqualcomm.support.ICApplication;
+import com.enqualcomm.support.bean.DNSTaskModel;
+
+import org.json.JSONException;
+import org.json.JSONStringer;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * httpdns请求数据对比的缓存文件
+ * @author xingyu10
+ *
+ */
+public class HttpDnsRecordUtil {
+
+ private static final String DNS_LOG_FOLDER = "/Android/data/.log/com.sina.util.dnscache/cache/";
+
+ /**
+ * 将任务数缓存至本地
+ * @param model
+ */
+ public static void record(DNSTaskModel model) {
+ File logFolder = getLogFolder();
+ if (null == logFolder) {
+ return;
+ }
+ File writtingFile = getWrittingFile(logFolder);
+ if (null == writtingFile) {
+ return;
+ }
+ FileWriter writer = null;
+ String content = generateLogContent(model);
+ try {
+ writer = new FileWriter(writtingFile, true);
+ String lineSeparator = System.getProperty("line.separator");
+ writer.write(content + lineSeparator);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (writer != null) {
+ writer.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ /**
+ * 获得最近使用的缓存文件
+ * @return
+ */
+ public static File getRecentlyRecordFile(){
+ File logFolder = getLogFolder();
+ if (null == logFolder) {
+ return null;
+ }
+ return getWrittingFile(logFolder);
+ }
+ /**
+ * 获取所有的缓存文件
+ * @return
+ */
+ public static File[] getRecordFiles(){
+ File logFolder = getLogFolder();
+ if (null == logFolder) {
+ return null;
+ }
+ return logFolder.listFiles();
+ }
+ /**
+ * 删除缓存文件
+ * @return
+ */
+ public static boolean removeFiles(){
+ File logFolder = getLogFolder();
+ if (null == logFolder) {
+ return false;
+ }
+ boolean succ = true;
+ File[] files = logFolder.listFiles();
+ if (null != files) {
+ for (File dstFile : files) {
+ succ &= dstFile.delete();
+ }
+ }
+ return succ;
+ }
+ private static String generateLogContent(DNSTaskModel model) {
+ String result = null;
+ JSONStringer jsonStringer = new JSONStringer();
+ try {
+ jsonStringer.object().key("taskID").value(model.taskID).key("taskExpendTime").value(model.taskExpendTime).key("hostExpendTime")
+ .value(model.hostExpendTime).key("domainExpendTime").value(model.domainExpendTime).endObject();
+ result = jsonStringer.toString();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ /**
+ * eg: httpdns.0.log httpdns.1.log
+ *
+ * @param folder
+ * @return
+ */
+ static File getWrittingFile(File folder) {
+ File file = null;
+ if (null != folder) {
+ String[] list = folder.list();
+ if (null == list || list.length == 0) {
+ file = new File(folder, "httpdns." + 0 + ".log");
+ return file;
+ } else {
+ int lastIndex = list.length - 1;
+ file = new File(folder, "httpdns." + lastIndex + ".log");
+ // 10MB则继续新建
+ if (file.length() > 10 * 1024 * 1024) {
+ file = new File(folder, "httpdns." + (lastIndex + 1) + ".log");
+ }
+ return file;
+ }
+ }
+ return file;
+ }
+
+ static File getLogFolder() {
+ return createLogFolderIfNecessary();
+ }
+
+ static File createLogFolderIfNecessary() {
+ File cacheDir = StorageUtils.getCacheDirectory(ICApplication.getInstance());
+ File logdir = new File(cacheDir, ".log");
+ if (!logdir.exists()) {
+ logdir.mkdirs();
+ }
+ return logdir;
+ }
+}
--- /dev/null
+package com.enqualcomm.support.utils;
+
+import android.os.Handler;
+import android.os.Message;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class IPtoAddress {
+
+ /////////////////////////////////////////////////////////////////
+
+ private static IPtoAddress Instance = null;
+
+ private IPtoAddress() { }
+
+ public static IPtoAddress getInstance() {
+
+ if( Instance == null ){
+ Instance = new IPtoAddress();
+ }
+ return IPtoAddress.Instance;
+ }
+
+ /////////////////////////////////////////////////////////////////
+
+ /**
+ * 缓存初始容量值
+ */
+ private final int INIT_SIZE = 8;
+
+ /**
+ * 缓存最大容量值
+ */
+ private final int MAX_CACHE_SIZE = 32;
+
+ /**
+ * 缓存链表
+ */
+ private ConcurrentHashMap<String, String> data = new ConcurrentHashMap<String, String>(INIT_SIZE, MAX_CACHE_SIZE);
+
+ private final String API_URL = "http://ip138.com/ips1388.asp?ip=";
+
+ /////////////////////////////////////////////////////////////////
+
+ public void toAddress( final int id, final String ip, final Handler handler){
+
+ String add = data.get(ip) ;
+
+ if( add != null ){
+
+ Message message = new Message();
+ message.what = id;
+ message.obj = add;
+ handler.sendMessage(message);
+
+ }else{
+
+ // 请求服务器 查询ip 对应的地址
+ new Thread( new Runnable() {
+
+ @Override
+ public void run() {
+ // TODO Auto-generated method stub
+ Thread.currentThread().setName("IP to AddressAndSp");
+
+ String result = executeHttpGet(ip) ;
+ result = regularAddress(result) ;
+ data.put(ip, result) ;
+
+ Message message = new Message();
+ message.what = id;
+ message.obj = result;
+ handler.sendMessage(message);
+
+ }
+ } ).start();
+
+ }
+
+ }
+
+ private String regularAddress( String result ){
+ String str = "" ;
+ Pattern p = Pattern.compile("来自:(.*)<br/><br/></td>");
+ Matcher m = p.matcher(result);
+ while(m.find()){
+ str += m.group(1) ;
+ }
+ return str ;
+ }
+
+ private String executeHttpGet( final String ip ) {
+ String result = null;
+ URL url = null;
+ HttpURLConnection connection = null;
+ InputStreamReader in = null;
+ try {
+ url = new URL(API_URL + ip);
+ connection = (HttpURLConnection) url.openConnection();
+ in = new InputStreamReader(connection.getInputStream(),"gb2312");
+ BufferedReader bufferedReader = new BufferedReader(in);
+ StringBuffer strBuffer = new StringBuffer();
+ String line = null;
+ while ((line = bufferedReader.readLine()) != null) {
+ strBuffer.append(line);
+ }
+ result = strBuffer.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+ return result;
+ }
+
+}
\r
public void connect(final String host, final int port) {\r
long l = SystemClock.elapsedRealtime();\r
- if (l - realtime_old < 3000L)\r
- return; \r
+ if (host.isEmpty()||host ==null){\r
+ Logger.i("host name error "+host);\r
+ return ;\r
+ }\r
+ if (l - realtime_old < 3000L ) {\r
+ Logger.i("3秒内skip 重连!");\r
+ return;\r
+ }\r
realtime_old = l;\r
Logger.i("connect1 "+host+":"+port);\r
// disconnect();\r
public class NetworkObservable {\r
BroadcastReceiver mNetStateBroadcastReceiver = new BroadcastReceiver() {\r
public void onReceive(Context var1, Intent var2) {\r
- NetworkInfo var3 = ((ConnectivityManager)var1.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();\r
- if (var3 != null && var3.isAvailable()) {\r
+ NetworkInfo networkInfo = ((ConnectivityManager)var1.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();\r
+ if (networkInfo != null && networkInfo.isAvailable()) {\r
StringBuilder var4 = new StringBuilder();\r
var4.append("BroadcastReceiver---reConnection++ KeepAlive.isConnected=");\r
var4.append(KeepAlive.isConnected);\r
Logger.i(var4.toString());\r
if (!KeepAlive.isConnected && !NetworkObservable.this.network_is_from_no_to_yes) {\r
if (NetworkObservable.this.network_is_down) {\r
+\r
NetworkObservable.this.objectPublishSubject.onNext(3);\r
NetworkObservable.this.network_is_down = false;\r
} else {\r
} else if (KeepAlive.isConnected) {\r
NetworkObservable.this.network_is_down = false;\r
}\r
-\r
NetworkObservable.this.network_is_from_no_to_yes = false;\r
} else {\r
Logger.i("网络断开");\r
import android.content.Context;\r
import android.content.Intent;\r
import android.hardware.display.DisplayManager;\r
+import android.net.ConnectivityManager;\r
+import android.net.NetworkInfo;\r
import android.os.Build;\r
import android.os.PowerManager;\r
import android.provider.Settings;\r
stringBuilder.append(paramString);\r
Logger.i(stringBuilder.toString());\r
}\r
- \r
+\r
+ /**\r
+ * 检查用户的网络:是否有网络,所需权限:<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>\r
+ */\r
+ public static boolean checkNet(Context context) {\r
+ // 判断:WIFI链接\r
+ boolean isWIFI = isWIFIConnection(context);\r
+ // 判断:Mobile链接\r
+ boolean isMOBILE = isMOBILEConnection(context);\r
+ if (!isWIFI && !isMOBILE) {\r
+ return false;//既不是手机连接,也不是wifi连接\r
+ }\r
+ return true;\r
+ }/**\r
+ * 判断:是否是手机链接\r
+ * @param context\r
+ * @return\r
+ */\r
+ private static boolean isMOBILEConnection(Context context) {\r
+ ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);\r
+ //获取连接的信息\r
+ NetworkInfo networkInfo = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);\r
+ if (networkInfo != null) {\r
+ return networkInfo.isConnected();\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * 判断:WIFI链接\r
+ *\r
+ * @param context\r
+ * @return\r
+ */\r
+ private static boolean isWIFIConnection(Context context) {\r
+ ConnectivityManager manager = (ConnectivityManager) context\r
+ .getSystemService(Context.CONNECTIVITY_SERVICE);\r
+\r
+ NetworkInfo networkInfo = manager\r
+ .getNetworkInfo(ConnectivityManager.TYPE_WIFI);\r
+ if (networkInfo != null) {\r
+ return networkInfo.isConnected();\r
+ }\r
+ return false;\r
+ }\r
public int getNetworkType() {\r
init();\r
int networktype=IS_UNKNOWN;\r
--- /dev/null
+/*******************************************************************************
+ * Copyright 2011-2013 Sergey Tarasevich
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package com.enqualcomm.support.utils;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.os.StatFs;
+
+import java.io.File;
+import java.io.IOException;
+
+import static android.os.Environment.MEDIA_MOUNTED;
+
+/**
+ * Provides application storage paths
+ *
+ * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
+ * @since 1.0.0
+ */
+public final class StorageUtils {
+
+ private static final String EXTERNAL_STORAGE_PERMISSION = "android.permission.WRITE_EXTERNAL_STORAGE";
+ private static final String INDIVIDUAL_DIR_NAME = "uil-images";
+
+ private StorageUtils() {
+ }
+
+ /**
+ * Returns application cache directory. Cache directory will be created on SD card
+ * <i>("/Android/data/[app_package_name]/cache")</i> if card is mounted and app has appropriate permission. Else -
+ * Android defines cache directory on device's file system.
+ *
+ * @param context Application context
+ * @return Cache {@link File directory}.<br />
+ * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and
+ * {@link Context#getCacheDir() Context.getCacheDir()} returns null).
+ */
+ public static File getCacheDirectory(Context context) {
+ return getCacheDirectory(context, true);
+ }
+
+ /**
+ * Returns application cache directory. Cache directory will be created on SD card
+ * <i>("/Android/data/[app_package_name]/cache")</i> (if card is mounted and app has appropriate permission) or
+ * on device's file system depending incoming parameters.
+ *
+ * @param context Application context
+ * @param preferExternal Whether prefer external location for cache
+ * @return Cache {@link File directory}.<br />
+ * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and
+ * {@link Context#getCacheDir() Context.getCacheDir()} returns null).
+ */
+ public static File getCacheDirectory(Context context, boolean preferExternal) {
+ File appCacheDir = null;
+ if (preferExternal && MEDIA_MOUNTED
+ .equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context) && haveFreeSpace()) {
+ appCacheDir = getExternalCacheDir(context);
+ }
+ if (appCacheDir == null) {
+ appCacheDir = context.getCacheDir();
+ }
+ if (appCacheDir == null) {
+ String cacheDirPath = "/data/data/" + context.getPackageName() + "/cache/";
+ appCacheDir = new File(cacheDirPath);
+ }
+ return appCacheDir;
+ }
+
+ /**
+ * Returns individual application cache directory (for only image caching from ImageLoader). Cache directory will be
+ * created on SD card <i>("/Android/data/[app_package_name]/cache/uil-images")</i> if card is mounted and app has
+ * appropriate permission. Else - Android defines cache directory on device's file system.
+ *
+ * @param context Application context
+ * @return Cache {@link File directory}
+ */
+ public static File getIndividualCacheDirectory(Context context) {
+ File cacheDir = getCacheDirectory(context);
+ File individualCacheDir = new File(cacheDir, INDIVIDUAL_DIR_NAME);
+ if (!individualCacheDir.exists()) {
+ if (!individualCacheDir.mkdir()) {
+ individualCacheDir = cacheDir;
+ }
+ }
+ return individualCacheDir;
+ }
+
+ /**
+ * Returns specified application cache directory. Cache directory will be created on SD card by defined path if card
+ * is mounted and app has appropriate permission. Else - Android defines cache directory on device's file system.
+ *
+ * @param context Application context
+ * @param cacheDir Cache directory path (e.g.: "AppCacheDir", "AppDir/cache/images")
+ * @return Cache {@link File directory}
+ */
+ public static File getOwnCacheDirectory(Context context, String cacheDir) {
+ File appCacheDir = null;
+ if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {
+ appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);
+ }
+ if (appCacheDir == null || (!appCacheDir.exists() && !appCacheDir.mkdirs())) {
+ appCacheDir = context.getCacheDir();
+ }
+ return appCacheDir;
+ }
+
+ private static File getExternalCacheDir(Context context) {
+ File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data");
+ File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache");
+ if (!appCacheDir.exists()) {
+ if (!appCacheDir.mkdirs()) {
+ return null;
+ }
+ try {
+ new File(appCacheDir, ".nomedia").createNewFile();
+ } catch (IOException e) {
+ }
+ }
+ return appCacheDir;
+ }
+
+ private static boolean hasExternalStoragePermission(Context context) {
+ int perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION);
+ return perm == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private static boolean haveFreeSpace() {
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ StatFs st = new StatFs(Environment.getExternalStorageDirectory().getPath());
+ int blockSize = st.getBlockSize();
+ long available = st.getAvailableBlocks();
+ long availableSize = (blockSize * available);
+ if (availableSize < 1024 * 1024 * 10) {// //sd卡空间如果小于10M,就认为sd卡空间不足
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+}
public static String getLocalTime() { return getLocalTime(System.currentTimeMillis()); }\r
\r
public static String getLocalTime(long paramLong) { return (new SimpleDateFormat("yyyy/MM/dd,HH:mm:ss")).format(new Date(paramLong)); }\r
- \r
+ public static String getLocalTime2() { return getLocalTime2(System.currentTimeMillis()); }\r
+\r
+ public static String getLocalTime2(long paramLong) { return (new SimpleDateFormat("MMddHHmmss")).format(new Date(paramLong)); }\r
+\r
public static String getSystemTime() { return getSystemTime(System.currentTimeMillis()); }\r
\r
public static String getSystemTime(long paramLong) { return (new SimpleDateFormat("yyyy-MM-dd;HH:mm:ss")).format(new Date(paramLong)); }\r
public static Charset UTF_8 = Charset.forName("UTF-8");\r
\r
\r
+\r
/**\r
* 解析域名获取IP数组\r
* @param host\r
public static String parseHostGetIPAddress(String host) {\r
StringBuilder serverip=new StringBuilder("");\r
try {\r
+\r
+\r
InetAddress[] inetAddressArr = InetAddress.getAllByName(host);\r
if (inetAddressArr != null && inetAddressArr.length > 0) {\r
String[] ipAddressArr = new String[inetAddressArr.length];\r
-#Mon Feb 10 23:47:07 CST 2020\r
-VERSION_CODE=348\r
+#Wed Feb 12 23:18:01 CST 2020\r
+VERSION_CODE=351\r
--- /dev/null
+apply plugin: 'com.android.library'\r
+\r
+android {\r
+ compileSdkVersion 18\r
+ buildToolsVersion "28.0.3"\r
+\r
+ defaultConfig {\r
+ }\r
+\r
+ buildTypes {\r
+ release {\r
+ zipAlignEnabled true // zip 对齐优化\r
+// shrinkResources true // 移除未使用的资源文件\r
+// signingConfig signingConfigs.key\r
+ minifyEnabled true\r
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\r
+ renderscriptDebuggable = false\r
+ debuggable = false\r
+ jniDebuggable = false\r
+ manifestPlaceholders = [:]\r
+ }\r
+\r
+ debug {\r
+// signingConfig signingConfigs.key\r
+ // 启用 Android 插件压缩器\r
+// minifyEnabled true\r
+// useProguard false\r
+ }\r
+ compileOptions {\r
+ sourceCompatibility JavaVersion.VERSION_1_8\r
+ targetCompatibility JavaVersion.VERSION_1_8\r
+ }\r
+ }\r
+}\r
+\r
+dependencies {\r
+ compile 'com.android.support:support-v4:18.0.0'\r
+}\r
--- /dev/null
+o/classes\r
--- /dev/null
+/**
+ * Automatically generated file. DO NOT MODIFY
+ */
+package com.sina.util.dnscache;
+
+public final class BuildConfig {
+ public static final boolean DEBUG = Boolean.parseBoolean("true");
+ public static final String LIBRARY_PACKAGE_NAME = "com.sina.util.dnscache";
+ /**
+ * @deprecated APPLICATION_ID is misleading in libraries. For the library package name use LIBRARY_PACKAGE_NAME
+ */
+ @Deprecated
+ public static final String APPLICATION_ID = "com.sina.util.dnscache";
+ public static final String BUILD_TYPE = "debug";
+ public static final String FLAVOR = "";
+ public static final int VERSION_CODE = -1;
+ public static final String VERSION_NAME = "";
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"\r
+ package="com.sina.util.dnscache" >\r
+\r
+ <!-- 需要配置的权限 -->\r
+ <uses-permission android:name="android.permission.INTERNET" />\r
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />\r
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />\r
+ <uses-permission android:name="android.permission.WAKE_LOCK" />\r
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />\r
+\r
+ <application android:label="@string/app_name" >\r
+\r
+ <!-- 主要注册一个广播 -->\r
+ <!-- <receiver -->\r
+ <!-- android:name="com.sina.util.networktype.NetworkStateReceiver" -->\r
+ <!-- android:label="NetworkConnection" > -->\r
+ <!-- <intent-filter> -->\r
+ <!-- <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> -->\r
+ <!-- <action android:name="android.intent.action.USER_PRESENT" /> -->\r
+ <!-- </intent-filter> -->\r
+ <!-- </receiver> -->\r
+\r
+ </application>\r
+\r
+</manifest>
\ No newline at end of file
--- /dev/null
+[{"outputType":{"type":"AAPT_FRIENDLY_MERGED_MANIFESTS"},"apkData":{"type":"MAIN","splits":[],"versionCode":-1,"enabled":true,"outputFile":"dNSCache-debug.aar","fullName":"debug","baseName":"debug"},"path":"AndroidManifest.xml","properties":{"packageId":"com.sina.util.dnscache","split":""}}]
\ No newline at end of file
--- /dev/null
+{}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\main\jniLibs"/></dataSet><dataSet config="debug" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\debug\jniLibs"/></dataSet></merger>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\main\shaders"/></dataSet><dataSet config="debug" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\debug\shaders"/></dataSet></merger>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\main\assets"/><source path="D:\Snicker\icsupport\dNSCache\build\intermediates\shader_assets\debug\compileDebugShaders\out"/></dataSet><dataSet config="debug" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\debug\assets"/></dataSet></merger>
\ No newline at end of file
--- /dev/null
+#Thu Feb 13 00:47:58 CST 2020\r
+D\:\\Snicker\\icsupport\\dNSCache\\src\\main\\res\\layout\\activity_main.xml=D\:\\Snicker\\icsupport\\dNSCache\\build\\intermediates\\packaged_res\\debug\\layout\\activity_main.xml\r
+D\:\\Snicker\\icsupport\\dNSCache\\src\\main\\res\\drawable-hdpi\\ic_launcher.png=D\:\\Snicker\\icsupport\\dNSCache\\build\\intermediates\\packaged_res\\debug\\drawable-hdpi-v4\\ic_launcher.png\r
+D\:\\Snicker\\icsupport\\dNSCache\\src\\main\\res\\drawable-mdpi\\ic_launcher.png=D\:\\Snicker\\icsupport\\dNSCache\\build\\intermediates\\packaged_res\\debug\\drawable-mdpi-v4\\ic_launcher.png\r
+D\:\\Snicker\\icsupport\\dNSCache\\src\\main\\res\\drawable-xhdpi\\ic_launcher.png=D\:\\Snicker\\icsupport\\dNSCache\\build\\intermediates\\packaged_res\\debug\\drawable-xhdpi-v4\\ic_launcher.png\r
+D\:\\Snicker\\icsupport\\dNSCache\\src\\main\\res\\menu\\menu_main.xml=D\:\\Snicker\\icsupport\\dNSCache\\build\\intermediates\\packaged_res\\debug\\menu\\menu_main.xml\r
+D\:\\Snicker\\icsupport\\dNSCache\\src\\main\\res\\drawable-xxhdpi\\ic_launcher.png=D\:\\Snicker\\icsupport\\dNSCache\\build\\intermediates\\packaged_res\\debug\\drawable-xxhdpi-v4\\ic_launcher.png\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="action_clear">清除缓存</string>
+ <string name="action_printf_domain">打印域名表</string>
+ <string name="action_printf_ip">打印IP表</string>
+ <string name="action_settings">参数设置</string>
+ <string name="app_name">DNSCache</string>
+ <string name="hello_world">Hello world!</string>
+</resources>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<merger version="3"><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\main\res"/><source path="D:\Snicker\icsupport\dNSCache\build\generated\res\rs\debug"/><source path="D:\Snicker\icsupport\dNSCache\build\generated\res\resValues\debug"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main" generated-set="main$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\main\res"><file name="ic_launcher" path="D:\Snicker\icsupport\dNSCache\src\main\res\drawable-hdpi\ic_launcher.png" qualifiers="hdpi-v4" type="drawable"/><file name="ic_launcher" path="D:\Snicker\icsupport\dNSCache\src\main\res\drawable-mdpi\ic_launcher.png" qualifiers="mdpi-v4" type="drawable"/><file name="ic_launcher" path="D:\Snicker\icsupport\dNSCache\src\main\res\drawable-xhdpi\ic_launcher.png" qualifiers="xhdpi-v4" type="drawable"/><file name="ic_launcher" path="D:\Snicker\icsupport\dNSCache\src\main\res\drawable-xxhdpi\ic_launcher.png" qualifiers="xxhdpi-v4" type="drawable"/><file name="activity_main" path="D:\Snicker\icsupport\dNSCache\src\main\res\layout\activity_main.xml" qualifiers="" type="layout"/><file name="menu_main" path="D:\Snicker\icsupport\dNSCache\src\main\res\menu\menu_main.xml" qualifiers="" type="menu"/><file path="D:\Snicker\icsupport\dNSCache\src\main\res\values\strings.xml" qualifiers=""><string name="app_name">DNSCache</string><string name="hello_world">Hello world!</string><string name="action_printf_domain">打印域名表</string><string name="action_printf_ip">打印IP表</string><string name="action_clear">清除缓存</string><string name="action_settings">参数设置</string></file></source><source path="D:\Snicker\icsupport\dNSCache\build\generated\res\rs\debug"/><source path="D:\Snicker\icsupport\dNSCache\build\generated\res\resValues\debug"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="debug$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\debug\res"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="debug" generated-set="debug$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\Snicker\icsupport\dNSCache\src\debug\res"/></dataSet><mergedItems/></merger>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"\r
+ package="com.sina.util.dnscache" >\r
+\r
+ <!-- 需要配置的权限 -->\r
+ <uses-permission android:name="android.permission.INTERNET" />\r
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />\r
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />\r
+ <uses-permission android:name="android.permission.WAKE_LOCK" />\r
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />\r
+\r
+ <application android:label="@string/app_name" >\r
+\r
+ <!-- 主要注册一个广播 -->\r
+ <!-- <receiver -->\r
+ <!-- android:name="com.sina.util.networktype.NetworkStateReceiver" -->\r
+ <!-- android:label="NetworkConnection" > -->\r
+ <!-- <intent-filter> -->\r
+ <!-- <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> -->\r
+ <!-- <action android:name="android.intent.action.USER_PRESENT" /> -->\r
+ <!-- </intent-filter> -->\r
+ <!-- </receiver> -->\r
+\r
+ </application>\r
+\r
+</manifest>
\ No newline at end of file
--- /dev/null
+R_DEF: Internal format may change without notice
+local
+drawable ic_launcher
+id action_clear
+id action_printf_domain
+id action_printf_ip
+id action_settings
+id button
+id editText
+id textView
+layout activity_main
+menu menu_main
+string action_clear
+string action_printf_domain
+string action_printf_ip
+string action_settings
+string app_name
+string hello_world
--- /dev/null
+1<?xml version="1.0" encoding="utf-8"?>
+2<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+3 package="com.sina.util.dnscache" >
+4
+5 <!-- 需要配置的权限 -->
+6 <uses-permission android:name="android.permission.INTERNET" />
+6-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:24:5-67
+6-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:24:22-64
+7 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+7-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:25:5-79
+7-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:25:22-76
+8 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+8-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:26:5-76
+8-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:26:22-73
+9 <uses-permission android:name="android.permission.WAKE_LOCK" />
+9-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:27:5-68
+9-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:27:22-65
+10 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+10-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:28:5-81
+10-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:28:22-78
+11
+12 <application android:label="@string/app_name" >
+12-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:5:5-21:19
+12-->D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:8:9-41
+13
+14 <!-- 主要注册一个广播 -->
+15 <!-- <receiver -->
+16 <!-- android:name="com.sina.util.networktype.NetworkStateReceiver" -->
+17 <!-- android:label="NetworkConnection" > -->
+18 <!-- <intent-filter> -->
+19 <!-- <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> -->
+20 <!-- <action android:name="android.intent.action.USER_PRESENT" /> -->
+21 <!-- </intent-filter> -->
+22 <!-- </receiver> -->
+23
+24 </application>
+25
+26</manifest>
--- /dev/null
+[{"outputType":{"type":"MERGED_MANIFESTS"},"apkData":{"type":"MAIN","splits":[],"versionCode":-1,"enabled":true,"outputFile":"dNSCache-debug.aar","fullName":"debug","baseName":"debug"},"path":"..\\..\\library_manifest\\debug\\AndroidManifest.xml","properties":{"packageId":"com.sina.util.dnscache","split":""}}]
\ No newline at end of file
--- /dev/null
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".MainActivity" >
+
+ <TextView
+ android:id="@+id/textView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text=" 输入一个需要测试的API URL:" />
+
+ <EditText
+ android:id="@+id/editText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:text="http://api.weibo.cn/2/remind/unread_count?remind_version=94&ext_all=0&c=android&i=f6fd268&s=7fe80de0&ua=Xiaomi-MI%203W__weibo__5.3.0_alpha1__android__android4.4.4&wm=3333_1001&idc=&v_f=2&from=1052895010&gsid=_2A254Mx_tDeTxGeNM7lMY9ybEzD6IHXVZaRQlrDV6PUJbrdANLVfzkWo8pgH_awAHMa74PMGrs-jUSB8TTg..&lang=zh_CN&skin=default&oldwm=3333_1001&with_settings=1&unread_message=1&with_page_group=1" />
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="测试" />
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
+
+ <item android:id="@+id/action_clear" android:title="@string/action_clear"
+ android:orderInCategory="100" />
+
+ <item android:id="@+id/action_printf_domain" android:title="@string/action_printf_domain"
+ android:orderInCategory="100" />
+
+ <item android:id="@+id/action_printf_ip" android:title="@string/action_printf_ip"
+ android:orderInCategory="100" />
+
+ <item android:id="@+id/action_settings" android:title="@string/action_settings"
+ android:orderInCategory="100" />
+
+</menu>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="action_clear">清除缓存</string>
+ <string name="action_printf_domain">打印域名表</string>
+ <string name="action_printf_ip">打印IP表</string>
+ <string name="action_settings">参数设置</string>
+ <string name="app_name">DNSCache</string>
+ <string name="hello_world">Hello world!</string>
+</resources>
\ No newline at end of file
--- /dev/null
+com.sina.util.dnscache
+drawable ic_launcher
+id action_clear
+id action_printf_domain
+id action_printf_ip
+id action_settings
+id button
+id editText
+id textView
+layout activity_main
+menu menu_main
+string action_clear
+string action_printf_domain
+string action_printf_ip
+string action_settings
+string app_name
+string hello_world
--- /dev/null
+int drawable ic_launcher 0x7f080001
+int id action_clear 0x7f0b0001
+int id action_printf_domain 0x7f0b0002
+int id action_printf_ip 0x7f0b0003
+int id action_settings 0x7f0b0004
+int id button 0x7f0b0005
+int id editText 0x7f0b0006
+int id textView 0x7f0b0007
+int layout activity_main 0x7f0e0001
+int menu menu_main 0x7f0f0001
+int string action_clear 0x7f140001
+int string action_printf_domain 0x7f140002
+int string action_printf_ip 0x7f140003
+int string action_settings 0x7f140004
+int string app_name 0x7f140005
+int string hello_world 0x7f140006
--- /dev/null
+-- Merging decision tree log ---
+manifest
+ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:2:1-30:12
+INJECTED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:2:1-30:12
+INJECTED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:2:1-30:12
+ package
+ ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:3:5-37
+ INJECTED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml
+ INJECTED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml
+ xmlns:android
+ ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:2:11-69
+application
+ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:5:5-21:19
+ android:label
+ ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:8:9-41
+uses-permission#android.permission.INTERNET
+ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:24:5-67
+ android:name
+ ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:24:22-64
+uses-permission#android.permission.ACCESS_NETWORK_STATE
+ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:25:5-79
+ android:name
+ ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:25:22-76
+uses-permission#android.permission.ACCESS_WIFI_STATE
+ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:26:5-76
+ android:name
+ ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:26:22-73
+uses-permission#android.permission.WAKE_LOCK
+ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:27:5-68
+ android:name
+ ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:27:22-65
+uses-permission#android.permission.WRITE_EXTERNAL_STORAGE
+ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:28:5-81
+ android:name
+ ADDED from D:\Snicker\icsupport\dNSCache\src\main\AndroidManifest.xml:28:22-78
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<module external.linked.project.id=":dNSCache" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">\r
+ <component name="FacetManager">\r
+ <facet type="android-gradle" name="Android-Gradle">\r
+ <configuration>\r
+ <option name="GRADLE_PROJECT_PATH" value=":dNSCache" />\r
+ <option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.5.3" />\r
+ <option name="LAST_KNOWN_AGP_VERSION" value="3.5.3" />\r
+ </configuration>\r
+ </facet>\r
+ <facet type="android" name="Android">\r
+ <configuration>\r
+ <option name="SELECTED_BUILD_VARIANT" value="debug" />\r
+ <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />\r
+ <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />\r
+ <afterSyncTasks>\r
+ <task>generateDebugSources</task>\r
+ </afterSyncTasks>\r
+ <option name="ALLOW_USER_CONFIGURATION" value="false" />\r
+ <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />\r
+ <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />\r
+ <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/resValues/debug" />\r
+ <option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="" />\r
+ <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />\r
+ <option name="PROJECT_TYPE" value="1" />\r
+ </configuration>\r
+ </facet>\r
+ </component>\r
+ <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">\r
+ <output url="file://$MODULE_DIR$/build/intermediates/javac/debug/classes" />\r
+ <output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/classes" />\r
+ <exclude-output />\r
+ <content url="file://$MODULE_DIR$">\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debug/out" isTestSource="false" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out" isTestSource="false" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" isTestSource="false" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debugAndroidTest/out" isTestSource="true" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" isTestSource="true" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debugUnitTest/out" isTestSource="true" generated="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />\r
+ <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />\r
+ <excludeFolder url="file://$MODULE_DIR$/build" />\r
+ </content>\r
+ <orderEntry type="jdk" jdkName="Android API 18 Platform" jdkType="Android SDK" />\r
+ <orderEntry type="sourceFolder" forTests="false" />\r
+ <orderEntry type="library" name="Gradle: com.android.support:support-v4:18.0.0@jar" level="project" />\r
+ </component>\r
+</module>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.sina.util.dnscache" >
+
+ <application
+
+
+ android:label="@string/app_name" >
+
+
+ <!-- 主要注册一个广播 -->
+<!-- <receiver-->
+<!-- android:name="com.sina.util.networktype.NetworkStateReceiver"-->
+<!-- android:label="NetworkConnection" >-->
+<!-- <intent-filter>-->
+<!-- <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />-->
+<!-- <action android:name="android.intent.action.USER_PRESENT" />-->
+<!-- </intent-filter>-->
+<!-- </receiver>-->
+
+ </application>
+
+ <!-- 需要配置的权限 -->
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+</manifest>
\ No newline at end of file
--- /dev/null
+package com.sina.util.dnscache;
+
+import java.io.File;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.telephony.TelephonyManager;
+
+public class AppConfigUtil {
+
+ private static Context mContext;
+
+ public static void init(Context ctx) {
+ mContext = ctx;
+ }
+
+ public static Context getApplicationContext() {
+ return mContext.getApplicationContext();
+ }
+
+ /**
+ * 获取缓存文件夹
+ *
+ * @return
+ */
+ public static File getExternalCacheDir() {
+ File file = mContext.getExternalCacheDir();
+ if (null == file) {
+ file = createExternalCacheDir();
+ }
+ return file;
+ }
+
+ private static File createExternalCacheDir() {
+ File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data");
+ File appCacheDir = new File(new File(dataDir, mContext.getPackageName()), "cache");
+ if (!appCacheDir.exists()) {
+ if (!appCacheDir.mkdirs()) {
+ return mContext.getCacheDir();
+ }
+ }
+ return appCacheDir;
+ }
+
+ /**
+ * 返回当前程序版本名
+ *
+ * @return
+ */
+ public static String getVersionName() {
+ String versionName = "";
+ try {
+ PackageManager pm = mContext.getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), 0);
+ versionName = pi.versionName;
+ if (versionName == null || versionName.length() <= 0) {
+ return "";
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return versionName;
+ }
+
+ /**
+ * 获取设备id
+ *
+ * @return
+ */
+ public static String getDeviceId() {
+ TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ String deviceId = tm.getDeviceId();
+ return deviceId;
+ }
+
+ /**
+ * 获取当前的应用key
+ * @return
+ */
+ public static String getAppKey() {
+ try {
+ ApplicationInfo appInfo = mContext.getPackageManager()
+ .getApplicationInfo(mContext.getPackageName(),PackageManager.GET_META_DATA);
+ appInfo.metaData.getString("meta_name");
+ Bundle metaData = appInfo.metaData;
+ if (null != metaData) {
+ String appKey = metaData.getString("DNSCACHE_APP_KEY");
+ return appKey;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
--- /dev/null
+package com.sina.util.dnscache;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.net.NetworkInfo;
+import android.text.TextUtils;
+
+import com.sina.util.dnscache.cache.DnsCacheManager;
+import com.sina.util.dnscache.cache.IDnsCache;
+import com.sina.util.dnscache.dnsp.DnsManager;
+import com.sina.util.dnscache.dnsp.IDns;
+import com.sina.util.dnscache.log.HttpDnsLogManager;
+import com.sina.util.dnscache.model.DomainModel;
+import com.sina.util.dnscache.model.HttpDnsPack;
+import com.sina.util.dnscache.model.IpModel;
+import com.sina.util.dnscache.net.ApacheHttpClientNetworkRequests;
+import com.sina.util.dnscache.net.networktype.Constants;
+import com.sina.util.dnscache.net.networktype.NetworkManager;
+import com.sina.util.dnscache.net.networktype.NetworkStateReceiver;
+import com.sina.util.dnscache.query.IQuery;
+import com.sina.util.dnscache.query.QueryManager;
+import com.sina.util.dnscache.score.IScore;
+import com.sina.util.dnscache.score.ScoreManager;
+import com.sina.util.dnscache.speedtest.ISpeedtest;
+import com.sina.util.dnscache.speedtest.SpeedtestManager;
+import com.sina.util.dnscache.thread.RealTimeThreadPool;
+
+/**
+ *
+ * 项目名称: DNSCache <br>
+ * 类名称: DNSCache <br>
+ * 类描述: Lib库全局 对外实例对象 <br>
+ * 创建人: fenglei <br>
+ * 创建时间: 2015-3-26 下午5:26:04 <br>
+ *
+ * 修改人: <br>
+ * 修改时间: <br>
+ * 修改备注: <br>
+ *
+ * @version V1.0
+ */
+@SuppressLint("NewApi")
+public class DNSCache {
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ public static boolean isEnable = true;
+ public static int timer_interval = 60 * 1000;
+ private static DNSCache Instance = null;
+ private static Context sContext;
+ private static Object lock = new Object();
+
+ public IDnsCache dnsCacheManager = null;
+ public IQuery queryManager = null;
+ public IScore scoreManager = null;
+ public IDns dnsManager = null;
+ public ISpeedtest speedtestManager = null;
+
+ public DNSCache(Context ctx) {
+ dnsCacheManager = new DnsCacheManager(ctx);
+ queryManager = new QueryManager(dnsCacheManager);
+ scoreManager = new ScoreManager();
+ dnsManager = new DnsManager();
+ speedtestManager = new SpeedtestManager();
+ startTimer();
+ }
+
+ public static DNSCache getInstance() {
+ if (null == Instance) {
+ synchronized (lock) {
+ if (Instance == null) {
+ Instance = new DNSCache(sContext);
+ }
+ }
+ }
+ return Instance;
+ }
+
+ public static void Init(Context ctx) {
+ if (null == ctx){
+ throw new RuntimeException("DNSCache Init; context can not be null!!!");
+ }
+ sContext = ctx.getApplicationContext();
+ // 根据配置文件 初始化策略
+ DNSCacheConfig.InitCfg(sContext);
+ NetworkManager.CreateInstance(sContext);
+ AppConfigUtil.init(sContext);
+ NetworkStateReceiver.register(sContext);
+ Instance = null;
+ }
+
+ /**
+ * 预加载逻辑
+ *
+ * @param domains
+ */
+ public void preLoadDomains(final String[] domains) {
+ for (String domain : domains) {
+// checkUpdates(domain, true);
+ checkUpdates(domain, false);//disable speed test
+ }
+ }
+
+ public IDnsCache getDnsCacheManager() {
+ return dnsCacheManager;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 获取 HttpDNS信息
+ *
+ * @param url
+ * 传入的Url
+ * @return 返回排序后的可直接使用接口
+ */
+ public DomainInfo[] getDomainServerIp(String url) {
+ String host = Tools.getHostName(url);
+ if (isEnable) {
+ if (!TextUtils.isEmpty(host) && Tools.isIPV4(host)) {
+ DomainInfo[] info = new DomainInfo[1];
+ info[0] = new DomainInfo("", url, "");
+ return info;
+ }
+ // 查询domain对应的server ip数组
+ final DomainModel domainModel = queryManager.queryDomainIp(String.valueOf(NetworkManager.getInstance().getSPID()), host);
+
+
+ // 如果本地cache 和 内置数据都没有 返回null,然后马上查询数据
+ if (null == domainModel || domainModel.id == -1) {
+// this.checkUpdates(host, true);
+ this.checkUpdates(host, false); //disable speed test
+ if (null == domainModel) {
+ return null;
+ }
+ }
+
+ HttpDnsLogManager.getInstance().writeLog(HttpDnsLogManager.TYPE_INFO, HttpDnsLogManager.ACTION_INFO_DOMAIN,domainModel.tojson(), true);
+
+ ArrayList<IpModel> result = filterInvalidIp(domainModel.ipModelArr);
+ String[] scoreIpArray = scoreManager.ListToArr(result);
+
+ if (scoreIpArray == null || scoreIpArray.length == 0) {
+ return null; // 排序错误 终端后续流程
+ }
+
+ // 转换成需要返回的数据模型
+ DomainInfo[] domainInfoList = DomainInfo.DomainInfoFactory(scoreIpArray, url, host);
+
+ return domainInfoList;
+ } else {
+ return null;
+ }
+ }
+ /**
+ * 过滤无效ip数据
+ * @param ipModelArr
+ * @return
+ */
+ private ArrayList<IpModel> filterInvalidIp(ArrayList<IpModel> ipModelArr) {
+ ArrayList<IpModel> result = new ArrayList<IpModel>();
+ for (IpModel ipModel : ipModelArr) {
+ if (!("" + SpeedtestManager.MAX_OVERTIME_RTT).equals(ipModel.rtt)) {
+ result.add(ipModel);
+ }
+ }
+ return result;
+ }
+
+ private boolean isSupport(String host) {
+ return (DNSCacheConfig.domainSupportList.size() == 0) || (DNSCacheConfig.domainSupportList.contains(host));
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ private ConcurrentHashMap<String, UpdateTask> mRunningTasks = new ConcurrentHashMap<String, UpdateTask>();
+
+ /**
+ * 从httpdns 服务器重新拉取数据
+ *
+ * @param domainModel
+ */
+ private void checkUpdates(String domain, boolean speedTest) {
+ if (isSupport(domain)) {
+ final String host = domain;
+ final boolean needSpeedTest = speedTest;
+ UpdateTask task = mRunningTasks.get(host);
+ if (null == task) {
+ UpdateTask updateTask = new UpdateTask(new Runnable() {
+ @Override
+ public void run() {
+ Thread.currentThread().setName("Get Http Dns Data");
+ getHttpDnsData(host);
+ mRunningTasks.remove(host);
+ if (needSpeedTest) {
+ RealTimeThreadPool.getInstance().execute(new SpeedTestTask());
+ }
+ }
+ });
+ mRunningTasks.put(host, updateTask);
+ updateTask.start();
+ } else {
+ long beginTime = task.getBeginTime();
+ long now = System.currentTimeMillis();
+ // 上次拉取超时,这次再开一个线程继续
+ if (now - beginTime > 30 * 1000) {
+ task.start();
+ }
+ }
+ }
+ }
+
+ static class UpdateTask {
+
+ public Runnable runnable;
+
+ public long beginTime;
+
+ public UpdateTask(Runnable runnable) {
+ super();
+ this.runnable = runnable;
+ this.beginTime = System.currentTimeMillis();
+ }
+
+ public void start() {
+ Thread thread = new Thread(runnable);
+ thread.start();
+ }
+
+ public long getBeginTime() {
+ return beginTime;
+ }
+ }
+
+ /**
+ * 根据 host 更新数据
+ *
+ * @param host
+ */
+ private final DomainModel getHttpDnsData(String host) {
+
+ // 获取 httpdns 数据
+ HttpDnsPack httpDnsPack = dnsManager.requestDns(host);
+
+ if (httpDnsPack == null) {
+ return null; // 没有从htppdns服务器获取正确的数据。必须中断下面流程
+ }
+
+ HttpDnsLogManager.getInstance().writeLog(HttpDnsLogManager.TYPE_INFO, HttpDnsLogManager.ACTION_INFO_DOMAIN, httpDnsPack.toJson(),
+ true);
+ // 插入本地 cache
+ DomainModel domainModel = dnsCacheManager.insertDnsCache(httpDnsPack);
+
+ return domainModel;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 定时器休眠时间
+ */
+ public final int sleepTime = timer_interval;
+
+ /**
+ * 启动定时器
+ */
+ private void startTimer() {
+ timer = new Timer();
+ timer.schedule(task, 0, sleepTime);
+ }
+
+ /**
+ * 定时器Obj
+ */
+ private Timer timer = null;
+
+ /**
+ * TimerTask 运行时间
+ */
+ public long TimerTaskOldRunTime = 0;
+ /**
+ * 上次测速时间
+ */
+ private long lastSpeedTime;
+ /**
+ * 上次日志上传时间
+ */
+ private long lastLogTime;
+
+ /**
+ * 定时器还多久启动
+ */
+ public long getTimerDelayedStartTime() {
+ return (sleepTime - (System.currentTimeMillis() - TimerTaskOldRunTime)) / 1000;
+ }
+
+ /**
+ * 定时器任务
+ */
+ private TimerTask task = new TimerTask() {
+
+ @Override
+ public void run() {
+ TimerTaskOldRunTime = System.currentTimeMillis();
+ //无网络情况下不执行任何后台任务操作
+ if (NetworkManager.Util.getNetworkType() == Constants.NETWORK_TYPE_UNCONNECTED || NetworkManager.Util.getNetworkType() == Constants.MOBILE_UNKNOWN) {
+ return;
+ }
+ /************************* 更新过期数据 ********************************/
+ Thread.currentThread().setName("HTTP DNS TimerTask");
+ final ArrayList<DomainModel> list = dnsCacheManager.getExpireDnsCache();
+ for (DomainModel model : list) {
+ checkUpdates(model.domain, false);
+ }
+
+ long now = System.currentTimeMillis();
+ /************************* 测速逻辑 ********************************/
+ if (now - lastSpeedTime > SpeedtestManager.time_interval - 3) {
+ lastSpeedTime = now;
+ RealTimeThreadPool.getInstance().execute(new SpeedTestTask());
+ }
+
+ /************************* 日志上报相关 ********************************/
+ now = System.currentTimeMillis();
+ if (HttpDnsLogManager.LOG_UPLOAD_SWITCH && now - lastLogTime > HttpDnsLogManager.time_interval) {
+ lastLogTime = now;
+ // 判断当前是wifi网络才能上传
+ if (NetworkManager.Util.getNetworkType() == Constants.NETWORK_TYPE_WIFI) {
+ RealTimeThreadPool.getInstance().execute(new LogUpLoadTask());
+ }
+ }
+ }
+ };
+
+ class SpeedTestTask implements Runnable {
+
+ public void run() {
+ ArrayList<DomainModel> list = dnsCacheManager.getAllMemoryCache();
+ updateSpeedInfo(list);
+ }
+
+ private void updateSpeedInfo(ArrayList<DomainModel> list) {
+ for (DomainModel domainModel : list) {
+ ArrayList<IpModel> ipArray = domainModel.ipModelArr;
+ if (ipArray == null || ipArray.size() < 1) {
+ continue;
+ }
+ for (IpModel ipModel : ipArray) {
+ int rtt = speedtestManager.speedTest(ipModel.ip, domainModel.domain);
+ boolean succ = rtt > SpeedtestManager.OCUR_ERROR;
+ if (succ) {
+ ipModel.rtt = String.valueOf(rtt);
+ ipModel.success_num = String.valueOf((Integer.valueOf(ipModel.success_num) + 1));
+ ipModel.finally_success_time = String.valueOf(System.currentTimeMillis());
+ } else {
+ ipModel.rtt = String.valueOf(SpeedtestManager.MAX_OVERTIME_RTT);
+ ipModel.err_num = String.valueOf((Integer.valueOf(ipModel.err_num) + 1));
+ ipModel.finally_fail_time = String.valueOf(System.currentTimeMillis());
+ }
+ }
+ scoreManager.serverIpScore(domainModel);
+ dnsCacheManager.setSpeedInfo(ipArray);
+ }
+ }
+ }
+
+ class LogUpLoadTask implements Runnable {
+ public void run() {
+ File logFile = HttpDnsLogManager.getInstance().getLogFile();
+ if (null == logFile || !logFile.exists()) {
+ return;
+ }
+ boolean succ = false;
+ // upload
+ try {
+ succ = ApacheHttpClientNetworkRequests.upLoadFile(HttpDnsLogManager.LOG_UPLOAD_API, logFile);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ // succ
+ if (succ) {
+ logFile.delete();
+ }
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 网络环境发生变化 刷新缓存数据 暂时先不需要 预处理逻辑。 用户直接请求的时候会更新数据。 (会有一次走本地dns ,
+ * 后期优化这个方法,主动请求缓存的数据)
+ *
+ * @param networkInfo
+ */
+ public void onNetworkStatusChanged(NetworkInfo networkInfo) {
+ if (null != dnsCacheManager) {
+ dnsCacheManager.clearMemoryCache();
+ }
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+}
--- /dev/null
+package com.sina.util.dnscache;
+
+import java.util.ArrayList;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONStringer;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import com.sina.util.dnscache.cache.DnsCacheManager;
+import com.sina.util.dnscache.dnsp.DnsConfig;
+import com.sina.util.dnscache.log.HttpDnsLogManager;
+import com.sina.util.dnscache.net.ApacheHttpClientNetworkRequests;
+import com.sina.util.dnscache.net.INetworkRequests;
+import com.sina.util.dnscache.score.PlugInManager;
+import com.sina.util.dnscache.score.ScoreManager;
+import com.sina.util.dnscache.speedtest.SpeedtestManager;
+
+/**
+ *
+ * 项目名称: DNSCache <br>
+ * 类名称: DNSCacheConfig <br>
+ * 类描述: Lib库全局 配置文件 <br>
+ * 创建人: fenglei <br>
+ * 创建时间: 2015-4-21 下午5:26:04 <br>
+ *
+ * 修改人: <br>
+ * 修改时间: <br>
+ * 修改备注: <br>
+ *
+ * @version V1.0
+ */
+public class DNSCacheConfig {
+
+ /**
+ * 调试 开关
+ */
+ public static boolean DEBUG = true;
+
+ /**
+ * 是否启用云端更新配置策略
+ */
+ private static final boolean ENABLE_UPDATE_CONFIG = false;
+
+ /**
+ * 配置文件更新地址
+ */
+ private static String ConfigText_API = "http://202.108.7.153/config";
+
+ public static ArrayList<String> domainSupportList = new ArrayList<String>();
+
+ /**
+ * 设置 动态更新配置参数服务器url连接
+ */
+ public static void SetConfigApiUrl(String url) {
+ DNSCacheConfig.ConfigText_API = url;
+ }
+
+ /**
+ * 初始化 配置文件。 步骤:1.获取本地缓存文件,若没有则创建默认配置
+ *
+ * @param ctx
+ */
+ public static void InitCfg(final Context ctx) {
+ SharedPreferences sharedPreferences = ctx.getSharedPreferences("HttpDNSConstantsJson", Context.MODE_PRIVATE); // 私有数据
+ Data data = null;
+ try {
+
+ String text = sharedPreferences.getString("ConfigText", "" );
+
+ if (text == null || text.equals("")) {
+ Tools.log("TAG_NET", "text = " + text);
+ data = Data.createDefault();
+ saveLocalConfigAndSync(ctx, data);
+ }else{
+ data = Data.fromJson(text);
+ syncConfig(data);
+ }
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ // 上报错误
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putString("ConfigText", "");
+ boolean is = editor.commit();
+ if (is)
+ InitCfg(ctx);
+ }
+ pullConfigFromServer(ctx);
+ }
+
+ /**
+ * 同步各模块配置项
+ *
+ * @param data
+ */
+ private static void syncConfig(Data data) {
+
+ if (null != data) {
+ DNSCache.timer_interval = Integer.valueOf(data.SCHEDULE_TIMER_INTERVAL);
+ SpeedtestManager.time_interval = Integer.valueOf(data.SCHEDULE_SPEED_INTERVAL);
+ HttpDnsLogManager.time_interval = Integer.valueOf(data.SCHEDULE_LOG_INTERVAL);
+ HttpDnsLogManager.sample_rate = Integer.valueOf(data.HTTPDNS_LOG_SAMPLE_RATE);
+ DnsCacheManager.ip_overdue_delay = Integer.valueOf(data.IP_OVERDUE_DELAY);
+ DNSCache.isEnable = data.HTTPDNS_SWITCH.equals("1") ? true : false;
+
+ DnsConfig.enableSinaHttpDns = data.IS_MY_HTTP_SERVER.equals("1") == true;
+ DnsConfig.enableDnsPod = data.IS_DNSPOD_SERVER.equals("1") == true;
+ DnsConfig.enableUdpDns = data.IS_UDPDNS_SERVER.equals("1") == true;
+ DnsConfig.DNSPOD_SERVER_API = data.DNSPOD_SERVER_API;
+ DnsConfig.UDPDNS_SERVER_API = data.UDPDNS_SERVER_API;
+
+ //
+ ScoreManager.IS_SORT = data.IS_SORT.equals("1") == true;
+
+ String SPEEDTEST_PLUGIN_NUM = data.SPEEDTEST_PLUGIN_NUM;
+ if (isNum(SPEEDTEST_PLUGIN_NUM)) {
+ PlugInManager.SpeedTestPluginNum = Float.valueOf(SPEEDTEST_PLUGIN_NUM);
+ }
+ String PRIORITY_PLUGIN_NUM = data.PRIORITY_PLUGIN_NUM;
+ if (isNum(PRIORITY_PLUGIN_NUM)) {
+ PlugInManager.PriorityPluginNum = Float.valueOf(PRIORITY_PLUGIN_NUM);
+ }
+ String SUCCESSNUM_PLUGIN_NUM = data.SUCCESSNUM_PLUGIN_NUM;
+ if (isNum(SUCCESSNUM_PLUGIN_NUM)) {
+ PlugInManager.SuccessNumPluginNum = Float.valueOf(SUCCESSNUM_PLUGIN_NUM);
+ }
+ String ERRNUM_PLUGIN_NUM = data.ERRNUM_PLUGIN_NUM;
+ if (isNum(ERRNUM_PLUGIN_NUM)) {
+ PlugInManager.ErrNumPluginNum = Float.valueOf(ERRNUM_PLUGIN_NUM);
+ }
+ String SUCCESSTIME_PLUGIN_NUM = data.SUCCESSTIME_PLUGIN_NUM;
+ if (isNum(SUCCESSTIME_PLUGIN_NUM)) {
+ PlugInManager.SuccessTimePluginNum = Float.valueOf(SUCCESSTIME_PLUGIN_NUM);
+ }
+
+ // arraylist
+ domainSupportList.clear();
+ DnsConfig.SINA_HTTPDNS_SERVER_API.clear();
+
+ domainSupportList.addAll(data.DOMAIN_SUPPORT_LIST);
+ DnsConfig.SINA_HTTPDNS_SERVER_API.addAll(data.HTTPDNS_SERVER_API);
+ }
+ }
+
+ /**
+ * 更新配置文件
+ */
+ private static void pullConfigFromServer(final Context ctx) {
+ if (!ENABLE_UPDATE_CONFIG || ConfigText_API == null || ConfigText_API.equals("")){
+ return;
+ }
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ INetworkRequests netWork = new ApacheHttpClientNetworkRequests();
+ String url = ConfigText_API + "?k=" + AppConfigUtil.getAppKey() + "&v=" + AppConfigUtil.getVersionName();
+ String responseStr = netWork.requests(url);
+// responseStr = createMockJsonStr();
+ Data data = Data.fromJson(responseStr);
+ if (null != data) {
+ saveLocalConfigAndSync(ctx, data);
+ }
+ HttpDnsLogManager.getInstance().writeLog(HttpDnsLogManager.TYPE_INFO, HttpDnsLogManager.ACTION_INFO_CONFIG, responseStr);
+ } catch (Exception e) {
+ String message = e.toString();
+ JSONStringer stringer = new JSONStringer();
+ try {
+ stringer.object()//
+ .key("errorMsg").value(message)//
+ .endObject();
+ } catch (JSONException e1) {
+ e1.printStackTrace();
+ }
+ HttpDnsLogManager.getInstance().writeLog(HttpDnsLogManager.TYPE_ERROR, HttpDnsLogManager.ACTION_INFO_CONFIG, stringer.toString());
+ }
+ }
+ }).start();
+ }
+
+ /**
+ * 保存本地配置信息。
+ *
+ * @param ctx
+ * @param configStr
+ */
+ public static void saveLocalConfigAndSync(Context ctx, Data model) {
+ if (null != ctx && null != model) {
+ SharedPreferences sharedPreferences = ctx.getSharedPreferences("HttpDNSConstantsJson", Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putString("ConfigText", model.toJson());
+ editor.commit();
+ syncConfig(model);
+ Data.Instance = null ;
+ }
+ }
+
+ /**
+ * 获取本地配置信息。
+ *
+ * @param ctx
+ * @param configStr
+ */
+ private static Data getLocalConfig() {
+ SharedPreferences sharedPreferences = AppConfigUtil.getApplicationContext().getSharedPreferences("HttpDNSConstantsJson",
+ Context.MODE_PRIVATE);
+ String json = sharedPreferences.getString("ConfigText", "");
+ Data data = Data.fromJson(json);
+ if (null == data) {
+ data = Data.createDefault();
+ }
+ return data;
+ }
+
+ /**
+ * 是否为数字
+ *
+ * @param str
+ * @return
+ */
+ private static boolean isNum(String str) {
+ return str.matches("^[-+]?(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)$");
+ }
+
+ public static class Data {
+
+ public static Data Instance = null;
+ public static Data getInstance(){
+ if( Instance == null ){
+ Instance = DNSCacheConfig.getLocalConfig() ;
+ }
+ return Instance ;
+ }
+
+ /**
+ * 是否启用udpdns服务器 默认不启用 | 1启用 0不启用
+ */
+ public String IS_UDPDNS_SERVER = "";
+ /**
+ * udp dnsserver的地址
+ */
+ public String UDPDNS_SERVER_API = "";
+ /**
+ * 日志采样率
+ */
+ public String HTTPDNS_LOG_SAMPLE_RATE = "";
+ /**
+ * lib库开关
+ */
+ public String HTTPDNS_SWITCH = "";
+ /**
+ * 测速间隔时间
+ */
+ public String SCHEDULE_SPEED_INTERVAL = "";
+ /**
+ * 日志上传的间隔时间
+ */
+ public String SCHEDULE_LOG_INTERVAL = "";
+ /**
+ * timer轮询器的间隔时间
+ */
+ public String SCHEDULE_TIMER_INTERVAL = "";
+ /**
+ * ip数据过期延迟差值
+ */
+ public String IP_OVERDUE_DELAY = "";
+ /**************************************以上部分是新加配置,共8个********************************************/
+ /**
+ * 是否启用自己家的HTTP_DNS服务器 默认不启用 | 1启用 0不启用
+ */
+ public String IS_MY_HTTP_SERVER = null;
+ /**
+ * 自己家HTTP_DNS服务API地址 使用时直接在字符串后面拼接domain地址 |
+ * 示例(http://202.108.7.153/dns?domain=)+ domain
+ */
+ public ArrayList<String> HTTPDNS_SERVER_API = new ArrayList<String>();
+ /**
+ * 是否启用dnspod服务器 默认不启用 | 1启用 0不启用
+ */
+ public String IS_DNSPOD_SERVER = null;
+ /**
+ * DNSPOD HTTP_DNS 服务器API地址 | 默认(http://119.29.29.29/d?ttl=1&dn=)
+ */
+ public String DNSPOD_SERVER_API = null;
+ /**
+ * DNSPOD 企业级ID配置选项
+ */
+ public String DNSPOD_ID = null;
+ /**
+ * DNSPOD 企业级KEY配置选项
+ */
+ public String DNSPOD_KEY = null;
+
+ /**
+ * 是否开启 本地排序插件算法 默认开启 | 1开启 0不开启
+ */
+ public String IS_SORT = null;
+ /**
+ * 速度插件 比重分配值:默认40%
+ */
+ public String SPEEDTEST_PLUGIN_NUM = null;
+ /**
+ * 服务器推荐优先级插件 比重分配:默认30% (需要自家HTTP_DNS服务器支持)
+ */
+ public String PRIORITY_PLUGIN_NUM = null;
+ /**
+ * 历史成功次数计算插件 比重分配:默认10%
+ */
+ public String SUCCESSNUM_PLUGIN_NUM = null;
+ /**
+ * 历史错误次数计算插件 比重分配:默认10%
+ */
+ public String ERRNUM_PLUGIN_NUM = null;
+ /**
+ * 最后一次成功时间计算插件 比重分配:默认10%
+ */
+ public String SUCCESSTIME_PLUGIN_NUM = null;
+ /**
+ * 白名单
+ */
+ public ArrayList<String> DOMAIN_SUPPORT_LIST = new ArrayList<String>();
+
+ /**
+ * 返回配置文件 json
+ */
+ public String toJson() {
+ // 为了节约lib库的大小直接拼接 json 字符串吧,就不适用第三方库了
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("{");
+ buffer.append("\"IS_UDPDNS_SERVER\":" + "\"" + IS_UDPDNS_SERVER + "\",");
+ buffer.append("\"UDPDNS_SERVER_API\":" + "\"" + UDPDNS_SERVER_API + "\",");
+ buffer.append("\"HTTPDNS_LOG_SAMPLE_RATE\":" + "\"" + HTTPDNS_LOG_SAMPLE_RATE + "\",");
+ buffer.append("\"HTTPDNS_SWITCH\":" + "\"" + HTTPDNS_SWITCH + "\",");
+ buffer.append("\"SCHEDULE_LOG_INTERVAL\":" + "\"" + SCHEDULE_LOG_INTERVAL + "\",");
+ buffer.append("\"SCHEDULE_SPEED_INTERVAL\":" + "\"" + SCHEDULE_SPEED_INTERVAL + "\",");
+ buffer.append("\"SCHEDULE_TIMER_INTERVAL\":" + "\"" + SCHEDULE_TIMER_INTERVAL + "\",");
+ buffer.append("\"IP_OVERDUE_DELAY\":" + "\"" + IP_OVERDUE_DELAY + "\",");
+ buffer.append("\"IS_MY_HTTP_SERVER\":" + "\"" + IS_MY_HTTP_SERVER + "\",");
+ buffer.append("\"IS_DNSPOD_SERVER\":" + "\"" + IS_DNSPOD_SERVER + "\",");
+ buffer.append("\"DNSPOD_SERVER_API\":" + "\"" + DNSPOD_SERVER_API + "\",");
+ // 测试阶段暂时先把 dnspod的ID和KEY加上
+ buffer.append("\"DNSPOD_ID\":" + "\"" + DNSPOD_ID + "\",");
+ buffer.append("\"DNSPOD_KEY\":" + "\"" + DNSPOD_KEY + "\",");
+ buffer.append("\"IS_SORT\":" + "\"" + IS_SORT + "\",");
+ buffer.append("\"SPEEDTEST_PLUGIN_NUM\":" + "\"" + SPEEDTEST_PLUGIN_NUM + "\",");
+ buffer.append("\"PRIORITY_PLUGIN_NUM\":" + "\"" + PRIORITY_PLUGIN_NUM + "\",");
+ buffer.append("\"SUCCESSNUM_PLUGIN_NUM\":" + "\"" + SUCCESSNUM_PLUGIN_NUM + "\",");
+ buffer.append("\"ERRNUM_PLUGIN_NUM\":" + "\"" + ERRNUM_PLUGIN_NUM + "\",");
+ buffer.append("\"SUCCESSTIME_PLUGIN_NUM\":" + "\"" + SUCCESSTIME_PLUGIN_NUM + "\",");
+ buffer.append("\"DOMAIN_SUPPORT_LIST\":" + "[");
+ for (int i = 0; i < DOMAIN_SUPPORT_LIST.size(); i++) {
+ buffer.append("\"" + DOMAIN_SUPPORT_LIST.get(i) + "\"" + (i != DOMAIN_SUPPORT_LIST.size() - 1 ? "," : ""));
+ }
+ buffer.append("]");
+ buffer.append(",");
+ buffer.append("\"HTTPDNS_SERVER_API\":" + "[");
+ for (int i = 0; i < HTTPDNS_SERVER_API.size(); i++) {
+ buffer.append("\"" + HTTPDNS_SERVER_API.get(i) + "\"" + (i != HTTPDNS_SERVER_API.size() - 1 ? "," : ""));
+ }
+ buffer.append("]");
+ buffer.append("}");
+ return buffer.toString();
+ }
+
+ public static Data createDefault() {
+ Data model = new Data();
+ model.HTTPDNS_LOG_SAMPLE_RATE = "50";
+ model.HTTPDNS_SWITCH = "1";
+ model.SCHEDULE_LOG_INTERVAL = "3600000";
+ model.SCHEDULE_SPEED_INTERVAL = "60000";
+ model.SCHEDULE_TIMER_INTERVAL = "60000";
+ model.IP_OVERDUE_DELAY = "60";
+
+ model.IS_MY_HTTP_SERVER = "0";
+ model.HTTPDNS_SERVER_API.add("http://xxx/dns?domain=");
+
+ model.IS_DNSPOD_SERVER = "1";
+ model.DNSPOD_SERVER_API = "http://119.29.29.29/d?ttl=1&dn=";
+ model.DNSPOD_ID = "";
+ model.DNSPOD_KEY = "";
+
+ model.IS_UDPDNS_SERVER = "1";
+ model.UDPDNS_SERVER_API = "114.114.114.114";
+
+ model.IS_SORT = "1";
+ model.SPEEDTEST_PLUGIN_NUM = "50";
+ model.PRIORITY_PLUGIN_NUM = "50";
+ model.SUCCESSNUM_PLUGIN_NUM = "10";
+ model.ERRNUM_PLUGIN_NUM = "10";
+ model.SUCCESSTIME_PLUGIN_NUM = "10";
+
+ return model;
+ }
+
+ public static Data fromJson(String json) {
+ Data model = createDefault();
+ try {
+ JSONObject jsonObj = new JSONObject(json);
+ //new
+ if (jsonObj.isNull("HTTPDNS_LOG_SAMPLE_RATE") == false) {
+ model.HTTPDNS_LOG_SAMPLE_RATE = jsonObj.getString("HTTPDNS_LOG_SAMPLE_RATE");
+ }
+ if (jsonObj.isNull("HTTPDNS_SWITCH") == false) {
+ model.HTTPDNS_SWITCH = jsonObj.getString("HTTPDNS_SWITCH");
+ }
+ if (jsonObj.isNull("SCHEDULE_LOG_INTERVAL") == false) {
+ model.SCHEDULE_LOG_INTERVAL = jsonObj.getString("SCHEDULE_LOG_INTERVAL");
+ }
+ if (jsonObj.isNull("SCHEDULE_SPEED_INTERVAL") == false) {
+ model.SCHEDULE_SPEED_INTERVAL = jsonObj.getString("SCHEDULE_SPEED_INTERVAL");
+ }
+ if (jsonObj.isNull("SCHEDULE_TIMER_INTERVAL") == false) {
+ model.SCHEDULE_TIMER_INTERVAL = jsonObj.getString("SCHEDULE_TIMER_INTERVAL");
+ }
+ if (jsonObj.isNull("IP_OVERDUE_DELAY") == false) {
+ model.IP_OVERDUE_DELAY = jsonObj.getString("IP_OVERDUE_DELAY");
+ }
+ if (jsonObj.isNull("IS_UDPDNS_SERVER") == false) {
+ model.IS_UDPDNS_SERVER = jsonObj.getString("IS_UDPDNS_SERVER");
+ }
+ if (jsonObj.isNull("UDPDNS_SERVER_API") == false) {
+ model.UDPDNS_SERVER_API = jsonObj.getString("UDPDNS_SERVER_API");
+ }
+ //----------------------------------------
+ // httpdns
+ if (jsonObj.isNull("IS_MY_HTTP_SERVER") == false) {
+ model.IS_MY_HTTP_SERVER = jsonObj.getString("IS_MY_HTTP_SERVER");
+ }
+ // dnspod
+ if (jsonObj.isNull("IS_DNSPOD_SERVER") == false) {
+ model.IS_DNSPOD_SERVER = jsonObj.getString("IS_DNSPOD_SERVER");
+ }
+
+ if (jsonObj.isNull("DNSPOD_SERVER_API") == false) {
+ model.DNSPOD_SERVER_API = jsonObj.getString("DNSPOD_SERVER_API");
+ }
+ if (jsonObj.isNull("DNSPOD_ID") == false) {
+ model.DNSPOD_ID = jsonObj.getString("DNSPOD_ID");
+ }
+ if (jsonObj.isNull("DNSPOD_KEY") == false) {
+ model.DNSPOD_KEY = jsonObj.getString("DNSPOD_KEY");
+ }
+
+ // sort
+ if (jsonObj.isNull("IS_SORT") == false) {
+ String IS_SORT = jsonObj.getString("IS_SORT");
+ model.IS_SORT = IS_SORT;
+ }
+ if (jsonObj.isNull("SPEEDTEST_PLUGIN_NUM") == false) {
+ model.SPEEDTEST_PLUGIN_NUM = jsonObj.getString("SPEEDTEST_PLUGIN_NUM");
+ }
+ if (jsonObj.isNull("PRIORITY_PLUGIN_NUM") == false) {
+ model.PRIORITY_PLUGIN_NUM = jsonObj.getString("PRIORITY_PLUGIN_NUM");
+ }
+ if (jsonObj.isNull("SUCCESSNUM_PLUGIN_NUM") == false) {
+ model.SUCCESSNUM_PLUGIN_NUM = jsonObj.getString("SUCCESSNUM_PLUGIN_NUM");
+ }
+ if (jsonObj.isNull("ERRNUM_PLUGIN_NUM") == false) {
+ model.ERRNUM_PLUGIN_NUM = jsonObj.getString("ERRNUM_PLUGIN_NUM");
+ }
+ if (jsonObj.isNull("SUCCESSTIME_PLUGIN_NUM") == false) {
+ model.SUCCESSTIME_PLUGIN_NUM = jsonObj.getString("SUCCESSTIME_PLUGIN_NUM");
+ }
+
+ // 白名单
+ model.DOMAIN_SUPPORT_LIST.clear();
+ if (jsonObj.isNull("DOMAIN_SUPPORT_LIST") == false) {
+ JSONArray jsonArr = jsonObj.getJSONArray("DOMAIN_SUPPORT_LIST");
+ for (int i = 0; i < jsonArr.length(); i++) {
+ String temp = jsonArr.getString(i);
+ model.DOMAIN_SUPPORT_LIST.add(temp);
+ }
+ }
+
+ // 新浪httpdns服务地址
+ model.HTTPDNS_SERVER_API.clear();
+ if (jsonObj.isNull("HTTPDNS_SERVER_API") == false) {
+ JSONArray jsonArr = jsonObj.getJSONArray("HTTPDNS_SERVER_API");
+ for (int i = 0; i < jsonArr.length(); i++) {
+ String temp = jsonArr.getString(i);
+ model.HTTPDNS_SERVER_API.add(temp);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ model = null;
+ }
+ return model;
+ }
+ }
+ //FOR TEST !!!
+ static String createMockJsonStr() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("{");
+ buffer.append("\"HTTPDNS_LOG_SAMPLE_RATE\":" + "\"" + 10 + "\",");
+ buffer.append("\"HTTPDNS_SWITCH\":" + "\"" + 1 + "\",");
+ buffer.append("\"SCHEDULE_LOG_INTERVAL\":" + "\"" + 60 * 60 * 1000 + "\",");
+ buffer.append("\"SCHEDULE_SPEED_INTERVAL\":" + "\"" + 10 * 1000 + "\",");
+ buffer.append("\"SCHEDULE_TIMER_INTERVAL\":" + "\"" + 10 * 1000 + "\",");
+ buffer.append("\"IS_MY_HTTP_SERVER\":" + "\"" + 1 + "\",");
+ buffer.append("\"IS_SORT\":" + "\"" + 1 + "\",");
+ buffer.append("\"SPEEDTEST_PLUGIN_NUM\":" + "\"" + 50 + "\",");
+ buffer.append("\"PRIORITY_PLUGIN_NUM\":" + "\"" + 50 + "\",");
+
+ ArrayList<String> whiteList = new ArrayList<String>();
+ whiteList.add("api.camera.weibo.com");
+ whiteList.add("ww4.sinaimg.cn");
+ whiteList.add("api.weibo.cn");
+ whiteList.add("m.weibo.cn");
+ buffer.append("\"DOMAIN_SUPPORT_LIST\":" + "[");
+ for (int i = 0; i < whiteList.size(); i++) {
+ buffer.append("\"" + whiteList.get(i) + "\"" + (i != whiteList.size() - 1 ? "," : ""));
+ }
+ buffer.append("]");
+ buffer.append(",");
+ buffer.append("\"HTTPDNS_SERVER_API\":" + "[");
+ for (int i = 0; i < 1; i++) {
+ buffer.append("\"" + "http://202.108.7.153/dns?domain=" + "\"");
+ }
+ buffer.append("]");
+ buffer.append("}");
+ return buffer.toString();
+ }
+}
--- /dev/null
+package com.sina.util.dnscache;
+
+
+/**
+*
+* 项目名称: DNSCache <br>
+* 类名称: DomainInfo <br>
+* 类描述: 为使用者封装的数据模型 <br>
+* 创建人: fenglei <br>
+* 创建时间: 2015-4-21 下午5:26:04 <br>
+*
+* 修改人: <br>
+* 修改时间: <br>
+* 修改备注: <br>
+*
+* @version V1.0
+*/
+public class DomainInfo {
+
+ /**
+ * 工场方法
+ *
+ * @param ip
+ * @param url
+ * @param host
+ * @return
+ */
+ public static DomainInfo DomainInfoFactory(String ip, String url, String host){
+
+ url = Tools.getIpUrl(url, host, ip) ;
+
+ return new DomainInfo( "" , url , host);
+ }
+
+ /**
+ * 工场方法
+ * @param serverIpArray
+ * @param url
+ * @param host
+ * @return
+ */
+ public static DomainInfo[] DomainInfoFactory(String[] serverIpArray, String url, String host){
+
+ DomainInfo[] domainArr = new DomainInfo[serverIpArray.length];
+
+ for( int i = 0 ; i < serverIpArray.length ; i++ ){
+
+ domainArr[i] = DomainInfoFactory( serverIpArray[i], url , host );
+ }
+
+ return domainArr ;
+ }
+
+
+ /**
+ * 构造函数
+ * @param id
+ * @param url
+ * @param host
+ */
+ public DomainInfo(String id, String url, String host){
+
+ this.id = id ;
+ this.url = url ;
+ this.host = host ;
+
+ this.startTime = String.valueOf( System.currentTimeMillis() );
+ }
+
+ /**
+ * id
+ */
+ public String id = null;
+
+ /**
+ * 可以直接使用的url 已经替换了host为ip
+ */
+ public String url = null;
+
+ /**
+ * 需要设置到 http head 里面的主机头
+ */
+ public String host = "";
+
+
+
+ /**
+ * 返回的内容体
+ */
+ public String data = null ;
+
+
+ /**
+ * 开始请求的时间
+ */
+ public String startTime = null ;
+
+
+ /**
+ * 请求结束的时间 请求超时 结束时间为null
+ */
+ public String stopTime = null ;
+
+
+ /**
+ * 请求的状态值 200 \ 404 \ 500 等
+ */
+ public String code = null ;
+
+
+
+
+ /**
+ * 返回 url 信息
+ * @return
+ */
+ public String toString(){
+
+ String str = "DomainInfo: \n" ;
+ str += "id = " + id + "\n" ;
+ str += "url = " + url + "\n" ;
+ str += "host = " + host + "\n" ;
+ str += "data = " + data + "\n" ;
+ str += "startTime = " + startTime + "\n" ;
+ str += "stopTime = " + stopTime + "\n" ;
+ str += "code = " + code + "\n" ;
+
+ return str ;
+ }
+
+
+}
--- /dev/null
+package com.sina.util.dnscache;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.ListIterator;
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.json.JSONException;
+import org.json.JSONStringer;
+
+import android.annotation.SuppressLint;
+import android.util.Log;
+
+import com.sina.util.dnscache.model.IpModel;
+
+/**
+*
+* 项目名称: DNSCache <br>
+* 类名称: Tools <br>
+* 类描述: 一些常用的小方法 <br>
+* 创建人: fenglei <br>
+* 创建时间: 2015-4-21 下午5:26:04 <br>
+*
+* 修改人: <br>
+* 修改时间: <br>
+* 修改备注: <br>
+*
+* @version V1.0
+*/
+public class Tools {
+
+ /**
+ * 从 url 中截取 domain
+ * @param url
+ * @return
+ */
+ public static String getHostName(String url){
+
+ if (url == null)
+ return "";
+
+ url = url.trim();
+ String host = url.toLowerCase();
+ int end;
+
+ if (host.startsWith("http://")) {
+ end = url.indexOf("/", 8);
+ if (end > 7) {
+ host = url.substring(7, end);
+ } else {
+ host = url.substring(7);
+ }
+
+ } else if (host.startsWith("https://")) {
+ end = url.indexOf("/", 9);
+ if (end > 8) {
+ host = url.substring(8, end);
+ } else {
+ host = url.substring(8);
+ }
+ } else {
+ end = url.indexOf("/", 1);
+ if (end > 1) {
+ host = url.substring(0, url.indexOf("/", 1));
+ } else {
+ host = url;
+ }
+ }
+
+ return host;
+ }
+
+
+ /**
+ * 转换url 主机头为ip地址
+ * @param url 原url
+ * @param host 主机头
+ * @param ip 服务器ip
+ * @return
+ */
+ public static String getIpUrl(String url, String host, String ip ){
+
+ if( url == null ){
+ Tools.log("TAG", "URL NULL") ;
+ }
+ if( host == null ){
+ Tools.log("TAG", "host NULL") ;
+ }
+ if( ip == null ){
+ Tools.log("TAG", "ip NULL") ;
+ }
+
+ if( url == null || host == null || ip == null ) return url ;
+
+ String ipUrl = url.replaceFirst(host, ip);
+
+ return ipUrl ;
+ }
+
+
+
+// /**
+// * 将ip转换成整形
+// */
+// public static long parseIpAddress(String ipAddress) {
+// if (ipAddress == null || ipAddress.equals("0") || TextUtils.isEmpty(ipAddress)) {
+// return 0;
+// }
+// ipAddress = ipAddress.trim();
+// long[] ip = new long[4];
+// // 先找到IP地址字符串中.的位置
+// int position1 = ipAddress.indexOf(".");
+// int position2 = ipAddress.indexOf(".", position1 + 1);
+// int position3 = ipAddress.indexOf(".", position2 + 1);
+// // 将每个.之间的字符串转换成整型
+// try {
+// ip[0] = Long.parseLong(ipAddress.substring(0, position1));
+// ip[1] = Long.parseLong(ipAddress.substring(position1 + 1, position2));
+// ip[2] = Long.parseLong(ipAddress.substring(position2 + 1, position3));
+// ip[3] = Long.parseLong(ipAddress.substring(position3 + 1));
+// } catch (NumberFormatException e) {
+//
+// }
+// return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
+// }
+//
+// /**
+// * 将整形ip转成成字符串ip地址
+// * @param longIp
+// * @return
+// */
+// public static String longToIP(long longIp) {
+// StringBuffer sb = new StringBuffer("");
+// // 直接右移24位
+// sb.append(String.valueOf((longIp >>> 24)));
+// sb.append(".");
+// // 将高8位置0,然后右移16位
+// sb.append(String.valueOf((longIp & 0x00FFFFFF) >>> 16));
+// sb.append(".");
+// // 将高16位置0,然后右移8位
+// sb.append(String.valueOf((longIp & 0x0000FFFF) >>> 8));
+// sb.append(".");
+// // 将高24位置0
+// sb.append(String.valueOf((longIp & 0x000000FF)));
+// return sb.toString();
+// }
+
+
+ @SuppressLint("SimpleDateFormat")
+ public static String getStringDateShort(long time) {
+ Date currentTime = new Date(time);
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String dateString = formatter.format(currentTime);
+ return dateString;
+ }
+
+ public static String getStringDateShort(String time) {
+ return getStringDateShort( Long.valueOf(time) );
+ }
+
+ public static void log( String tag, String msg ){
+ if( DNSCacheConfig.DEBUG == false ) return ;
+ Log.d(tag, msg) ;
+ }
+ /**
+ * 随机排序算法
+ * @param list
+ * @return
+ */
+ public static void randomSort(ArrayList<IpModel> list) {
+ ArrayList<IpModel> temp = new ArrayList<IpModel>();
+ temp.addAll(list);
+ int count = temp.size();
+ IpModel[] array = new IpModel[count];
+ Random rand = new Random();
+ for (int i = 0; i < count; i++) {
+ int num = rand.nextInt(count - i);
+ array[i] = temp.remove(num);
+ }
+ int i = 0;
+ // 下面这种写法,是为了不引起list的并发异常
+ ListIterator<IpModel> it = list.listIterator();
+ while (it.hasNext()) {
+ it.next();
+ it.set(array[i++]);
+ }
+ }
+
+ public String generateJsonStrFromMap(HashMap<String, String> map) {
+ JSONStringer jsonStringer = new JSONStringer();
+ try {
+ jsonStringer = jsonStringer.object();
+ Set<Entry<String, String>> entrySet = map.entrySet();
+ for (Entry<String, String> entry : entrySet) {
+ jsonStringer = jsonStringer.key(entry.getKey()).value(entry.getValue());
+ }
+ jsonStringer = jsonStringer.endObject();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return "{}";
+ }
+ return jsonStringer.toString();
+ }
+ /**
+ * 判断该host是否是为 ipv4 格式。
+ * @param host 支持加端口验证
+ * @return
+ */
+ public static boolean isIPV4(String host) {
+ long begin = System.currentTimeMillis();
+ host = host.trim();
+ if (host.contains(":")) {
+ String[] array = host.split(":");
+ if (null != array && array.length == 2) {
+ host = array[0];
+ host = host.trim();
+ }
+ } else {
+ if (null == host || host.length() < 7 || host.length() > 15 || "".equals(host)) {
+ return false;
+ }
+ }
+ String rexp = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\." //
+ + "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." //
+ + "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."//
+ + "(00?\\d|1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";
+ Pattern pat = Pattern.compile(rexp);
+ Matcher mat = pat.matcher(host);
+ boolean ipAddress = mat.find();
+ long end = System.currentTimeMillis();
+ Tools.log("Tools:", "regular time spend : " + (end - begin) + "ms");
+ return ipAddress;
+ }
+
+}
--- /dev/null
+package com.sina.util.dnscache.cache;
+
+
+/**
+ *
+ * 项目名称: DNSCache <br>
+ * 类名称: DBConstants <br>
+ * 类描述: 数据库名、表明、列明 相关常量定义 <br>
+ * 创建人: fenglei <br>
+ * 创建时间: 2015-3-26 下午3:54:59 <br>
+ *
+ * 修改人: <br>
+ * 修改时间: <br>
+ * 修改备注: <br>
+ *
+ * @version V1.0
+ */
+public interface DBConstants {
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * db 数据库名字
+ */
+ public static final String DATABASE_NAME = "dns_ip_info.db" ;
+ /**
+ * db 版本
+ */
+ public static final int DATABASE_VERSION = 4 ;
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+ /**
+ * domain表名称、列名定义
+ */
+ public static final String TABLE_NAME_DOMAIN = "domain" ;
+ /**
+ * domain 自增id
+ */
+ public static final String DOMAIN_COLUMN_ID = "id";
+ /**
+ * 域名
+ */
+ public static final String DOMAIN_COLUMN_DOMAIN = "domain" ;
+ /**
+ * 运营商
+ */
+ public static final String DOMAIN_COLUMN_SP = "sp" ;
+ /**
+ * 域名过期时间
+ */
+ public static final String DOMAIN_COLUMN_TTL = "ttl" ;
+ /**
+ * 最后查询时间
+ */
+ public static final String DOMAIN_COLUMN_TIME = "time" ;
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+ /**
+ * ip表名称、列名定义
+ */
+ public static final String TABLE_NAME_IP = "ip" ;
+ /**
+ * ip 自增id
+ */
+ public static final String IP_COLUMN_ID = "id" ;
+ /**
+ * domain 关联id
+ */
+ public static final String IP_COLUMN_DOMAIN_ID = "d_id" ;
+ /**
+ * 服务器 ip地址
+ */
+ public static final String IP_COLUMN_IP = "ip" ;
+ /**
+ * ip服务器对应的端口
+ */
+ public static final String IP_COLUMN_PORT = "port" ;
+ /**
+ * ip服务器对应的sp运营商
+ */
+ public static final String IP_COLUMN_SP = "sp";
+ /**
+ * ip服务器对应域名过期时间
+ */
+ public static final String IP_COLUMN_TTL = "ttl";
+ /**
+ * ip服务器优先级-排序算法策略使用
+ */
+ public static final String IP_COLUMN_PRIORITY = "priority" ;
+ /**
+ * ip服务器访问延时时间(可用ping或http发送空包实现)。单位ms
+ */
+ public static final String IP_COLUMN_RTT = "rtt" ;
+ /**
+ * ip服务器链接产生的成功数
+ */
+ public static final String IP_COLUMN_SUCCESS_NUM = "success_num" ;
+ /**
+ * ip服务器链接产生的错误数
+ */
+ public static final String IP_COLUMN_ERR_NUM = "err_num" ;
+ /**
+ * ip服务器最后成功链接时间
+ */
+ public static final String IP_COLUMN_FINALLY_SUCCESS_TIME = "finally_success_time" ;
+ /**
+ * ip服务器最后失败链接时间
+ */
+ public static final String IP_COLUMN_FINALLY_FAIL_TIME = "finally_fail_time" ;
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+ /**
+ * 链接失败表名称、列定义(主要用来上报通知异常)
+ */
+ public static final String TABLE_NAME_CONNECT_FAIL = "connect_fail" ;
+ /**
+ * 链接失败表 自曾id
+ */
+ public static final String CONNECT_FAIL_ID = "id" ;
+ /**
+ * 链接失败的ip地址
+ */
+ public static final String CONNECT_FAIL_IP = "ip" ;
+ /**
+ * 链接失败服务器的端口号
+ */
+ public static final String CONNECT_FAIL_PORT = "port" ;
+ /**
+ * 链接失败的错误代码,(一般都是http的错误代码)
+ */
+ public static final String CONNECT_FAIL_ERRCODE = "errcode" ;
+ /**
+ * 链接失败时本地网络类型
+ */
+ public static final String CONNECT_FAIL_NETWORK_TYPE = "network_type" ;
+ /**
+ * 链接失败时如果是手机运营商,则统计运营商sp—code(为了重现现场收集数据)
+ */
+ public static final String CONNECT_FAIL_SPCODE = "spcode" ;
+ /**
+ * 链接该服务器总共的错误次数
+ */
+ public static final String CONNECT_FAIL_COUNT = "count" ;
+ /**
+ * 链接该服务器最后失败时间
+ */
+ public static final String CONNECT_FAIL_FINALLY_TIME = "finally_time" ;
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * 创建 domain 表 sql 语句
+ */
+ public static final String CREATE_DOMAIN_TABLE_SQL =
+ "CREATE TABLE " + TABLE_NAME_DOMAIN + " (" +
+ DOMAIN_COLUMN_ID + " INTEGER PRIMARY KEY," +
+ DOMAIN_COLUMN_DOMAIN + " TEXT," +
+ DOMAIN_COLUMN_SP + " TEXT," +
+ DOMAIN_COLUMN_TTL + " TEXT," +
+ DOMAIN_COLUMN_TIME + " TEXT" +
+ ");";
+
+ /**
+ * 创建 ip 表 sql 语句
+ */
+ public static final String CREATE_IP_TEBLE_SQL =
+ "CREATE TABLE " + TABLE_NAME_IP + " (" +
+ IP_COLUMN_ID + " INTEGER PRIMARY KEY," +
+ IP_COLUMN_DOMAIN_ID + " INTEGER," +
+ IP_COLUMN_IP + " INTEGER," +
+ IP_COLUMN_PORT + " INTEGER," +
+ IP_COLUMN_SP + " TEXT," +
+ IP_COLUMN_TTL + " TEXT," +
+ IP_COLUMN_PRIORITY + " INTEGER," +
+ IP_COLUMN_RTT + " INTEGER," +
+ IP_COLUMN_SUCCESS_NUM + " INTEGER," +
+ IP_COLUMN_ERR_NUM + " INTEGER," +
+ IP_COLUMN_FINALLY_SUCCESS_TIME + " TEXT," +
+ IP_COLUMN_FINALLY_FAIL_TIME + " TEXT" +
+ ");";
+
+ /**
+ * 创建 connect_fail 表 sql 语句
+ */
+ public static final String CREATE_CONNECT_FAIL_TABLE_SQL =
+ "CREATE TABLE " + TABLE_NAME_CONNECT_FAIL + " (" +
+ CONNECT_FAIL_ID + " INTEGER PRIMARY KEY," +
+ CONNECT_FAIL_IP + " TEXT," +
+ CONNECT_FAIL_PORT + " INGEGER," +
+ CONNECT_FAIL_ERRCODE + " TEXT," +
+ CONNECT_FAIL_NETWORK_TYPE + " TEXT," +
+ CONNECT_FAIL_SPCODE + " TEXT," +
+ CONNECT_FAIL_COUNT + " INGEGER," +
+ CONNECT_FAIL_FINALLY_TIME + " TEXT" +
+ ");" ;
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+}
--- /dev/null
+/**
+ *
+ */
+package com.sina.util.dnscache.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import com.sina.util.dnscache.model.DomainModel;
+import com.sina.util.dnscache.model.IpModel;
+
+/**
+ *
+ * 项目名称: DNSCache <br>
+ * 类名称: DNSCacheDatabaseHelper <br>
+ * 类描述: 缓存数据库 创建、更新、删除、增删改查相关操作 <br>
+ * 创建人: fenglei <br>
+ * 创建时间: 2015-3-26 下午4:04:23 <br>
+ *
+ * 修改人: <br>
+ * 修改时间: <br>
+ * 修改备注: <br>
+ *
+ * @version V1.0
+ */
+public class DNSCacheDatabaseHelper extends SQLiteOpenHelper implements DBConstants{
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 资源锁
+ */
+ private final static byte synLock[] = new byte[1];
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 构造函数
+ * @param context
+ */
+ public DNSCacheDatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ // TODO Auto-generated constructor stub
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 创建数据库
+ *
+ * 残酷的现实告诉我们,创建多个表时,要分开多次执行db.execSQL方法!!
+ */
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ // TODO Auto-generated method stub
+ //Log.d("DB", "onCreate") ;
+ db.execSQL(CREATE_DOMAIN_TABLE_SQL);
+ db.execSQL(CREATE_IP_TEBLE_SQL);
+ db.execSQL(CREATE_CONNECT_FAIL_TABLE_SQL);
+ }
+
+ /**
+ * 数据库版本更新策略(直接放弃旧表)
+ */
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // TODO Auto-generated method stub
+ //Log.d("DB", "onUpgrade") ;
+ if (oldVersion != newVersion) {
+ // 其它情况,直接放弃旧表.
+ db.beginTransaction();
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_DOMAIN + ";");
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_IP + ";");
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME_CONNECT_FAIL + ";");
+ db.setTransactionSuccessful();
+ db.endTransaction();
+ onCreate(db);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 添加一条新的记录 。如果域名重复删除旧数据。
+ *
+ * @param url
+ * @param sp
+ * @param model
+ * @return
+ */
+ public DomainModel addDomainModel(String url, String sp, DomainModel model) {
+ synchronized (synLock) {
+ // 过滤重复数据
+ ArrayList<DomainModel> domainList = (ArrayList<DomainModel>) QueryDomainInfo(model.domain, model.sp);
+ if (domainList != null && domainList.size() > 0) {
+ //之所以删除该记录是为了保证 与过期ip数据断开关联关系。
+ //比如:第一次拉下来的是1、2、3ip数据。第二次拉下来是4、5、6ip数据。那么1、2、3关联的did就会失效。 即:1、2、3记录成为无效数据
+ deleteDomainInfo(domainList);
+ }
+ SQLiteDatabase db = getWritableDatabase();
+ ContentValues cv = new ContentValues();
+ try {
+ db.beginTransaction();
+ cv.put(DOMAIN_COLUMN_DOMAIN, model.domain);
+ cv.put(DOMAIN_COLUMN_SP, model.sp);
+ cv.put(DOMAIN_COLUMN_TTL, model.ttl);
+ cv.put(DOMAIN_COLUMN_TIME, model.time);
+ model.id = db.insert(TABLE_NAME_DOMAIN, null, cv);
+ for (int i = 0; i < model.ipModelArr.size(); i++) {
+ IpModel temp = model.ipModelArr.get(i);
+ // 更新内存中IP表中的d_id字段
+ IpModel oldModel = getIpModel(temp.ip, sp);
+ IpModel ipModel = null;
+ // 若数据库中无此条数据,则插入一条
+ if (oldModel == null) {
+ ipModel = temp;
+ ipModel.d_id = model.id;
+ ipModel.id = addIpModel(ipModel);
+ } else {
+ ipModel = oldModel;
+ ipModel.d_id = model.id;
+ // 若数据库中存在此条数据,则更新对应的domainId即可
+ updateIpInfo(ipModel);
+ }
+ model.ipModelArr.remove(i);
+ model.ipModelArr.add(i, ipModel);
+ }
+ db.setTransactionSuccessful();
+ } catch (Exception e) {
+ e.printStackTrace();
+ // 上报错误
+ } finally {
+ db.endTransaction();
+ db.close();
+ }
+ return model;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 根据url 获取缓存domain
+ *
+ * @param domain
+ * @param sp
+ * @return
+ */
+ public List<DomainModel> QueryDomainInfo(String domain, String sp){
+
+ synchronized (synLock) {
+ List<DomainModel> list = new ArrayList<DomainModel>() ;
+ StringBuilder sql = new StringBuilder();
+ sql.append("SELECT * FROM ");
+ sql.append(TABLE_NAME_DOMAIN);
+ sql.append(" WHERE ");
+ sql.append(DOMAIN_COLUMN_DOMAIN);
+ sql.append(" =? ");
+ sql.append(" AND ");
+ sql.append(DOMAIN_COLUMN_SP);
+ sql.append(" =? ;");
+ SQLiteDatabase db = getReadableDatabase();
+ Cursor cursor = null;
+ try {
+ cursor = db.rawQuery(sql.toString(), new String[] { domain, sp });
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+ do {
+ DomainModel model = new DomainModel() ;
+ model.id = cursor.getInt(cursor.getColumnIndex(DOMAIN_COLUMN_ID));
+ model.domain = cursor.getString(cursor.getColumnIndex(DOMAIN_COLUMN_DOMAIN));
+ model.sp = cursor.getString(cursor.getColumnIndex(DOMAIN_COLUMN_SP));
+ model.ttl = cursor.getString(cursor.getColumnIndex(DOMAIN_COLUMN_TTL));
+ model.time = cursor.getString(cursor.getColumnIndex(DOMAIN_COLUMN_TIME));
+ model.ipModelArr = (ArrayList<IpModel>) QueryIpModelInfo(model) ;
+ list.add(model) ;
+ } while (cursor.moveToNext());
+ }
+
+ } catch (Exception e) {
+ // TODO: handle exception
+ e.printStackTrace();
+ } finally {
+ cursor.close();
+ db.close() ;
+ }
+ return list ;
+ }
+ }
+
+ /**
+ * 通过url获取服务器ip信息
+ * 根据 domainModel 获取Ipmodel 对象。
+ * @param domainModel
+ * @return
+ */
+ private List<IpModel> QueryIpModelInfo( DomainModel domainModel ){
+
+ // 内部方法 不需要加锁
+ List<IpModel> list = new ArrayList<IpModel>() ;
+ StringBuilder sql = new StringBuilder();
+ sql.append("SELECT * FROM ");
+ sql.append(TABLE_NAME_IP);
+ sql.append(" WHERE ");
+ sql.append(IP_COLUMN_DOMAIN_ID);
+ sql.append(" =? ;");
+ SQLiteDatabase db = getReadableDatabase();
+ Cursor cursor = null;
+ try {
+ cursor = db.rawQuery(sql.toString(), new String[] { String.valueOf( domainModel.id ) });
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+ do{
+ IpModel ip = new IpModel() ;
+ ip.id = cursor.getInt(cursor.getColumnIndex(IP_COLUMN_ID));
+ ip.d_id = cursor.getInt(cursor.getColumnIndex(IP_COLUMN_DOMAIN_ID));
+ ip.ip = cursor.getString(cursor.getColumnIndex(IP_COLUMN_IP));
+// ip.ip = String.valueOf( Tools.longToIP( Long.parseLong( ip.ip ) ) );
+ ip.port = cursor.getInt(cursor.getColumnIndex(IP_COLUMN_PORT));
+ ip.sp = cursor.getString(cursor.getColumnIndex(IP_COLUMN_SP));
+ ip.ttl = cursor.getString(cursor.getColumnIndex(IP_COLUMN_TTL));
+ ip.priority = cursor.getString(cursor.getColumnIndex(IP_COLUMN_PRIORITY));
+ ip.rtt = cursor.getString(cursor.getColumnIndex(IP_COLUMN_RTT));
+ ip.success_num = cursor.getString(cursor.getColumnIndex(IP_COLUMN_SUCCESS_NUM));
+ ip.err_num = cursor.getString(cursor.getColumnIndex(IP_COLUMN_ERR_NUM));
+ ip.finally_success_time = cursor.getString(cursor.getColumnIndex(IP_COLUMN_FINALLY_SUCCESS_TIME));
+ ip.finally_fail_time = cursor.getString(cursor.getColumnIndex(IP_COLUMN_FINALLY_FAIL_TIME));
+ list.add(ip) ;
+ }while(cursor.moveToNext());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ cursor.close();
+ db.close() ;
+ }
+
+ return list ;
+ }
+
+ /**
+ * 根据 服务器 ip 获取数据库的数据集
+ *
+ * @param serverIp
+ * @return
+ */
+ private IpModel getIpModel(String serverIp, String sp){
+
+ ArrayList<IpModel> list = new ArrayList<IpModel>();
+
+ synchronized (synLock) {
+
+ StringBuilder sql = new StringBuilder();
+ sql.append("SELECT * FROM ");
+ sql.append(TABLE_NAME_IP);
+ sql.append(" WHERE ");
+ sql.append(IP_COLUMN_IP);
+ sql.append(" =? ");
+ sql.append(" AND ");
+ sql.append(DOMAIN_COLUMN_SP);
+ sql.append(" =? ;");
+
+ SQLiteDatabase db = getWritableDatabase();
+ Cursor cursor = null;
+ try {
+ cursor = db.rawQuery(sql.toString(), new String[]{serverIp, sp});
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+ do {
+ IpModel ip = new IpModel();
+ ip.id = cursor.getInt(cursor.getColumnIndex(IP_COLUMN_ID));
+ ip.d_id = cursor.getInt(cursor.getColumnIndex(IP_COLUMN_DOMAIN_ID));
+ ip.ip = cursor.getString(cursor.getColumnIndex(IP_COLUMN_IP));
+ ip.port = cursor.getInt(cursor.getColumnIndex(IP_COLUMN_PORT));
+ ip.sp = cursor.getString(cursor.getColumnIndex(IP_COLUMN_SP));
+ ip.ttl = cursor.getString(cursor.getColumnIndex(IP_COLUMN_TTL));
+ ip.priority = cursor.getString(cursor.getColumnIndex(IP_COLUMN_PRIORITY));
+ ip.rtt = cursor.getString(cursor.getColumnIndex(IP_COLUMN_RTT));
+ ip.success_num = cursor.getString(cursor.getColumnIndex(IP_COLUMN_SUCCESS_NUM));
+ ip.err_num = cursor.getString(cursor.getColumnIndex(IP_COLUMN_ERR_NUM));
+ ip.finally_success_time = cursor.getString(cursor.getColumnIndex(IP_COLUMN_FINALLY_SUCCESS_TIME));
+ ip.finally_fail_time = cursor.getString(cursor.getColumnIndex(IP_COLUMN_FINALLY_FAIL_TIME));
+ list.add(ip);
+ } while (cursor.moveToNext());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ cursor.close();
+ //db.close();
+ }
+ }
+
+ // 排除下重复的IP 理论上是不会出现重复IP的, 多线程同时写数据库有锁。
+ if( list.size() > 1 ){
+ for( int i = 0 ; i < list.size() - 1 ; i++ ){
+ IpModel ipModel = list.get(i);
+ deleteIpServer(ipModel.id) ;
+ }
+ }
+
+ return list.size() > 0 ? list.get(list.size() - 1) : null ;
+ }
+
+ /**
+ * 根据域名id 删除域名相关信息
+ */
+ private void deleteDomainInfo(long domain_id){
+
+ synchronized (synLock) {
+ SQLiteDatabase db = getWritableDatabase();
+ try {
+ db.delete(TABLE_NAME_DOMAIN, DOMAIN_COLUMN_ID + " = ?", new String[]{String.valueOf(domain_id)} ) ;
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ db.close();
+ }
+ }
+ }
+
+// /**
+// * 根据域名id 删除服务器相关信息
+// * @param domain_id
+// */
+// private void deleteIpInfo(long domain_id){
+//
+// synchronized (synLock) {
+// SQLiteDatabase db = getWritableDatabase();
+// try {
+// db.delete(TABLE_NAME_IP, IP_COLUMN_DOMAIN_ID + " = ?", new String[]{String.valueOf(domain_id)} ) ;
+// } catch (Exception e) {
+// e.printStackTrace();
+// } finally {
+// db.close();
+// }
+// }
+// }
+
+ /**
+ * 根据 ID 删除服务器信息
+ * @param ip
+ */
+ private void deleteIpServer(long id){
+
+ synchronized (synLock) {
+ SQLiteDatabase db = getWritableDatabase();
+ try {
+ db.delete(TABLE_NAME_IP, IP_COLUMN_ID + " = ?", new String[]{String.valueOf(id)} ) ;
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ db.close();
+ }
+ }
+ }
+
+
+ /**
+ * 删除域名相关信息
+ */
+ public void deleteDomainInfo(DomainModel domainModel){
+ deleteDomainInfo( domainModel.id) ;
+ }
+
+ /**
+ * 删除域名相关信息
+ */
+ public void deleteDomainInfo(ArrayList<DomainModel> domainModelArr){
+ for( DomainModel temp : domainModelArr )
+ deleteDomainInfo( temp.id) ;
+ }
+
+
+ /**
+ * 清除缓存数据
+ */
+ public void clear() {
+ synchronized (synLock) {
+ SQLiteDatabase db = getWritableDatabase();
+ try {
+ db.delete(TABLE_NAME_DOMAIN, null, null);
+ db.delete(TABLE_NAME_IP, null, null);
+ db.delete(TABLE_NAME_CONNECT_FAIL, null, null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ db.close();
+ }
+ }
+ }
+
+
+ /**
+ * 返回 domain 表信息
+ */
+ public ArrayList<DomainModel> getAllTableDomain(boolean appendIpInfo) {
+ ArrayList<DomainModel> list = new ArrayList<DomainModel>();
+ synchronized (synLock) {
+ StringBuilder sql = new StringBuilder();
+ sql.append("SELECT * FROM ");
+ sql.append(TABLE_NAME_DOMAIN);
+ sql.append(" ; ");
+ SQLiteDatabase db = getReadableDatabase();
+ Cursor cursor = null;
+ try {
+ cursor = db.rawQuery(sql.toString(), null);
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+ do {
+ DomainModel model = new DomainModel();
+ model.id = cursor.getInt(cursor.getColumnIndex(DOMAIN_COLUMN_ID));
+ model.domain = cursor.getString(cursor.getColumnIndex(DOMAIN_COLUMN_DOMAIN));
+ model.sp = cursor.getString(cursor.getColumnIndex(DOMAIN_COLUMN_SP));
+ model.ttl = cursor.getString(cursor.getColumnIndex(DOMAIN_COLUMN_TTL));
+ model.time = cursor.getString(cursor.getColumnIndex(DOMAIN_COLUMN_TIME));
+ if (appendIpInfo) {
+ model.ipModelArr = (ArrayList<IpModel>) QueryIpModelInfo(model);
+ }
+ list.add(model);
+ } while (cursor.moveToNext());
+ }
+ } catch (Exception e) {
+ // TODO: handle exception
+ e.printStackTrace();
+ } finally {
+ cursor.close();
+ db.close();
+ }
+ }
+ return list;
+ }
+ /**
+ * 返回 domain 表信息
+ */
+ public ArrayList<DomainModel> getAllTableDomain() {
+ return getAllTableDomain(false);
+ }
+
+
+ /**
+ * 返回 ip 表信息
+ */
+ public ArrayList<IpModel> getTableIP(){
+ synchronized (synLock) {
+ ArrayList<IpModel> list = new ArrayList<IpModel>();
+ StringBuilder sql = new StringBuilder();
+ sql.append("SELECT * FROM ");
+ sql.append(TABLE_NAME_IP);
+ sql.append(" ; ");
+
+ SQLiteDatabase db = getReadableDatabase();
+ Cursor cursor = null;
+ try {
+ cursor = db.rawQuery(sql.toString(), null);
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToFirst();
+ do {
+ IpModel ip = new IpModel();
+ ip.id = cursor.getInt(cursor.getColumnIndex(IP_COLUMN_ID));
+ ip.d_id = cursor.getInt(cursor.getColumnIndex(IP_COLUMN_DOMAIN_ID));
+ ip.ip = cursor.getString(cursor.getColumnIndex(IP_COLUMN_IP));
+ ip.port = cursor.getInt(cursor.getColumnIndex(IP_COLUMN_PORT));
+ ip.sp = cursor.getString(cursor.getColumnIndex(IP_COLUMN_SP));
+ ip.ttl = cursor.getString(cursor.getColumnIndex(IP_COLUMN_TTL));
+ ip.priority = cursor.getString(cursor.getColumnIndex(IP_COLUMN_PRIORITY));
+ ip.rtt = cursor.getString(cursor.getColumnIndex(IP_COLUMN_RTT));
+ ip.success_num = cursor.getString(cursor.getColumnIndex(IP_COLUMN_SUCCESS_NUM));
+ ip.err_num = cursor.getString(cursor.getColumnIndex(IP_COLUMN_ERR_NUM));
+ ip.finally_success_time = cursor.getString(cursor.getColumnIndex(IP_COLUMN_FINALLY_SUCCESS_TIME));
+ ip.finally_fail_time = cursor.getString(cursor.getColumnIndex(IP_COLUMN_FINALLY_FAIL_TIME));
+ list.add(ip);
+ } while (cursor.moveToNext());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ cursor.close();
+ db.close();
+ }
+ return list ;
+ }
+ }
+ /**
+ * 向数据库中新增一条ip记录
+ * @param model
+ * @return
+ */
+ public long addIpModel(IpModel model) {
+ synchronized (synLock) {
+ SQLiteDatabase db = getWritableDatabase();
+ ContentValues cv = new ContentValues();
+ cv.put(IP_COLUMN_DOMAIN_ID, model.d_id);
+ cv.put(IP_COLUMN_IP, model.ip);
+ cv.put(IP_COLUMN_PORT, model.port);
+ cv.put(IP_COLUMN_PRIORITY, model.priority);
+ cv.put(IP_COLUMN_SP, model.sp);
+
+ cv.put(IP_COLUMN_RTT, model.rtt);
+ cv.put(IP_COLUMN_FINALLY_FAIL_TIME, model.finally_fail_time);
+ cv.put(IP_COLUMN_FINALLY_SUCCESS_TIME, model.finally_success_time);
+ cv.put(IP_COLUMN_SUCCESS_NUM, model.success_num);
+ cv.put(IP_COLUMN_ERR_NUM, model.err_num);
+ cv.put(IP_COLUMN_TTL, model.ttl);
+ return db.insert(TABLE_NAME_IP, null, cv);
+ }
+ }
+
+ /**
+ * 更新数据库中的一条ip记录
+ * @param model
+ * @return
+ */
+ private void updateIpInfo(IpModel model) {
+ synchronized (synLock) {
+ SQLiteDatabase db = getWritableDatabase();
+ ContentValues cv = new ContentValues();
+ StringBuilder where = new StringBuilder();
+ where.append(IP_COLUMN_ID);
+ where.append(" = ? ");
+ cv.put(IP_COLUMN_DOMAIN_ID, model.d_id);
+ cv.put(IP_COLUMN_IP, model.ip);
+ cv.put(IP_COLUMN_PORT, model.port);
+ cv.put(IP_COLUMN_PRIORITY, model.priority);
+ cv.put(IP_COLUMN_SP, model.sp);
+
+ cv.put(IP_COLUMN_RTT, model.rtt);
+ cv.put(IP_COLUMN_FINALLY_FAIL_TIME, model.finally_fail_time);
+ cv.put(IP_COLUMN_FINALLY_SUCCESS_TIME, model.finally_success_time);
+ cv.put(IP_COLUMN_SUCCESS_NUM, model.success_num);
+ cv.put(IP_COLUMN_ERR_NUM, model.err_num);
+ cv.put(IP_COLUMN_TTL, model.ttl);
+ String[] args = new String[] { String.valueOf(model.id) };
+ db.update(TABLE_NAME_IP, cv, where.toString(), args);
+ }
+ }
+
+ /**
+ * 批量更新ip表数据
+ * @param model
+ * @return
+ */
+ public void updateIpInfo(List<IpModel> ipModels) {
+ synchronized (synLock) {
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+ try {
+ for (IpModel model : ipModels) {
+ ContentValues cv = new ContentValues();
+ StringBuilder where = new StringBuilder();
+ where.append(IP_COLUMN_ID);
+ where.append(" = ? ");
+ cv.put(IP_COLUMN_DOMAIN_ID, model.d_id);
+ cv.put(IP_COLUMN_IP, model.ip);
+ cv.put(IP_COLUMN_PORT, model.port);
+ cv.put(IP_COLUMN_PRIORITY, model.priority);
+ cv.put(IP_COLUMN_SP, model.sp);
+
+ cv.put(IP_COLUMN_RTT, model.rtt);
+ cv.put(IP_COLUMN_FINALLY_FAIL_TIME, model.finally_fail_time);
+ cv.put(IP_COLUMN_FINALLY_SUCCESS_TIME, model.finally_success_time);
+ cv.put(IP_COLUMN_SUCCESS_NUM, model.success_num);
+ cv.put(IP_COLUMN_ERR_NUM, model.err_num);
+ cv.put(IP_COLUMN_TTL, model.ttl);
+ String[] args = new String[] { String.valueOf(model.id) };
+ db.update(TABLE_NAME_IP, cv, where.toString(), args);
+ }
+ db.setTransactionSuccessful();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally{
+ db.endTransaction();
+ db.close();
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ *
+ */
+package com.sina.util.dnscache.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+
+import com.sina.util.dnscache.model.DomainModel;
+import com.sina.util.dnscache.model.HttpDnsPack;
+import com.sina.util.dnscache.model.IpModel;
+
+/**
+ *
+ * 项目名称: DNSCache <br>
+ * 类名称: DnsCacheManager <br>
+ * 类描述: Dnd缓存层管理类 <br>
+ * 创建人: fenglei <br>
+ * 创建时间: 2015-3-26 下午6:10:10 <br>
+ *
+ * 修改人: <br>
+ * 修改时间: <br>
+ * 修改备注: <br>
+ *
+ * @version V1.0
+ */
+public class DnsCacheManager extends DNSCacheDatabaseHelper implements IDnsCache{
+
+ public DnsCacheManager(Context context) {
+ super(context);
+ db = new DNSCacheDatabaseHelper(context) ;
+ }
+
+ /**
+ * 数据库操作类
+ */
+ private DNSCacheDatabaseHelper db = null ;
+
+ /**
+ * 缓存初始容量值
+ */
+ private final int INIT_SIZE = 8;
+
+ /**
+ * 缓存最大容量值
+ */
+ private final int MAX_CACHE_SIZE = 32;
+
+ /**
+ * 延迟差值,单位s
+ */
+ public static int ip_overdue_delay = 20 ;
+
+ /**
+ * 缓存链表
+ */
+ @SuppressLint("NewApi")
+ private ConcurrentHashMap<String, DomainModel> data = new ConcurrentHashMap<String, DomainModel>(INIT_SIZE, MAX_CACHE_SIZE);
+
+
+ /////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 获取url缓存
+ * @param url
+ * @return
+ */
+ @Override
+ public DomainModel getDnsCache(String sp, String url){
+
+
+ DomainModel model = data.get(url) ;
+
+ if( model == null ){
+ //缓存中没有从数据库中查找
+ ArrayList<DomainModel> list = (ArrayList<DomainModel>) db.QueryDomainInfo(url, sp ) ;
+ if( list != null && list.size() != 0){
+ model = list.get( list.size() - 1 ) ;
+ }
+
+ //查询到数据 添加到缓存中
+ if( model != null )addMemoryCache(url, model) ;
+
+ }
+
+ if( model != null){
+ //检测是否过期
+ if( isExpire(model, ip_overdue_delay) ){
+ model = null ;
+ }
+ }
+
+ return model ;
+ }
+
+
+ /**
+ * 插入本地 cache 缓存
+ *
+ * @param dnsPack
+ * @return
+ */
+ public DomainModel insertDnsCache(HttpDnsPack dnsPack){
+
+ DomainModel domainModel = new DomainModel() ;
+ domainModel.domain = dnsPack.domain ;
+ domainModel.sp = dnsPack.localhostSp ;
+ domainModel.time = String.valueOf(System.currentTimeMillis());
+
+ domainModel.ipModelArr = new ArrayList<IpModel>();
+
+ int domainTTL = 60 ;
+ for( HttpDnsPack.IP temp : dnsPack.dns ){
+
+ IpModel ipModel = new IpModel() ;
+ ipModel.ip = temp.ip ;
+ ipModel.ttl = temp.ttl ;
+ ipModel.priority = temp.priority ;
+
+ ipModel.port = 80 ;
+ ipModel.sp = domainModel.sp ;
+
+ domainModel.ipModelArr.add(ipModel) ;
+
+ domainTTL = Math.min(domainTTL, Integer.valueOf(ipModel.ttl));
+
+ }
+
+ domainModel.ttl = String.valueOf(domainTTL);
+
+ if( domainModel != null && domainModel.ipModelArr != null && domainModel.ipModelArr.size() > 0){
+ // 插入数据库
+ domainModel = super.addDomainModel(dnsPack.domain,dnsPack.localhostSp,domainModel) ;
+ // 插入内存缓存
+ addMemoryCache( domainModel.domain, domainModel );
+ }
+
+ return domainModel ;
+ }
+
+ /**
+ * 获取即将过期的 domain 数据
+ * @return
+ */
+ @Override
+ public ArrayList<DomainModel> getExpireDnsCache() {
+
+ ArrayList<DomainModel> listDomain = new ArrayList<DomainModel>();
+
+ for (Entry<String, DomainModel> entry : data.entrySet()) {
+ DomainModel temp = data.get(entry.getKey());
+ if (isExpire(temp)) {
+ listDomain.add(temp);
+ }
+ }
+
+ return listDomain;
+ }
+
+
+ /**
+ * 获取缓存中全部的 DomainModel数据
+ */
+ public ArrayList<DomainModel> getAllMemoryCache() {
+ ArrayList<DomainModel> list = new ArrayList<DomainModel>() ;
+ for (Entry<String, DomainModel> entry : data.entrySet()) {
+ DomainModel temp = data.get(entry.getKey());
+ list.add(temp) ;
+ }
+ return list;
+ }
+
+ /**
+ * 清除全部缓存
+ */
+ public void clear(){
+ super.clear();
+ data.clear();
+ }
+
+ /**
+ * 清除内存缓存
+ */
+ public void clearMemoryCache(){
+ data.clear();
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * 添加url缓存
+ * @param model
+ */
+ public void addMemoryCache(String url, DomainModel model) {
+
+ if( model == null ) return ;
+ if( model.ipModelArr == null ) return ;
+ if( model.ipModelArr.size() <= 0 ) return ;
+ for( IpModel ipModel : model.ipModelArr ){
+ if( ipModel == null ) return ;
+ }
+
+ // 检测下缓存中是否存在, 如果存在删除旧数据在添加
+ DomainModel temp = data.get(url);
+ if (temp != null) {
+ data.remove(url);
+ }
+
+ data.put(url, model);
+ }
+
+
+ /**
+ * 检测是否过期,提前3秒刷一下
+ * @param domainModel
+ * @return
+ */
+ private boolean isExpire(DomainModel domainModel) {
+ return isExpire(domainModel, -3);
+ }
+
+ /**
+ * 检测是否过期
+ *
+ * @param domainModel
+ * @return
+ */
+ private boolean isExpire(DomainModel domainModel, long difference) {
+ long queryTime = Long.parseLong(domainModel.time) / 1000;
+ long ttl = Long.parseLong(domainModel.ttl);
+ long newTime = System.currentTimeMillis() / 1000;
+ if ((newTime - queryTime) > (ttl + difference)) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void setSpeedInfo(List<IpModel> ipModels) {
+ updateIpInfo(ipModels);
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////
+
+}
--- /dev/null
+package com.sina.util.dnscache.cache;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.sina.util.dnscache.model.DomainModel;
+import com.sina.util.dnscache.model.HttpDnsPack;
+import com.sina.util.dnscache.model.IpModel;
+
+/**
+*
+* 项目名称: DNSCache <br>
+* 类名称: IDnsCache <br>
+* 类描述: 缓存层对外接口 <br>
+* 创建人: fenglei <br>
+* 创建时间: 2015-3-26 下午6:12:10 <br>
+*
+* 修改人: <br>
+* 修改时间: <br>
+* 修改备注: <br>
+*
+* @version V1.0
+*/
+public interface IDnsCache {
+
+ /**
+ * 获取 domain 缓存
+ * @param sp
+ * @param domain
+ * @return
+ */
+ public DomainModel getDnsCache( String sp, String domain ) ;
+
+
+ /**
+ * 插入一条缓存记录
+ * @param dnsPack
+ * @return
+ */
+ public DomainModel insertDnsCache(HttpDnsPack dnsPack) ;
+
+
+ /**
+ * 批量更新测速后信息,保证事务的原子性。即保持一个域名下的所有ip都同时修改。
+ * @param ipModels
+ */
+ public void setSpeedInfo(List<IpModel> ipModels) ;
+
+
+ /**
+ * 获取即将过期的domain信息
+ * @return
+ */
+ public ArrayList<DomainModel> getExpireDnsCache() ;
+
+ /**
+ * 内存中 增加缓存信息
+ * @param url
+ * @param model
+ */
+ public void addMemoryCache(String url, DomainModel model) ;
+
+
+ /**
+ * 清除全部缓存数据
+ */
+ public void clear();
+
+
+ /**
+ * 清除内存缓存
+ */
+ public void clearMemoryCache() ;
+
+ /**
+ * 获取缓存中全部的 DomainModel数据
+ * @return
+ */
+ public ArrayList<DomainModel> getAllMemoryCache() ;
+
+
+ /**
+ * 获取数据库 domain 表,默认不追加ip表的数据
+ */
+ public ArrayList<DomainModel> getAllTableDomain();
+
+ public ArrayList<DomainModel> getAllTableDomain(boolean appendIpinfo);
+
+
+ /**
+ * 获取数据库 ip 表
+ */
+ public ArrayList<IpModel> getTableIP() ;
+
+}
--- /dev/null
+package com.sina.util.dnscache.dnsp;
+
+import java.util.ArrayList;
+
+/**
+*
+* 项目名称: DNSCache <br>
+* 类名称: HttpDnsConfig <br>
+* 类描述: HTTPDNS 接口配置类 <br>
+* 创建人: fenglei <br>
+* 创建时间: 2015-4-15 下午9:10:10 <br>
+*
+* 修改人: <br>
+* 修改时间: <br>
+* 修改备注: <br>
+*
+* @version V1.0
+*/
+public class DnsConfig {
+
+ /**
+ * 是否使用 自己的httpdns 服务器
+ */
+ public static boolean enableSinaHttpDns = true ;
+
+ /**
+ * DNSPOD http dns 开端
+ */
+ public static boolean enableDnsPod = true ;
+
+ /**
+ * DNSPOD http dns 开端
+ */
+ public static boolean enableUdpDns = true ;
+
+ /**
+ * httpdns 服务器地址
+ */
+ public static ArrayList<String> SINA_HTTPDNS_SERVER_API = new ArrayList<String>();
+
+ /**
+ * DNSPOD 服务器地址
+ */
+ public static String DNSPOD_SERVER_API = "" ;
+
+ /**
+ * dns 服务器地址
+ */
+ public static String UDPDNS_SERVER_API = "" ;
+
+
+}
--- /dev/null
+package com.sina.util.dnscache.dnsp;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import com.sina.util.dnscache.DNSCacheConfig;
+import com.sina.util.dnscache.Tools;
+import com.sina.util.dnscache.dnsp.impl.HttpPodDns;
+import com.sina.util.dnscache.dnsp.impl.LocalDns;
+import com.sina.util.dnscache.dnsp.impl.SinaHttpDns;
+import com.sina.util.dnscache.dnsp.impl.UdpDns;
+import com.sina.util.dnscache.log.HttpDnsLogManager;
+import com.sina.util.dnscache.model.HttpDnsPack;
+import com.sina.util.dnscache.net.networktype.NetworkManager;
+
+public class DnsManager implements IDns {
+
+ ArrayList<IDnsProvider> mDnsProviders = new ArrayList<IDnsProvider>();
+ private ArrayList<String> debugInfo = new ArrayList<String>();
+
+ public DnsManager() {
+ mDnsProviders.add(new SinaHttpDns());
+ mDnsProviders.add(new HttpPodDns());
+ mDnsProviders.add(new UdpDns());
+ mDnsProviders.add(new LocalDns());
+ }
+
+ @Override
+ public HttpDnsPack requestDns(String domain) {
+ Collections.sort(mDnsProviders, new Comparator<IDnsProvider>() {
+ @Override
+ public int compare(IDnsProvider lhs, IDnsProvider rhs) {
+ if (lhs == null || rhs == null) {
+ return 0;
+ } else {
+ // 按照降序排序
+ return rhs.getPriority() - lhs.getPriority();
+ }
+ }
+ });
+ for (IDnsProvider dp : mDnsProviders) {
+ Tools.log("TAG", "访问" + dp.getClass().getSimpleName() + "接口开始," + "\n优先级是:" + dp.getPriority() + "\n该模块是否开启:" + dp.isActivate()
+ + "\n该模块的API地址是:" + dp.getServerApi());
+ if (dp.isActivate()) {
+ HttpDnsPack dnsPack = dp.requestDns(domain);
+ Tools.log("TAG", "访问" + dp.getClass().getSimpleName() + "接口结束," + "\n返回的结果是:" + dnsPack);
+ if (null != dnsPack) {
+ if (DNSCacheConfig.DEBUG) {
+ if (null != debugInfo) {
+ debugInfo.add(dnsPack.rawResult + "[from:" + dp.getClass().getSimpleName() + "]");
+ }
+ }
+
+ dnsPack.localhostSp = NetworkManager.getInstance().getSPID() ;
+ if( !dnsPack.device_sp.equals( dnsPack.localhostSp ) ){
+ HttpDnsLogManager.getInstance().writeLog(HttpDnsLogManager.TYPE_ERROR, HttpDnsLogManager.ACTION_ERR_SPINFO, dnsPack.toJson() );
+ }
+
+ return dnsPack;
+ }
+ }
+ }
+
+ HttpDnsLogManager.getInstance().writeLog(HttpDnsLogManager.TYPE_ERROR, HttpDnsLogManager.ACTION_ERR_DOMAININFO, "{\"domain\":" + "\"" + domain + "\"}" );
+
+ return null;
+ }
+
+ @Override
+ public ArrayList<String> getDebugInfo() {
+ return debugInfo;
+ }
+
+ @Override
+ public void initDebugInfo() {
+ debugInfo = new ArrayList<String>();
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.dnsp;
+
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.model.HttpDnsPack;
+
+public interface IDns {
+
+ /**
+ * 请求dns server,解析该domain域名
+ * @param domain
+ * @return
+ */
+ public HttpDnsPack requestDns(String domain) ;
+
+ /**
+ * debug调试信息
+ * @return
+ */
+ public ArrayList<String> getDebugInfo() ;
+
+ /**
+ * 初始化debug信息
+ * @return
+ */
+ public void initDebugInfo() ;
+
+}
\ No newline at end of file
--- /dev/null
+package com.sina.util.dnscache.dnsp;
+
+import com.sina.util.dnscache.model.HttpDnsPack;
+
+public interface IDnsProvider {
+
+ /**
+ * 请求dns server,返回指定的域名解析信息
+ * @return
+ */
+ public HttpDnsPack requestDns(String domain) ;
+
+ /**
+ * 被执行的优先级
+ * @return
+ */
+ public int getPriority();
+
+ /**
+ * 是否是激活状态
+ * @return
+ */
+ public boolean isActivate();
+
+
+ /**
+ * 获取dns server的地址
+ * @return
+ */
+ public String getServerApi();
+}
\ No newline at end of file
--- /dev/null
+/**
+ *
+ */
+package com.sina.util.dnscache.dnsp;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import com.sina.util.dnscache.model.HttpDnsPack;
+
+/**
+ *
+ * 项目名称: DNSCache 类名称: IJsonParser 类描述: 创建人: fenglei 创建时间: 2015-3-30 下午3:37:05
+ *
+ * 修改人: 修改时间: 修改备注:
+ *
+ * @version V1.0
+ */
+public interface IJsonParser {
+
+ public HttpDnsPack JsonStrToObj(String jsonStr) throws Exception;
+
+ public class JavaJSON_SINAHTTPDNS implements IJsonParser {
+
+ @Override
+ public HttpDnsPack JsonStrToObj(String jsonStr) throws Exception {
+ HttpDnsPack dnsPack = new HttpDnsPack();
+ JSONObject jsonObj = new JSONObject(jsonStr);
+ dnsPack.rawResult = jsonStr;
+ dnsPack.domain = jsonObj.getString("domain");
+ dnsPack.device_ip = jsonObj.getString("device_ip");
+ dnsPack.device_sp = jsonObj.getString("device_sp");
+
+ JSONArray jsonarray = jsonObj.getJSONArray("dns");
+ dnsPack.dns = new HttpDnsPack.IP[jsonarray.length()];
+ for (int i = 0; i < dnsPack.dns.length; i++) {
+ JSONObject tempJsonObj = new JSONObject(jsonarray.getString(i));
+ dnsPack.dns[i] = new HttpDnsPack.IP();
+ dnsPack.dns[i].ip = tempJsonObj.getString("ip");
+ dnsPack.dns[i].ttl = tempJsonObj.getString("ttl");
+ dnsPack.dns[i].priority = tempJsonObj.getString("priority");
+ }
+ return dnsPack;
+ }
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.dnsp.impl;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.sina.util.dnscache.DNSCacheConfig;
+import com.sina.util.dnscache.Tools;
+import com.sina.util.dnscache.dnsp.DnsConfig;
+import com.sina.util.dnscache.dnsp.IDnsProvider;
+import com.sina.util.dnscache.model.HttpDnsPack;
+import com.sina.util.dnscache.net.ApacheHttpClientNetworkRequests;
+import com.sina.util.dnscache.net.networktype.NetworkManager;
+
+public class HttpPodDns implements IDnsProvider {
+
+ private ApacheHttpClientNetworkRequests netWork;
+
+ public HttpPodDns() {
+ netWork = new ApacheHttpClientNetworkRequests();
+ }
+
+ @Override
+ public HttpDnsPack requestDns(String domain) {
+ // 如果新浪自家的服务器没有拿到数据,或者数据有问题,则使用 dnspod 提供的接口获取数据
+ String jsonDataStr = null;
+ HttpDnsPack dnsPack = null;
+
+ String dnspod_httpdns_api_url = DnsConfig.DNSPOD_SERVER_API + DNSPodCipher.Encryption(domain);
+ jsonDataStr = netWork.requests(dnspod_httpdns_api_url);
+ if (jsonDataStr == null || jsonDataStr.equals(""))
+ return null; // 如果dnspod 也没提取到数据 则返回空
+
+ jsonDataStr = DNSPodCipher.Decryption(jsonDataStr);
+
+ dnsPack = new HttpDnsPack();
+ try {
+ String IP_TTL[] = jsonDataStr.split(",");
+ String IPArr[] = IP_TTL[0].split(";");
+ String TTL = IP_TTL[1];
+ dnsPack.rawResult = jsonDataStr;
+ dnsPack.domain = domain;
+ dnsPack.device_ip = NetworkManager.Util.getLocalIpAddress();
+ dnsPack.device_sp = NetworkManager.getInstance().getSPID() ;
+
+ dnsPack.dns = new HttpDnsPack.IP[IPArr.length];
+ for (int i = 0; i < IPArr.length; i++) {
+ dnsPack.dns[i] = new HttpDnsPack.IP();
+ dnsPack.dns[i].ip = IPArr[i];
+ dnsPack.dns[i].ttl = TTL;
+ dnsPack.dns[i].priority = "0";
+ }
+ } catch (Exception e) {
+ dnsPack = null;
+ }
+ return dnsPack;
+ }
+
+ @Override
+ public boolean isActivate() {
+ return DnsConfig.enableDnsPod;
+ }
+
+ static class DNSPodCipher {
+
+ public static String Encryption(String domain) {
+
+ if (DNSCacheConfig.Data.getInstance().DNSPOD_ID == null || DNSCacheConfig.Data.getInstance().DNSPOD_ID.equals(""))
+ return domain;
+
+ if (DNSCacheConfig.Data.getInstance().DNSPOD_KEY == null || DNSCacheConfig.Data.getInstance().DNSPOD_KEY.equals(""))
+ return domain;
+
+ try {
+ // 初始化密钥
+ SecretKeySpec keySpec = new SecretKeySpec(DNSCacheConfig.Data.getInstance().DNSPOD_KEY.getBytes("utf-8"), "DES");
+ // 选择使用 DES 算法,ECB 方式,填充方式为 PKCS5Padding
+ Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
+ // 初始化
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec);
+ // 获取加密后的字符串
+ byte[] encryptedString = cipher.doFinal(domain.getBytes("utf-8"));
+
+ Tools.log("TAG_NET", bytesToHexString(encryptedString));
+
+ return bytesToHexString(encryptedString) + "&id=" + DNSCacheConfig.Data.getInstance().DNSPOD_ID;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return "";
+ }
+
+ public static String Decryption(String data) {
+
+ if (DNSCacheConfig.Data.getInstance().DNSPOD_ID == null || DNSCacheConfig.Data.getInstance().DNSPOD_ID.equals(""))
+ return data;
+
+ if (DNSCacheConfig.Data.getInstance().DNSPOD_KEY == null || DNSCacheConfig.Data.getInstance().DNSPOD_KEY.equals(""))
+ return data;
+
+ try {
+ // 初始化密钥
+ SecretKeySpec keySpec = new SecretKeySpec(DNSCacheConfig.Data.getInstance().DNSPOD_KEY.getBytes("utf-8"), "DES");
+ // 选择使用 DES 算法,ECB 方式,填充方式为 PKCS5Padding
+ Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
+ // 初始化
+ cipher.init(Cipher.DECRYPT_MODE, keySpec);
+ // 获取解密后的字符串
+ byte[] decryptedString = cipher.doFinal(hexStringToBytes(data));
+
+ Tools.log("TAG_NET", new String(decryptedString));
+
+ return new String(decryptedString);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return "";
+ }
+
+ public static String bytesToHexString(byte[] src) {
+ StringBuilder stringBuilder = new StringBuilder("");
+ if (src == null || src.length <= 0) {
+ return null;
+ }
+ for (int i = 0; i < src.length; i++) {
+ int v = src[i] & 0xFF;
+ String hv = Integer.toHexString(v);
+ if (hv.length() < 2) {
+ stringBuilder.append(0);
+ }
+ stringBuilder.append(hv);
+ }
+ return stringBuilder.toString();
+ }
+
+ public static byte[] hexStringToBytes(String hexString) {
+ if (hexString == null || hexString.equals("")) {
+ return null;
+ }
+ hexString = hexString.toUpperCase();
+ int length = hexString.length() / 2;
+ char[] hexChars = hexString.toCharArray();
+ byte[] d = new byte[length];
+ for (int i = 0; i < length; i++) {
+ int pos = i * 2;
+ d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
+ }
+ return d;
+ }
+
+ /**
+ * Convert char to byte
+ *
+ * @param c
+ * char
+ * @return byte
+ */
+ private static byte charToByte(char c) {
+ return (byte) "0123456789ABCDEF".indexOf(c);
+ }
+
+ }
+
+ @Override
+ public String getServerApi() {
+ return DnsConfig.DNSPOD_SERVER_API;
+ }
+
+ @Override
+ public int getPriority() {
+ return 8;
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.dnsp.impl;
+
+import java.net.InetAddress;
+
+import com.sina.util.dnscache.dnsp.IDnsProvider;
+import com.sina.util.dnscache.model.HttpDnsPack;
+import com.sina.util.dnscache.net.networktype.NetworkManager;
+
+public class LocalDns implements IDnsProvider {
+
+ @Override
+ public HttpDnsPack requestDns(String domain) {
+ try {
+ InetAddress[] addresses = InetAddress.getAllByName(domain);
+ String[] ipList = new String[addresses.length];
+ for (int i = 0; i < addresses.length; i++) {
+ ipList[i] = addresses[i].getHostAddress();
+ }
+ if (null != ipList && ipList.length > 0) {
+ HttpDnsPack dnsPack = new HttpDnsPack();
+ String IPArr[] = ipList;
+ String TTL = "60";
+ dnsPack.domain = domain;
+ dnsPack.device_ip = NetworkManager.Util.getLocalIpAddress();
+ dnsPack.device_sp = NetworkManager.getInstance().getSPID() ;
+ dnsPack.rawResult = "domain:" + domain + ";\nipArray:";
+ dnsPack.dns = new HttpDnsPack.IP[IPArr.length];
+ for (int i = 0; i < IPArr.length; i++) {
+ String ip = IPArr[i];
+ if (i == IPArr.length - 1) {
+ //去掉最后的逗号
+ dnsPack.rawResult += (ip);
+ } else {
+ dnsPack.rawResult += (ip + ",");
+ }
+ dnsPack.dns[i] = new HttpDnsPack.IP();
+ dnsPack.dns[i].ip = ip;
+ dnsPack.dns[i].ttl = TTL;
+ dnsPack.dns[i].priority = "0";
+ }
+ return dnsPack;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ @Override
+ public int getPriority() {
+ return 0;
+ }
+
+ @Override
+ public boolean isActivate() {
+ return true;
+ }
+
+ @Override
+ public String getServerApi() {
+ return null;
+ }
+
+}
--- /dev/null
+package com.sina.util.dnscache.dnsp.impl;
+
+import java.util.ArrayList;
+
+import android.text.TextUtils;
+
+import com.sina.util.dnscache.dnsp.DnsConfig;
+import com.sina.util.dnscache.dnsp.IDnsProvider;
+import com.sina.util.dnscache.dnsp.IJsonParser;
+import com.sina.util.dnscache.dnsp.IJsonParser.JavaJSON_SINAHTTPDNS;
+import com.sina.util.dnscache.model.HttpDnsPack;
+import com.sina.util.dnscache.net.ApacheHttpClientNetworkRequests;
+
+public class SinaHttpDns implements IDnsProvider{
+
+ private ApacheHttpClientNetworkRequests netWork;
+ private JavaJSON_SINAHTTPDNS jsonObj;
+ private String usingServerApi = "";
+ public SinaHttpDns() {
+ netWork = new ApacheHttpClientNetworkRequests();
+ jsonObj = new IJsonParser.JavaJSON_SINAHTTPDNS();
+ }
+
+ @Override
+ public HttpDnsPack requestDns(String domain) {
+ String jsonDataStr = null;
+ HttpDnsPack dnsPack = null;
+ ArrayList<String> serverApis = new ArrayList<String>();
+ serverApis.addAll(DnsConfig.SINA_HTTPDNS_SERVER_API);
+ while (null == dnsPack && serverApis.size() > 0) {
+ try {
+ String api = "";
+ int index = serverApis.indexOf(usingServerApi);
+ if (index != -1) {
+ api = serverApis.remove(index);
+ } else {
+ api = serverApis.remove(0);
+ }
+ String sina_httpdns_api_url = api + domain;
+ jsonDataStr = netWork.requests(sina_httpdns_api_url);
+ dnsPack = jsonObj.JsonStrToObj(jsonDataStr);
+ usingServerApi = api;
+ } catch (Exception e) {
+ e.printStackTrace();
+ usingServerApi = "";
+ }
+ }
+ return dnsPack;
+ }
+
+ @Override
+ public boolean isActivate() {
+ return DnsConfig.enableSinaHttpDns;
+ }
+
+
+ @Override
+ public String getServerApi() {
+ String serverApi = "";
+ if (!TextUtils.isEmpty(usingServerApi)) {
+ serverApi = usingServerApi;
+ } else {
+ boolean yes = DnsConfig.SINA_HTTPDNS_SERVER_API.size() > 0;
+ if (yes) {
+ serverApi = DnsConfig.SINA_HTTPDNS_SERVER_API.get(0);
+ }
+ }
+ return serverApi;
+ }
+
+ @Override
+ public int getPriority() {
+ return 10;
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.dnsp.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketTimeoutException;
+
+import com.sina.util.dnscache.dnsp.DnsConfig;
+import com.sina.util.dnscache.dnsp.IDnsProvider;
+import com.sina.util.dnscache.dnsp.impl.UdpDns.UdnDnsClient.UdpDnsInfo;
+import com.sina.util.dnscache.model.HttpDnsPack;
+import com.sina.util.dnscache.net.networktype.NetworkManager;
+
+public class UdpDns implements IDnsProvider {
+
+ @Override
+ public HttpDnsPack requestDns(String domain) {
+ try {
+ UdpDnsInfo info = UdnDnsClient.query(DnsConfig.UDPDNS_SERVER_API, domain);
+ if (null != info && info.ips.length > 0) {
+ HttpDnsPack dnsPack = new HttpDnsPack();
+ String IPArr[] = info.ips;
+ String TTL = String.valueOf(info.ttl);
+ dnsPack.rawResult = "domain : " + domain + "\n" + info.toString();
+ dnsPack.domain = domain;
+ dnsPack.device_ip = NetworkManager.Util.getLocalIpAddress();
+ dnsPack.device_sp = NetworkManager.getInstance().getSPID();
+
+ dnsPack.dns = new HttpDnsPack.IP[IPArr.length];
+ for (int i = 0; i < IPArr.length; i++) {
+ dnsPack.dns[i] = new HttpDnsPack.IP();
+ dnsPack.dns[i].ip = IPArr[i];
+ dnsPack.dns[i].ttl = TTL;
+ dnsPack.dns[i].priority = "0";
+ }
+ return dnsPack;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ static class UdnDnsClient {
+ private final static int TIME_OUT = 2000;
+ private final static int PORT = 53;
+ private final static int BUF_SIZE = 1024;
+
+ static class UdpDnsInfo {
+ public int ttl;
+ public String[] ips;
+
+ @Override
+ public String toString() {
+ StringBuilder info = new StringBuilder();
+ info.append("ttl : " + ttl + "\n");
+ info.append("ipArray : ");
+ if (null != ips) {
+ for (String ip : ips) {
+ info.append(ip + ",");
+ }
+ } else {
+ info.append("null ");
+ }
+ return info.toString();
+ }
+ }
+
+ private static UdpDnsInfo query(String dnsServerIP, String domainName) throws SocketTimeoutException, IOException {
+ UdpDnsInfo info = new UdpDnsInfo();
+ DatagramSocket socket = new DatagramSocket(0);
+ socket.setSoTimeout(TIME_OUT);
+
+ ByteArrayOutputStream outBuf = new ByteArrayOutputStream(BUF_SIZE);
+ DataOutputStream output = new DataOutputStream(outBuf);
+ encodeDNSMessage(output, domainName);
+
+ InetAddress host = InetAddress.getByName(dnsServerIP);
+ DatagramPacket request = new DatagramPacket(outBuf.toByteArray(), outBuf.size(), host, PORT);
+
+ socket.send(request);
+
+ byte[] inBuf = new byte[BUF_SIZE];
+ ByteArrayInputStream inBufArray = new ByteArrayInputStream(inBuf);
+ DataInputStream input = new DataInputStream(inBufArray);
+ DatagramPacket response = new DatagramPacket(inBuf, inBuf.length);
+
+ socket.receive(response);
+
+ decodeDNSMessage(input, info);
+
+ socket.close();
+ return info;
+ }
+
+ private static void encodeDNSMessage(DataOutputStream output, String domainName) throws IOException {
+ // transaction id
+ output.writeShort(1);
+ // flags
+ output.writeShort(0x100);
+ // number of queries
+ output.writeShort(1);
+ // answer, auth, other
+ output.writeShort(0);
+ output.writeShort(0);
+ output.writeShort(0);
+
+ encodeDomainName(output, domainName);
+
+ // query type
+ output.writeShort(1);
+ // query class
+ output.writeShort(1);
+
+ output.flush();
+ }
+
+ private static void encodeDomainName(DataOutputStream output, String domainName) throws IOException {
+ for (String label : domainName.split("\\.")) {
+ output.writeByte((byte) label.length());
+ output.write(label.getBytes());
+ }
+ output.writeByte(0);
+ }
+
+ private static void decodeDNSMessage(DataInputStream input, UdpDnsInfo info) throws IOException {
+ // header
+ // transaction id
+ input.skip(2);
+ // flags
+ input.skip(2);
+ // number of queries
+ input.skip(2);
+ // answer, auth, other
+ short numberOfAnswer = input.readShort();
+ input.skip(2);
+ input.skip(2);
+
+ // question record
+ skipDomainName(input);
+ // query type
+ input.skip(2);
+ // query class
+ input.skip(2);
+
+ // answer records
+ for (int i = 0; i < numberOfAnswer; i++) {
+ input.mark(1);
+ byte ahead = input.readByte();
+ input.reset();
+ if ((ahead & 0xc0) == 0xc0) {
+ // compressed name
+ input.skip(2);
+ } else {
+ skipDomainName(input);
+ }
+
+ // query type
+ short type = input.readShort();
+ // query class
+ input.skip(2);
+ // ttl
+ int ttl = input.readInt();
+ info.ttl = ttl;
+ short addrLen = input.readShort();
+ info.ips = new String[1];
+ if (type == 1 && addrLen == 4) {
+ int addr = input.readInt();
+ info.ips[0] = (longToIp(addr));
+ } else {
+ input.skip(addrLen);
+ }
+ }
+ }
+
+ private static void skipDomainName(DataInputStream input) throws IOException {
+ byte labelLength = 0;
+ do {
+ labelLength = input.readByte();
+ input.skip(labelLength);
+ } while (labelLength != 0);
+ }
+
+ private static String longToIp(long ip) {
+ return ((ip >> 24) & 0xFF) + "." + ((ip >> 16) & 0xFF) + "." + ((ip >> 8) & 0xFF) + "." + (ip & 0xFF);
+ }
+ }
+
+ @Override
+ public boolean isActivate() {
+ return DnsConfig.enableUdpDns;
+ }
+
+ @Override
+ public String getServerApi() {
+ return DnsConfig.UDPDNS_SERVER_API;
+ }
+
+ @Override
+ public int getPriority() {
+ return 7;
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.log;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.os.Environment;
+import android.os.StatFs;
+
+/**
+ * 文件操作工具类
+ *
+ * @author xingyu10
+ *
+ */
+public class FileUtil {
+
+ /**
+ * 判断SD卡是否还有可用空间,小于10M为不可用
+ *
+ * @return
+ */
+ public static boolean haveFreeSpaceInSD() {
+ if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
+ StatFs st = new StatFs(Environment.getExternalStorageDirectory().getPath());
+ int blockSize = st.getBlockSize();
+ long available = st.getAvailableBlocks();
+ long availableSize = (blockSize * available);
+ if (availableSize < 1024 * 1024 * 10) {// //sd卡空间如果小于10M,就认为sd卡空间不足
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 获取SD卡的路径
+ *
+ * @return
+ */
+ public static String getSDPath() {
+ return Environment.getExternalStorageDirectory().getPath();
+ }
+
+ /**
+ * 写文件内容,一次只写一行
+ *
+ * @param file 目标文件
+ * @param append 是否追加
+ * @param line 一行字符串
+ */
+ public static void writeFileLine(File file, boolean append, String line) {
+ FileWriter writer = null;
+ try {
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ writer = new FileWriter(file, append);
+ String lineSeparator = System.getProperty("line.separator");
+ writer.write(line + lineSeparator);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (null != writer) {
+ try {
+ writer.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ /**
+ * 调整文件行数
+ * @param file 目标文件
+ * @param maxSize 最大的文件大小
+ * @param factor 缩容因子,每次缩容的百分比
+ */
+ public static void adjustFileSize(File file, int maxSize, float factor) {
+ if (null == file || !file.exists()) {
+ return;
+ }
+ if (file.length() < maxSize) {
+ return;
+ }
+ BufferedReader reader = null;
+ List<String> result = new ArrayList<String>();
+ FileWriter writer = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ result.add(line);
+ }
+ file.delete();
+ file.createNewFile();
+
+ writer = new FileWriter(file, true);
+ String lineSeparator = System.getProperty("line.separator");
+ int size = result.size();
+ int startPos = (int) (size * factor);
+ for (int i = startPos; i < size; i++) {
+ writer.write(result.get(i) + lineSeparator);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ if (file.exists()) {
+ file.delete();
+ }
+ } finally {
+ try {
+ reader.close();
+ writer.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.log;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.json.JSONException;
+import org.json.JSONStringer;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+
+import com.sina.util.dnscache.AppConfigUtil;
+
+public class HttpDnsLogManager implements IDnsLog {
+
+ /**
+ * 配置文件更新地址
+ */
+ public static String LOG_UPLOAD_API = "";
+
+ public static final boolean LOG_UPLOAD_SWITCH = false;
+
+ public static int sample_rate = 50;
+ /**
+ * 错误类型
+ */
+ public static final int TYPE_ERROR = 1;
+ /**
+ * 调试信息类型
+ */
+ public static final int TYPE_INFO = 2;
+ /**
+ * 测速类型
+ */
+ public static final int TYPE_SPEED = 3;
+ /**
+ * 日志文件的最大容量。8MB
+ */
+ private static final int DEFAULT_MAX_SIZE = 8 * 1024 * 1024;
+ /**
+ * 调整因子。取值大于0小于1
+ */
+ private static final float DEFAULT_FACTOR = 0.5f;
+ /**
+ * 日志文件
+ */
+ private File mLogFile;
+
+ private static HttpDnsLogManager mDnsLogManager;
+
+ /**
+ * 调试信息分类中的domain信息
+ */
+ public static final String ACTION_INFO_DOMAIN = "httpdns_domaininfo";
+ /**
+ * 调试信息分类中的pack信息
+ */
+ public static final String ACTION_INFO_PACK = "httpdns_packinfo";
+
+ /**
+ * 调试信息分类中的config信息
+ */
+ public static final String ACTION_INFO_CONFIG = "httpdns_configinfo";
+
+ /**
+ * 设备sp 和 server识别出口sp 不一致错误信息
+ */
+ public static final String ACTION_ERR_SPINFO = "httpdns_errspinfo";
+
+ /**
+ * 设备sp 和 server识别出口sp 不一致错误信息
+ */
+ public static final String ACTION_ERR_DOMAININFO = "httpdns_errdomaininfo";
+
+
+
+ private static final Object lock = new Object();
+ private static Handler mLogHandler;
+ /**设置日志上报的间隔为1小时*/
+ public static long time_interval = 1 * 60 * 60 * 1000;
+
+ public static HttpDnsLogManager getInstance() {
+
+ if (null == mDnsLogManager) {
+ synchronized (lock) {
+ if (null == mDnsLogManager) {
+ HandlerThread ht = new HandlerThread("logThread");
+ ht.start();
+ Looper looper = ht.getLooper();
+ mLogHandler = new Handler(looper);
+ mDnsLogManager = new HttpDnsLogManager();
+ }
+ }
+ }
+ return mDnsLogManager;
+ }
+
+ private HttpDnsLogManager() {
+ tryCreateLogFile();
+ }
+
+ private void tryCreateLogFile() {
+ if (FileUtil.haveFreeSpaceInSD()) {
+ mLogFile = new File(AppConfigUtil.getExternalCacheDir(), "httpdns.log");
+ if (null != mLogFile && !mLogFile.exists()) {
+ try {
+ mLogFile.createNewFile();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ } else {
+ mLogFile = null;
+ }
+ }
+
+ private void adjustFileSize(File file) {
+ FileUtil.adjustFileSize(file, DEFAULT_MAX_SIZE, DEFAULT_FACTOR);
+ }
+
+ @Override
+ public File getLogFile() {
+ synchronized (lock) {
+ return mLogFile;
+ }
+ }
+
+ @Override
+ public boolean deleteLogFile() {
+ synchronized (lock) {
+ if (null != mLogFile) {
+ return mLogFile.delete();
+ }
+ return false;
+ }
+ }
+
+ private String generateJsonStr(int type, String action, String body) {
+ JSONStringer jsonStringer = new JSONStringer();
+ try {
+ jsonStringer.object()//
+ .key("type").value(type)//
+ .key("action").value(action)//
+ .key("content").value(body)//
+ .key("versionName").value(AppConfigUtil.getVersionName())//
+ .key("did").value(AppConfigUtil.getDeviceId())//
+ .key("appkey").value(AppConfigUtil.getAppKey())//
+ .key("timestamp").value(System.currentTimeMillis())//
+ .endObject();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return "{}";
+ }
+ return jsonStringer.toString();
+ }
+
+ @Override
+ public void writeLog(int type, String action, String body) {
+ writeLog(type, action, body, false);
+ }
+
+ @Override
+ public void writeLog(final int type, final String action, final String body, final boolean enableSample) {
+ writeLog(type, action, body, enableSample, -1);
+ }
+
+ @Override
+ public void writeLog(final int type, final String action, final String body, final boolean enableSample, final int sampleRate) {
+ mLogHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (lock) {
+ // 做一个采样操作
+ boolean succ = true;
+ if (enableSample) {
+ if (sampleRate == -1) {
+ succ = (int) (Math.random() * sample_rate) == 0;
+ } else {
+ succ = (int) (Math.random() * sampleRate) == 0;
+ }
+ }
+ if (succ) {
+ if (null != mLogFile && !mLogFile.exists()) {
+ tryCreateLogFile();
+ }
+ if (null == mLogFile) {
+ return;
+ }
+ adjustFileSize(mLogFile);
+ String line = generateJsonStr(type, action, body);
+ FileUtil.writeFileLine(mLogFile, true, line);
+ }
+ }
+ }
+ });
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.log;
+
+import java.io.File;
+
+public interface IDnsLog {
+
+ /**
+ * 记录日志
+ *
+ * @param type
+ * 日志类型
+ * @param body
+ * 日志信息,建议用json字符串
+ */
+ void writeLog(int type, String action, String body);
+
+ void writeLog(int type, String action, String body, boolean enableSample);
+
+ void writeLog(int type, String action, String body, boolean enableSample, int sampleRate);
+
+ /**
+ * 获取日志文件
+ *
+ * @return
+ */
+ File getLogFile();
+
+ /**
+ * 删除文件
+ *
+ * @return
+ */
+ boolean deleteLogFile();
+}
--- /dev/null
+/**
+ *
+ */
+package com.sina.util.dnscache.model;
+
+
+/**
+ *
+ * 项目名称: DNSCache <br>
+ * 类名称: ConnectFailModel <br>
+ * 类描述: 链接异常数据模型 - 对应connect_fail表 <br>
+ * 创建人: fenglei <br>
+ * 创建时间: 2015-3-26 下午5:26:04 <br>
+ *
+ * 修改人: <br>
+ * 修改时间: <br>
+ * 修改备注: <br>
+ *
+ * @version V1.0
+ */
+public class ConnectFailModel {
+
+ public ConnectFailModel(){}
+
+ /**
+ * 链接失败表 自曾id <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } CONNECT_FAIL_ID 字段 <br>
+ */
+ public int id = -1 ;
+
+ /**
+ * 链接失败的ip地址 <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } CONNECT_FAIL_IP 字段 <br>
+ */
+ public int ip = -1 ;
+
+ /**
+ * 链接失败服务器的端口号 <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } CONNECT_FAIL_PORT 字段 <br>
+ */
+ public int port = -1 ;
+
+ /**
+ * 链接失败的错误代码,(一般都是http的错误代码) <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } CONNECT_FAIL_ERRCODE 字段 <br>
+ */
+ public String errcode = "" ;
+
+ /**
+ * 链接失败时本地网络类型 <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } CONNECT_FAIL_NETWORK_TYPE 字段 <br>
+ */
+ public String network_type = "" ;
+
+ /**
+ * 链接失败时如果是手机运营商,则统计运营商sp—code(为了重现现场收集数据) <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } CONNECT_FAIL_SPCODE 字段 <br>
+ */
+ public String spcode = "" ;
+
+ /**
+ * 链接该服务器总共的错误次数 <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } CONNECT_FAIL_COUNT 字段 <br>
+ */
+ public String count = "" ;
+
+ /**
+ * 链接该服务器最后失败时间 <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } CONNECT_FAIL_FINALLY_TIME 字段 <br>
+ */
+ public String finally_tiem = "" ;
+
+
+}
--- /dev/null
+/**
+ *
+ */
+package com.sina.util.dnscache.model;
+
+import java.util.ArrayList;
+
+import org.json.JSONException;
+import org.json.JSONStringer;
+
+import com.sina.util.dnscache.AppConfigUtil;
+import com.sina.util.dnscache.DNSCacheConfig;
+import com.sina.util.dnscache.Tools;
+
+/**
+ *
+ * 项目名称: DNSCache <br>
+ * 类名称: DomainModel <br>
+ * 类描述: 域名数据模型 - 对应domain表 <br>
+ * 创建人: fenglei <br>
+ * 创建时间: 2015-3-26 下午5:04:01 <br>
+ *
+ * 修改人: <br>
+ * 修改时间: <br>
+ * 修改备注: <br>
+ *
+ * @version V1.0
+ */
+public class DomainModel {
+
+
+ public DomainModel(){}
+
+ /**
+ * 自增id <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } DOMAIN_COLUMN_ID 字段 <br>
+ */
+ public long id = -1 ;
+
+ /**
+ * 域名 <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } DOMAIN_COLUMN_DOMAIN 字段 <br>
+ */
+ public String domain = "" ;
+
+ /**
+ * 运营商 <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } DOMAIN_COLUMN_SP 字段 <br>
+ */
+ public String sp = "" ;
+
+ /**
+ * 域名过期时间 <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } DOMAIN_COLUMN_TTL 字段 <br>
+ */
+ public String ttl = "0" ;
+
+ /**
+ * 域名最后查询时间 <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants } DOMAIN_COLUMN_TIME 字段 <br>
+ */
+ public String time = "0" ;
+
+
+
+
+ /**
+ * 域名关联的ip数组 <br>
+ */
+ public ArrayList<IpModel> ipModelArr = null ;
+
+
+
+ public String toString(){
+ String str = "" ;
+ str += "域名ID = " + id + "\n" ;
+ str += "域名 = " + domain + "\n" ;
+ str += "运营商ID = " + sp + "\n" ;
+ str += "域名过期时间: = " + ttl + "\n" ;
+ str += "域名最后查询时间:" + Tools.getStringDateShort(time) + "\n" ;
+ if( ipModelArr != null && ipModelArr.size() > 0 ){
+ for( IpModel temp : ipModelArr ){
+ if( temp == null ) continue ;
+ str += "-- " + temp.toString() ;
+ }
+ }
+
+ str += "------------------------------------------------------\n\n";
+ return str ;
+ }
+
+ public String tojson(){
+ JSONStringer jsonStringer = new JSONStringer();
+ try {
+ StringBuilder ipmodelStr = new StringBuilder();
+ ipmodelStr.append("[");
+ if (null != ipModelArr) {
+ for (IpModel ipModel : ipModelArr) {
+ ipmodelStr.append(ipModel.toJson() + ",");
+ }
+ }
+ if (ipmodelStr.toString().endsWith(",")) {
+ ipmodelStr.deleteCharAt(ipmodelStr.length() - 1);
+ }
+ ipmodelStr.append("]");
+
+ jsonStringer.object()//
+ .key("domain").value(domain)//
+ .key("sp").value(sp)//
+ .key("ttl").value(ttl)//
+ .key("time").value(time)//
+ .key("ipModelArr").value(ipmodelStr.toString())//
+ .endObject();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return "{}";
+ }
+ return jsonStringer.toString();
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ *
+ */
+package com.sina.util.dnscache.model;
+
+import org.json.JSONException;
+import org.json.JSONStringer;
+
+/**
+ *
+ * 项目名称: DNSCache 类名称: HttpDnsPack 类描述:
+ * 将httpdns返回的数据封装一层,方便日后httpdns接口改动不影响数据库模型。 并且该接口还会标识httpdns错误之后的一些信息用来上报 创建人:
+ * fenglei 创建时间: 2015-3-30 上午11:20:11
+ *
+ * 修改人: 修改时间: 修改备注:
+ *
+ * @version V1.0
+ */
+public class HttpDnsPack {
+
+ /**
+ * httpdns 接口返回字段 域名信息
+ */
+ public String domain = "";
+
+ /**
+ * httpdns 接口返回字段 请求的设备ip(也可能是sp的出口ip)
+ */
+ public String device_ip = "";
+
+ /**
+ * httpdns 接口返回字段 请求的设备sp运营商
+ */
+ public String device_sp = "";
+
+ /**
+ * httpdns 接口返回的a记录。(目前不包含cname别名信息)
+ */
+ public IP[] dns = null;
+
+ /**
+ * 本机识别的sp运营商,手机卡下运营商正常,wifi下为ssid名字
+ */
+ public String localhostSp = "";
+
+ /**
+ * httpdns 接口返回的原始信息
+ */
+ public String rawResult;
+
+ /**
+ * 打印该类相关变量信息
+ */
+ public String toString() {
+
+ String str = "HttpDnsPack class \n";
+ str += "domain:" + domain + "\n";
+ str += "device_ip:" + device_ip + "\n";
+ str += "device_sp:" + device_sp + "\n";
+
+ if (dns != null) {
+ str += "-------------------\n";
+ for (int i = 0; i < dns.length; i++) {
+ str += "dns[" + i + "]:" + dns[i] + "\n";
+ }
+ str += "-------------------\n";
+ }
+
+ return str;
+ }
+
+ /**
+ * A记录相关字段信息
+ */
+ public static class IP {
+
+ /**
+ * A记录IP
+ */
+ public String ip = "";
+
+ /**
+ * 域名A记录过期时间
+ */
+ public String ttl = "";
+
+ /**
+ * 服务器推荐使用的A记录 级别从0-10
+ */
+ public String priority = "";
+
+
+ /**
+ * 打印该类信息
+ */
+ public String toString() {
+ String str = "IP class \n";
+ str += "ip:" + ip + "\n";
+ str += "ttl:" + ttl + "\n";
+ str += "priority:" + priority + "\n";
+ return str;
+ }
+
+ public String toJson() {
+ JSONStringer jsonStringer = new JSONStringer();
+ try {
+ jsonStringer.object()//
+ .key("ip").value(ip)//
+ .key("ttl").value(ttl)//
+ .key("priority").value(priority)//
+ .endObject();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return "{}";
+ }
+ return jsonStringer.toString();
+ }
+
+ }
+
+ public String toJson() {
+ JSONStringer jsonStringer = new JSONStringer();
+ try {
+ StringBuilder ipArrayStr = new StringBuilder();
+ ipArrayStr.append("[");
+ if (null != dns) {
+ for (IP ip : dns) {
+ ipArrayStr.append(ip.toJson() + ",");
+ }
+ }
+ if (ipArrayStr.toString().endsWith(",")) {
+ ipArrayStr.deleteCharAt(ipArrayStr.length() - 1);
+ }
+ ipArrayStr.append("]");
+
+ jsonStringer.object()//
+ .key("domain").value(domain)//
+ .key("device_ip").value(device_ip)//
+ .key("device_sp").value(device_sp)//
+ .key("localhostSp").value(localhostSp)//
+ .key("rawResult").value(rawResult)//
+ .key("ipArray").value(ipArrayStr.toString())//
+ .endObject();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return "{}";
+ }
+ return jsonStringer.toString();
+ }
+
+}
--- /dev/null
+/**
+ *
+ */
+package com.sina.util.dnscache.model;
+
+import org.json.JSONException;
+import org.json.JSONStringer;
+
+import com.sina.util.dnscache.Tools;
+
+
+/**
+ *
+ * 项目名称: DNSCache <br>
+ * 类名称: IpModel <br>
+ * 类描述: ip数据模型 - 对应ip表 <br>
+ * 创建人: fenglei <br>
+ * 创建时间: 2015-3-26 下午5:23:06 <br>
+ *
+ * 修改人: <br>
+ * 修改时间: <br>
+ * 修改备注: <br>
+ *
+ * @version V1.0
+ */
+public class IpModel {
+
+ public IpModel(){}
+
+ /**
+ * 自增id <br>
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_ID }字段 <br>
+ */
+ public long id = -1 ;
+
+ /**
+ * domain id 关联id
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_DOMAIN_ID }字段 <br>
+ */
+ public long d_id = -1 ;
+
+ /**
+ * 服务器ip地址
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_PORT }字段 <br>
+ */
+ public String ip = "" ;
+
+ /**
+ * ip服务器对应的端口
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_PORT }字段 <br>
+ */
+ public int port = -1 ;
+
+ /**
+ * ip服务器对应的sp运营商
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_SP }字段 <br>
+ */
+ public String sp = "" ;
+
+ /**
+ * ip过期时间
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_TTL }字段 <br>
+ */
+ public String ttl = "0" ;
+
+ /**
+ * ip服务器优先级-排序算法策略使用
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_PRIORITY }字段 <br>
+ */
+ public String priority = "0" ;
+ /**
+ * 访问ip服务器的往返时延
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_PRIORITY }}字段 <br>
+ */
+ public String rtt = "0" ;
+
+ /**
+ * ip服务器链接产生的成功数
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_SUCCESS_NUM }字段 <br>
+ */
+ public String success_num = "0" ;
+
+ /**
+ * ip服务器链接产生的错误数
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_ERR_NUM }字段 <br>
+ */
+ public String err_num = "0" ;
+
+ /**
+ * ip服务器最后成功链接时间
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_FINALLY_SUCCESS_TIME }字段 <br>
+ */
+ public String finally_success_time = "0" ;
+
+ /**
+ * ip服务器最后失败链接时间
+ *
+ * 该字段映射类 {@link com.sina.util.dnscache.cache.DBConstants#IP_COLUMN_FINALLY_FAIL_TIME }字段 <br>
+ */
+ public String finally_fail_time = "0" ;
+
+
+
+ /**
+ * 评估体系 评分分值
+ */
+ public float grade = 0 ;
+
+
+ public String toString(){
+
+ String str = "*\n" ;
+
+ str += "-- 服务器id = " + id + "\n" ;
+ str += "-- 服务器ip = " + ip + "\n" ;
+ str += "-- 域名ID索引 = " + d_id + "\n" ;
+ str += "-- 服务器端口 = " + port + "\n" ;
+ str += "-- 运营商 = " + sp + "\n" ;
+ str += "-- 过期时间 = " + ttl + "\n" ;
+ str += "-- 优先级 = " + priority + "\n" ;
+ str += "-- 访问ip服务器的往返时延 = " + rtt + "\n" ;
+ str += "-- 历史成功次数 = " + success_num + "\n" ;
+ str += "-- 历史错误次数 = " + err_num + "\n" ;
+ str += "-- 最后一次访问成功时间 = " + Tools.getStringDateShort(finally_success_time) + "\n" ;
+ str += "-- 最后一次访问失败时间 = " + Tools.getStringDateShort(finally_fail_time) + "\n" ;
+ str += "-- 系统对服务器的评分 = " + grade + "\n" ;
+ str += "\n" ;
+
+ return str ;
+ }
+
+ public String toJson(){
+ JSONStringer jsonStringer = new JSONStringer();
+ try {
+ jsonStringer.object()//
+ .key("id").value(id)//
+ .key("d_id").value(d_id)//
+ .key("ip").value(ip)//
+ .key("port").value(port)//
+ .key("ttl").value(ttl)//
+ .key("priority").value(priority)//
+ .key("success_num").value(success_num)//
+ .key("err_num").value(err_num)//
+ .key("finally_success_time").value(finally_success_time)//
+ .key("finally_fail_time").value(finally_fail_time)//
+ .endObject();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return "{}";
+ }
+ return jsonStringer.toString();
+ }
+
+}
--- /dev/null
+/**
+ *
+ */
+package com.sina.util.dnscache.net;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.params.ConnManagerParams;
+import org.apache.http.conn.params.ConnPerRouteBean;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+import com.sina.util.dnscache.Tools;
+
+/**
+ *
+ * 项目名称: DNSCache 类名称: ApacheHttpClientNetworkRequests
+ * 类描述: 轻量级的网络请求库
+ * 创建人: fenglei
+ * 使用 Apache HttpClient 实现网络请求
+ * 创建时间: 2015-3-30 上午11:50:49
+ *
+ * 修改人: xingyu10
+ * 修改时间: 2015-9-9
+ * 修改备注: HTTPS不进行域名校验
+ *
+ * @version V2.0
+ */
+public class ApacheHttpClientNetworkRequests implements INetworkRequests {
+ private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000;
+ private static final int CONNECTION_TIMEOUT = 30 * 1000;
+ private static final int SOCKET_BUFFER_SIZE = 8192;
+
+ public String requests(String url) {
+ return requests(url, "");
+ }
+
+ public static HttpClient newInstance() {
+ HttpParams params = new BasicHttpParams();
+ // 不自动处理重定向请求
+ params.setParameter(ClientPNames.HANDLE_REDIRECTS, false);
+ HttpConnectionParams.setStaleCheckingEnabled(params, true);
+ HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
+ HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT);
+ HttpConnectionParams.setSocketBufferSize(params, SOCKET_BUFFER_SIZE);
+ HttpConnectionParams.setTcpNoDelay(params, true);
+ ConnManagerParams.setMaxTotalConnections(params, 50);
+ ConnPerRouteBean connPerRoute = new ConnPerRouteBean();
+ connPerRoute.setDefaultMaxPerRoute(4);
+ ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
+
+ SchemeRegistry schemeRegistry = new SchemeRegistry();
+ schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+ SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
+ socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+ schemeRegistry.register(new Scheme("https", socketFactory, 443));
+ ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);
+ return new DefaultHttpClient(manager, params);
+ }
+
+ @Override
+ public String requests(String url, String host) {
+ HashMap<String, String> map = null;
+ if (host == null || host.equals("")) {
+ map = null;
+ } else {
+ map = new HashMap<String, String>();
+ map.put("host", host);
+ }
+
+ return requests(url, map);
+ }
+
+ @Override
+ public String requests(String url, HashMap<String, String> head) {
+
+ String result = null;
+ BufferedReader reader = null;
+
+ try {
+ HttpClient client = newInstance();
+ HttpGet request = new HttpGet();
+
+ if (head != null) {
+ for (Entry<String, String> entry : head.entrySet()) {
+ Tools.log("TAG", "" + entry.getKey() + " - " + entry.getValue());
+ request.addHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ request.setURI(new URI(url));
+ HttpResponse response = client.execute(request);
+
+ reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+
+ StringBuffer strBuffer = new StringBuffer("");
+ String line = null;
+
+ while ((line = reader.readLine()) != null) {
+ strBuffer.append(line);
+ }
+ result = strBuffer.toString();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ reader = null;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public byte[] requestsByteArr(String url, HashMap<String, String> head) {
+
+ byte[] result = null;
+
+ try {
+ HttpClient client = newInstance();
+ HttpGet request = new HttpGet();
+
+ if (head != null) {
+ for (Entry<String, String> entry : head.entrySet()) {
+ Tools.log("TAG", "" + entry.getKey() + " - " + entry.getValue());
+ request.addHeader(entry.getKey(), entry.getValue());
+ }
+ }
+
+ request.setURI(new URI(url));
+ HttpResponse response = client.execute(request);
+
+ result = readStream(response.getEntity().getContent());
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ }
+
+ return result;
+ }
+
+ /*
+ * 得到图片字节流 数组大小
+ */
+ public static byte[] readStream(InputStream inStream) {
+
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+
+ try {
+ byte[] buffer = new byte[1024];
+ int len = 0;
+ while ((len = inStream.read(buffer)) != -1) {
+ outStream.write(buffer, 0, len);
+ }
+ outStream.close();
+ inStream.close();
+
+ } catch (Exception e) {
+ }
+
+ Tools.log("TAG", "outStream.toByteArray()=" + outStream.toByteArray());
+
+ return outStream.toByteArray();
+ }
+
+ public static boolean upLoadFile(String url, File file) {
+ boolean result = false;
+ try {
+ if (null == url || null == file || !file.exists() || file.length() < 1) {
+ return false;
+ }
+ /**
+ * 第一部分
+ */
+ URL urlObj = new URL(url);
+ HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
+
+ /**
+ * 设置关键值
+ */
+ con.setRequestMethod("POST"); // 以Post方式提交表单,默认get方式
+ con.setDoInput(true);
+ con.setDoOutput(true);
+ con.setUseCaches(false); // post方式不能使用缓存
+
+ // 设置请求头信息
+ con.setRequestProperty("Connection", "Keep-Alive");
+ con.setRequestProperty("Charset", "UTF-8");
+
+ // 设置边界
+ String BOUNDARY = "----------" + System.currentTimeMillis();
+ con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
+
+ // 请求正文信息
+
+ // 第一部分:
+ StringBuilder sb = new StringBuilder();
+ sb.append("--"); // ////////必须多两道线
+ sb.append(BOUNDARY);
+ sb.append("\r\n");
+ sb.append("Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n");
+ sb.append("Content-Type:application/octet-stream\r\n\r\n");
+
+ byte[] head = sb.toString().getBytes("utf-8");
+
+ // 获得输出流
+ OutputStream out = new DataOutputStream(con.getOutputStream());
+ out.write(head);
+
+ // 文件正文部分
+ DataInputStream in = new DataInputStream(new FileInputStream(file));
+ int bytes = 0;
+ byte[] bufferOut = new byte[1024];
+ while ((bytes = in.read(bufferOut)) != -1) {
+ out.write(bufferOut, 0, bytes);
+ }
+ in.close();
+
+ // 结尾部分
+ byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
+ out.write(foot);
+ out.flush();
+ out.close();
+
+ int statusCode = con.getResponseCode();
+ if (statusCode == 200) {
+ result = true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+}
--- /dev/null
+/**
+ *
+ */
+package com.sina.util.dnscache.net;
+
+import java.util.HashMap;
+
+/**
+ *
+ * 项目名称: DNSCache
+ * 类名称: INetworkRequests
+ * 类描述: 由于该工程是一个辅助lib 尽量复用项目工程里在使用的网络库。
+ * 创建人: fenglei
+ * 创建时间: 2015-3-30 上午11:34:07
+ *
+ * 修改人:
+ * 修改时间:
+ * 修改备注:
+ *
+ * @version V1.0
+ */
+public interface INetworkRequests {
+
+ /**
+ * 请求网络接口
+ * @return 返回url数据内容
+ */
+ public String requests(String url) ;
+
+ /**
+ * 请求网络接口 (带host访问)
+ *
+ * @return 返回url数据内容
+ */
+ public String requests(String url, String host) ;
+
+ /**
+ * 请求网络接口 (多个head访问)
+ *
+ * @return 返回url数据内容
+ */
+ public String requests(String url, HashMap<String, String> head) ;
+
+ /**
+ * 请求网络接口 (多个head访问)
+ *
+ * @return 返回url数据内容
+ */
+ public byte[] requestsByteArr(String url, HashMap<String, String> head) ;
+
+}
--- /dev/null
+package com.sina.util.dnscache.net.networktype;
+
+public class Constants {
+
+ // //网络类型////
+
+ /**
+ * 无网络
+ */
+ public final static short NETWORK_TYPE_UNCONNECTED = -1;
+ /**
+ * 未知网络
+ */
+ public final static short NETWORK_TYPE_UNKNOWN = 0;
+ /**
+ * WIFI网络
+ */
+ public final static short NETWORK_TYPE_WIFI = 1;
+ /**
+ * 2G网络
+ */
+ public final static short NETWORK_TYPE_2G = 2;
+ /**
+ * 3G网络
+ */
+ public final static short NETWORK_TYPE_3G = 3;
+ /**
+ * 4G网络
+ */
+ public final static short NETWORK_TYPE_4G = 4;
+
+ // //网络运营商标识码///
+
+ /**
+ * 未知运营商
+ */
+ public final static int MOBILE_UNKNOWN = 0 ; // 未知运营商
+ /**
+ * mobile-中国电信
+ */
+ public final static int MOBILE_TELCOM = 3 ; // 中国电信
+ /**
+ * mobile-中国联通
+ */
+ public final static int MOBILE_UNICOM = 5; // 中国联通
+ /**
+ * mobile-中国移动
+ */
+ public final static int MOBILE_CHINAMOBILE = 4; // 中国移动
+
+
+ // 有时间可以把网络类型常量定义方式改成自学习模式,就不用每次有新发现的类型在重新填写。
+
+ public final static String NETWORK_TYPE_TO_STR(int type) {
+ String str = "";
+ switch (type) {
+ case NETWORK_TYPE_UNCONNECTED:
+ str = "无网络";
+ break;
+ case NETWORK_TYPE_UNKNOWN:
+ str = "未知网络";
+ break;
+ case NETWORK_TYPE_WIFI:
+ str = "WIFI网络";
+ break;
+ case NETWORK_TYPE_2G:
+ str = "2G网络";
+ break;
+ case NETWORK_TYPE_3G:
+ str = "3G网络";
+ break;
+ case NETWORK_TYPE_4G:
+ str = "4G网络";
+ break;
+ }
+ return str;
+ }
+
+ public final static String SP_TO_STR(int type) {
+
+ String str = "";
+
+ switch (type) {
+ case MOBILE_UNKNOWN:
+ str = "未知运营商";
+ break;
+ case MOBILE_TELCOM:
+ str = "中国电信";
+ break;
+ case MOBILE_UNICOM:
+ str = "中国联通";
+ break;
+ case MOBILE_CHINAMOBILE:
+ str = "中国移动 ";
+ break;
+ }
+
+ return str;
+
+ }
+
+}
--- /dev/null
+package com.sina.util.dnscache.net.networktype;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.apache.http.conn.util.InetAddressUtils;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.telephony.TelephonyManager;
+
+
+@SuppressLint("NewApi")
+public class NetworkManager extends Constants{
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ private static NetworkManager Instance = null;
+
+ public NetworkManager() { }
+
+ public static NetworkManager CreateInstance(Context context) {
+
+ setContext(context) ;
+
+ if (Instance == null) {
+ Instance = new NetworkManager();
+ Instance.Init();
+ }
+ return Instance;
+ }
+
+ public static NetworkManager getInstance() {
+ return Instance;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ private static Context sContext;
+
+ public static void setContext(Context ctx) {
+ Context app = ctx.getApplicationContext();
+ if (sContext == app) {
+ return;
+ }
+ sContext = app;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 当前网络类型
+ */
+ public int NETWORK_TYPE = -1111;
+
+ /**
+ * 当前网络类型名字
+ */
+ public String NETWORK_TYPE_STR = "-1111";
+
+ /**
+ * 当前SP类型
+ */
+ public int SP_TYPE = -1111;
+
+ /**
+ * 当前SP类型名字
+ */
+ public String SP_TYPE_STR = "-1111";
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * IP地址
+ */
+ public String IP_ADDRESS = "-1111";
+
+ /**
+ * MAC地址
+ */
+ public String MACADDRESS = "-1111";
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * 公网IP
+ */
+ public String NETWORK_IP_ADDRESS = "-1111";
+
+
+ // ///////////////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * 初始化网络环境信息数据,可重复
+ */
+ public void Init() {
+
+ new Thread(new Runnable() {
+ public void run() {
+ // TODO Auto-generated method stub
+
+ Thread.currentThread().setName("Net Work Manager Init");
+
+ NETWORK_TYPE = Util.getNetworkType() ;
+
+ switch( NETWORK_TYPE ){
+
+ case Constants.NETWORK_TYPE_UNCONNECTED:
+ case Constants.NETWORK_TYPE_UNKNOWN:
+ break;
+
+ case Constants.NETWORK_TYPE_WIFI:
+ IP_ADDRESS = Util.getLocalIpAddress();
+ MACADDRESS = Util.getRouteMac() ;
+ SP_TYPE = Util.getWifiSp();
+ break;
+
+ case Constants.NETWORK_TYPE_2G:
+ case Constants.NETWORK_TYPE_3G:
+ case Constants.NETWORK_TYPE_4G:
+ SP_TYPE = Util.getSP();
+ break;
+ }
+
+ NETWORK_TYPE_STR = Constants.NETWORK_TYPE_TO_STR(NETWORK_TYPE) ;
+
+ if( NETWORK_TYPE != NETWORK_TYPE_WIFI){
+ SP_TYPE_STR = Constants.SP_TO_STR(SP_TYPE) ;
+ }else{
+ SP_TYPE_STR = Util.getWifiSSID(NetworkManager.sContext) ;
+ }
+
+
+ }
+ }).start();
+
+ }
+
+
+ public String toString(){
+ String str = "" ;
+
+ str += "当前网络类型ID:" + NETWORK_TYPE + "\n" ;
+ str += "当前网络类型名字:" + NETWORK_TYPE_STR + "\n\n" ;
+
+ str += "当前服务商类型ID:" + SP_TYPE + "\n" ;
+ str += "当前服务商类型名字:" + SP_TYPE_STR + "\n\n" ;
+
+ str += "内网IP:" + IP_ADDRESS + "\n" ;
+ str += "公网IP:" + NETWORK_IP_ADDRESS + "\n" ;
+ str += "当前MAC:" + MACADDRESS + "\n\n" ;
+
+ return str ;
+ }
+
+
+ /**
+ * 获取 sp id
+ * @return
+ */
+ public String getSPID(){
+ if( NETWORK_TYPE == NETWORK_TYPE_WIFI ){
+ return SP_TYPE_STR;
+ }
+ return String.valueOf( SP_TYPE ) ;
+ }
+
+
+ public static class Util {
+
+ /**
+ * 获取本机IP函数
+ */
+ public static String getLocalIpAddress() {
+ try {
+ String ipv4;
+ ArrayList<NetworkInterface> mylist = Collections.list(NetworkInterface.getNetworkInterfaces());
+ for (NetworkInterface ni : mylist) {
+ ArrayList<InetAddress> iaList = Collections.list(ni.getInetAddresses());
+ for (InetAddress address : iaList) {
+ if (!address.isLoopbackAddress() && InetAddressUtils.isIPv4Address(ipv4 = address.getHostAddress())) {
+ return ipv4;
+ }
+ }
+ }
+ } catch (SocketException ex) {
+ ex.printStackTrace() ;
+ }
+ return "0";
+ }
+
+ /**
+ * 获取本机MAC地址
+ */
+ public static String getRouteMac() {
+ try {
+ WifiManager wifiManager = (WifiManager) sContext.getSystemService(Context.WIFI_SERVICE);
+ WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+ if (wifiInfo == null) {
+ return "0";
+ }
+ return wifiInfo.getBSSID();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ }
+ return "0";
+ }
+
+
+ /**
+ * 获取运营商代码
+ */
+ public static int getSP() {
+
+ int code = Constants.MOBILE_UNKNOWN;
+
+ if (sContext != null) {
+
+ try {
+ TelephonyManager telManager = (TelephonyManager) sContext.getSystemService(Context.TELEPHONY_SERVICE);
+ String operator = telManager.getSimOperator();
+
+ if (operator != null) {
+ if (operator.equals("46000") || operator.equals("46002")
+ || operator.equals("46007") || operator.equals("46020")) {
+
+ /** 中国移动 */
+ code = Constants.MOBILE_CHINAMOBILE;
+ } else if (operator.equals("46001") || operator.equals("46006")) {
+
+ /** 中国联通 */
+ code = Constants.MOBILE_UNICOM;
+ } else if (operator.equals("46003") || operator.equals("46005")) {
+
+ /** 中国电信 */
+ code = Constants.MOBILE_TELCOM;
+ }
+
+ }
+ } catch (Exception e) {
+
+ e.printStackTrace();
+ }
+ }
+
+ return code;
+ }
+
+
+ /**
+ * 获取自定义当前联网类型
+ *
+ * @return 网络类型。-1为网络不可用;0为未知网络;1为WIFI;2为2G;3为3G;4为4G
+ */
+ public static int getNetworkType() {
+
+ try {
+
+ if (sContext != null) {
+
+ ConnectivityManager connectivity = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (connectivity == null) {
+ return Constants.NETWORK_TYPE_UNKNOWN;
+ }
+
+ NetworkInfo activeNetInfo = connectivity.getActiveNetworkInfo();
+ if (activeNetInfo == null) {
+ return Constants.NETWORK_TYPE_UNCONNECTED;
+ }
+
+ if (!activeNetInfo.isAvailable() || !activeNetInfo.isConnected()) {
+ return Constants.NETWORK_TYPE_UNCONNECTED;
+ }
+
+ if (activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ return Constants.NETWORK_TYPE_WIFI;
+
+ } else if (activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
+
+ switch (activeNetInfo.getSubtype()) {
+ case TelephonyManager.NETWORK_TYPE_CDMA:// ~ 14-64 kbps
+ case TelephonyManager.NETWORK_TYPE_IDEN:// ~25 kbps
+ case TelephonyManager.NETWORK_TYPE_1xRTT:// ~ 50-100 kbps
+ case TelephonyManager.NETWORK_TYPE_EDGE:// ~ 50-100 kbps
+ case TelephonyManager.NETWORK_TYPE_GPRS:// ~ 100 kbps
+ return Constants.NETWORK_TYPE_2G;
+
+ case TelephonyManager.NETWORK_TYPE_EVDO_0:// ~ 400-1000 kbps
+ case TelephonyManager.NETWORK_TYPE_UMTS:// ~ 400-7000 kbps
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:// ~ 600-1400 kbps
+ case TelephonyManager.NETWORK_TYPE_HSPA:// ~ 700-1700 kbps
+ case TelephonyManager.NETWORK_TYPE_HSUPA:// ~ 1-23 Mbps
+ case TelephonyManager.NETWORK_TYPE_HSDPA:// ~ 2-14 Mbps
+ case 15: // 对应TelephonyManager.NETWORK_TYPE_HSPAP: 在api level 13下没有此值,但存在此网络类型,下面直接用数值代替
+ return Constants.NETWORK_TYPE_3G;
+
+ case 13: // 对应TelephonyManager.NETWORK_TYPE_LTE
+ return Constants.NETWORK_TYPE_4G;
+
+ case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+ default:
+ return Constants.NETWORK_TYPE_UNKNOWN;
+ }
+ } else {
+ return Constants.NETWORK_TYPE_UNKNOWN;
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return Constants.NETWORK_TYPE_UNCONNECTED;
+ }
+
+ /**
+ * 获取wifi运营商
+ * @return
+ */
+ public static int getWifiSp(){
+
+ return 0 ;
+ }
+
+ /**
+ * 获取WifiSSID
+ * @param context
+ * @return
+ */
+ public static String getWifiSSID(Context context){
+ WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ WifiInfo info = wifiMgr.getConnectionInfo();
+ String wifiId = info != null ? info.getSSID() : null;
+ return wifiId ;
+ }
+
+ }
+
+}
--- /dev/null
+package com.sina.util.dnscache.net.networktype;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.text.TextUtils;
+
+import com.sina.util.dnscache.DNSCache;
+
+public class NetworkStateReceiver extends BroadcastReceiver {
+
+ public String TAG = "TAG_NET" ;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+
+ String action = intent.getAction();
+ if (TextUtils.equals(action, ConnectivityManager.CONNECTIVITY_ACTION)) {
+ NetworkInfo networkInfo = getActiveNetwork(context);
+ if( networkInfo != null ){
+
+ // 刷新网络环境
+ if( NetworkManager.getInstance() != null ) {
+ NetworkManager.getInstance().Init();
+ if( DNSCache.getInstance() != null ){
+ DNSCache.getInstance().onNetworkStatusChanged(networkInfo);
+ }
+ }
+ }
+ }
+ }
+
+ public static NetworkInfo getActiveNetwork(Context context) {
+ if (context == null)
+ return null;
+ ConnectivityManager mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (mConnMgr == null)
+ return null;
+
+ NetworkInfo aActiveInfo = mConnMgr.getActiveNetworkInfo(); // 获取活动网络连接信息
+ return aActiveInfo;
+ }
+
+ public static void register(Context context) {
+ IntentFilter mFilter = new IntentFilter();
+ mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ context.registerReceiver(new NetworkStateReceiver(), mFilter);
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.query;
+
+import com.sina.util.dnscache.model.DomainModel;
+
+/**
+*
+* 项目名称: DNSCache <br>
+* 类名称: IQuery <br>
+* 类描述: 查询模块 对外接口 <br>
+* 创建人: fenglei <br>
+* 创建时间: 2015-4-15 下午5:23:06 <br>
+*
+* 修改人: <br>
+* 修改时间: <br>
+* 修改备注: <br>
+*
+* @version V1.0
+*/
+public interface IQuery {
+
+ public DomainModel queryDomainIp(String sp, String host) ;
+
+
+ public DomainModel getCacheDomainIp(String sp, String host) ;
+}
--- /dev/null
+package com.sina.util.dnscache.query;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.cache.IDnsCache;
+import com.sina.util.dnscache.model.DomainModel;
+import com.sina.util.dnscache.model.IpModel;
+import com.sina.util.dnscache.speedtest.SpeedtestManager;
+
+/**
+*
+* 项目名称: DNSCache <br>
+* 类名称: QueryManager <br>
+* 类描述: 查询模块管理类 <br>
+* 创建人: fenglei <br>
+* 创建时间: 2015-4-15 下午5:23:06 <br>
+*
+* 修改人: <br>
+* 修改时间: <br>
+* 修改备注: <br>
+*
+* @version V1.0
+*/
+public class QueryManager implements IQuery {
+
+ private IDnsCache dnsCache = null ;
+
+ public QueryManager( IDnsCache dnsCache ){
+
+ this.dnsCache = dnsCache ;
+ }
+
+ /**
+ * 根据host名字查询server ip
+ * @return
+ */
+ @Override
+ public DomainModel queryDomainIp(String sp, String host) {
+
+ // 从缓存中查询,如果为空 情况有两种 1:没有缓存数据 2:数据过期
+ DomainModel domainModel = getCacheDomainIp(sp, host);
+
+ // 如果缓存是无效数据,则取local返回
+ if (inValidData(domainModel)) {
+
+ String[] ipList = null;
+ try {
+ InetAddress[] addresses = InetAddress.getAllByName(host);
+ ipList = new String[addresses.length];
+ for (int i = 0; i < addresses.length; i++) {
+ ipList[i] = addresses[i].getHostAddress();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ if (null != ipList) {
+ domainModel = new DomainModel();
+ domainModel.id = -1;
+ domainModel.domain = host;
+ domainModel.sp = sp;
+ domainModel.ttl = "60";
+ domainModel.time = String.valueOf(System.currentTimeMillis());
+ domainModel.ipModelArr = new ArrayList<IpModel>();
+ for (int i = 0; i < ipList.length; i++) {
+ domainModel.ipModelArr.add(new IpModel());
+ domainModel.ipModelArr.get(i).ip = ipList[i];
+ domainModel.ipModelArr.get(i).sp = sp;
+ }
+ dnsCache.addMemoryCache(host, domainModel);
+ }
+ }
+ return domainModel;
+ }
+
+ /**
+ * 是否是无效数据。判断依据:
+ * 1.domainModel为null
+ * 2.domainModel.ipModelArr == null
+ * 3.domainModel.ipModelArr.size() == 0
+ * 4.domainModel.ipModelArr的rtt都是计算都出错,即都不通
+ * @param domainModel
+ * @return
+ */
+ private boolean inValidData(DomainModel domainModel) {
+ if (domainModel == null || domainModel.ipModelArr == null || domainModel.ipModelArr.size() == 0) {
+ return true;
+ }
+ ArrayList<IpModel> ips = domainModel.ipModelArr;
+ for (IpModel ipModel : ips) {
+ //只要有一个是通的,就认为是有效数据
+ if (!("" + SpeedtestManager.MAX_OVERTIME_RTT).equals(ipModel.rtt)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 从缓存层获取获取数据
+ * @param sp
+ * @param host
+ * @return
+ */
+ public DomainModel getCacheDomainIp(String sp, String host){
+ return dnsCache.getDnsCache(sp, host) ;
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.score;
+
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.model.IpModel;
+
+
+public interface IPlugIn {
+
+ /**
+ * 插件实现计算分值的方法
+ */
+ public abstract void run( ArrayList<IpModel> list );
+
+ abstract float getWeight();
+
+ abstract boolean isActivated();
+}
--- /dev/null
+package com.sina.util.dnscache.score;
+
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.model.DomainModel;
+import com.sina.util.dnscache.model.IpModel;
+
+/**
+ * Created by fenglei on 15/4/21.
+ */
+public interface IScore {
+
+ public String[] serverIpScore(DomainModel domainModel) ;
+
+ public String[] ListToArr( ArrayList<IpModel> list) ;
+}
--- /dev/null
+package com.sina.util.dnscache.score;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import com.sina.util.dnscache.model.IpModel;
+import com.sina.util.dnscache.score.plugin.ErrNumPlugin;
+import com.sina.util.dnscache.score.plugin.PriorityPlugin;
+import com.sina.util.dnscache.score.plugin.SpeedTestPlugin;
+import com.sina.util.dnscache.score.plugin.SuccessNumPlugin;
+import com.sina.util.dnscache.score.plugin.SuccessTimePlugin;
+
+public class PlugInManager {
+
+ public ArrayList<IPlugIn> plugIn = new ArrayList<IPlugIn>();
+
+ public static float SpeedTestPluginNum = 40;
+ public static float PriorityPluginNum = 60;
+ public static float SuccessNumPluginNum = 10;
+ public static float ErrNumPluginNum = 10;
+ public static float SuccessTimePluginNum = 10;
+
+ public PlugInManager() {
+
+ plugIn.add(new SpeedTestPlugin()); // 速度插件
+ plugIn.add(new PriorityPlugin()); // 优先级推荐插件
+ plugIn.add(new SuccessNumPlugin());
+ plugIn.add(new ErrNumPlugin()); // 历史错误次数插件
+ plugIn.add(new SuccessTimePlugin());
+ }
+
+ public void run(ArrayList<IpModel> list) {
+ if (list == null || list.size() == 0) {
+ return;
+ }
+ //恢复得分为0
+ for (IpModel temp : list) {
+ if (null != temp) {
+ temp.grade = 0;
+ } else {
+ return;
+ }
+ }
+ for (IPlugIn plug : plugIn) {
+ if (plug.isActivated()) {
+ plug.run(list);
+ }
+ }
+ ipModelSort(list);
+ }
+
+ public void ipModelSort(ArrayList<IpModel> list) {
+ Collections.sort(list, new IpModelSort());
+ }
+
+ class IpModelSort implements Comparator<IpModel> {
+ @Override
+ public int compare(IpModel lhs, IpModel rhs) {
+ return (int) (rhs.grade - lhs.grade);
+ }
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.score;
+
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.Tools;
+import com.sina.util.dnscache.model.DomainModel;
+import com.sina.util.dnscache.model.IpModel;
+
+/**
+ *
+ * 对 ip 进行排序
+ *
+ * Created by fenglei on 15/4/21.
+ */
+public class ScoreManager implements IScore {
+
+ /**
+ * 是否开启排序开关
+ */
+ public static boolean IS_SORT = true ;
+
+ private PlugInManager plugInManager = new PlugInManager() ;
+
+ @Override
+ public String[] serverIpScore(DomainModel domainModel) {
+
+ String[] IpArr = null ;
+
+ // 数据库中得数据,进行排序 , 当ipmodelSize 大于1个的时候在参与排序
+ if (domainModel.ipModelArr.size() > 1) {
+ if (IS_SORT) {
+ plugInManager.run(domainModel.ipModelArr);
+ } else {
+ Tools.randomSort(domainModel.ipModelArr);
+ }
+ }
+
+ // 转换数据格式
+ IpArr = ListToArr(domainModel.ipModelArr) ;
+
+ return IpArr;
+ }
+
+ public String[] ListToArr( ArrayList<IpModel> list){
+ if(list == null || list.size() == 0 ) return null ;
+ String[] IpArr = new String[list.size()];
+ for (int i = 0; i < list.size(); i++) {
+ if( list.get(i) == null ) continue ;
+ IpArr[i] = list.get(i).ip;
+ }
+ return IpArr ;
+ }
+
+
+}
--- /dev/null
+package com.sina.util.dnscache.score.plugin;
+
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.model.IpModel;
+import com.sina.util.dnscache.score.IPlugIn;
+import com.sina.util.dnscache.score.PlugInManager;
+
+public class ErrNumPlugin implements IPlugIn {
+
+ @Override
+ public void run(ArrayList<IpModel> list) {
+ // 查找到最大错误数
+ float MAX_ERRNUM = 0;
+ for (IpModel temp : list) {
+ if (temp.err_num == null || temp.err_num.equals(""))
+ continue;
+ float err_num = Float.parseFloat(temp.err_num);
+ MAX_ERRNUM = Math.max(MAX_ERRNUM, err_num);
+ }
+ // 计算比值
+ if (MAX_ERRNUM == 0) {
+ return;
+ }
+ float bi = getWeight() / MAX_ERRNUM;
+ // 计算得分
+ for (IpModel temp : list) {
+ if (temp.err_num == null || temp.err_num.equals("")){
+ continue;
+ }
+ float err_num = Float.parseFloat(temp.err_num);
+ temp.grade += (err_num - (err_num * bi)); // 错误最少的 得分应该最高
+ }
+ }
+
+ @Override
+ public float getWeight() {
+ return PlugInManager.ErrNumPluginNum;
+ }
+
+ @Override
+ public boolean isActivated() {
+ return true;
+ }
+
+}
--- /dev/null
+package com.sina.util.dnscache.score.plugin;
+
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.model.IpModel;
+import com.sina.util.dnscache.score.IPlugIn;
+import com.sina.util.dnscache.score.PlugInManager;
+
+public class PriorityPlugin implements IPlugIn {
+
+ @Override
+ public void run(ArrayList<IpModel> list) {
+ // 查找到最大优先级
+ float MAX_PRIORITY = 0;
+ for (IpModel temp : list) {
+ if (temp.priority == null || temp.priority.equals(""))
+ continue;
+ float priority = Float.parseFloat(temp.priority);
+ MAX_PRIORITY = Math.max(MAX_PRIORITY, priority);
+ }
+ // 计算比值
+ if (MAX_PRIORITY == 0) {
+ return;
+ }
+ float bi = getWeight() / MAX_PRIORITY;
+ // 计算得分
+ for (IpModel temp : list) {
+ if (temp.priority == null || temp.priority.equals("")){
+ continue;
+ }
+ float priority = Float.parseFloat(temp.priority);
+ temp.grade += (priority * bi);
+ }
+
+ }
+
+ @Override
+ public float getWeight() {
+ return PlugInManager.PriorityPluginNum;
+ }
+
+ @Override
+ public boolean isActivated() {
+ return true;
+ }
+
+}
--- /dev/null
+package com.sina.util.dnscache.score.plugin;
+
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.model.IpModel;
+import com.sina.util.dnscache.score.IPlugIn;
+import com.sina.util.dnscache.score.PlugInManager;
+
+public class SpeedTestPlugin implements IPlugIn {
+
+ @Override
+ public void run(ArrayList<IpModel> list) {
+ // 查找到最大速度
+ float MAX_SPEED = 0;
+ for (IpModel temp : list) {
+ if (temp.rtt == null || temp.rtt.equals(""))
+ continue;
+ float finallySpeed = Float.parseFloat(temp.rtt);
+ MAX_SPEED = Math.max(MAX_SPEED, finallySpeed);
+ }
+ // 计算比值
+ if (MAX_SPEED == 0) {
+ return;
+ }
+ float bi = getWeight() / MAX_SPEED;
+ // 计算得分
+ for (IpModel temp : list) {
+ if (temp.rtt == null || temp.rtt.equals("")){
+ continue;
+ }
+ float finallySpeed = Float.parseFloat(temp.rtt);
+ temp.grade += (getWeight() - (finallySpeed * bi));
+ }
+ }
+
+ @Override
+ public float getWeight() {
+ return PlugInManager.SpeedTestPluginNum;
+ }
+
+ @Override
+ public boolean isActivated() {
+ return true;
+ }
+
+}
--- /dev/null
+package com.sina.util.dnscache.score.plugin;
+
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.model.IpModel;
+import com.sina.util.dnscache.score.IPlugIn;
+import com.sina.util.dnscache.score.PlugInManager;
+
+public class SuccessNumPlugin implements IPlugIn {
+
+ @Override
+ public void run(ArrayList<IpModel> list) {
+ // 查找到最大历史成功次数
+ float MAX_SUCCESSNUM = 0;
+ for (IpModel temp : list) {
+ if (temp.success_num == null || temp.success_num.equals(""))
+ continue;
+ float successNum = Float.parseFloat(temp.success_num);
+ MAX_SUCCESSNUM = Math.max(MAX_SUCCESSNUM, successNum);
+ }
+ // 计算比值
+ if (MAX_SUCCESSNUM == 0) {
+ return;
+ }
+ float bi = getWeight() / MAX_SUCCESSNUM;
+ // 计算得分
+ for (IpModel temp : list) {
+ if (temp.success_num == null || temp.success_num.equals("")){
+ continue;
+ }
+ float successNum = Float.parseFloat(temp.success_num);
+ temp.grade += (successNum * bi);
+ }
+
+ }
+
+ @Override
+ public float getWeight() {
+ return PlugInManager.SuccessNumPluginNum;
+ }
+
+ @Override
+ public boolean isActivated() {
+ return true;
+ }
+
+}
--- /dev/null
+package com.sina.util.dnscache.score.plugin;
+
+import java.util.ArrayList;
+
+import com.sina.util.dnscache.model.IpModel;
+import com.sina.util.dnscache.score.IPlugIn;
+import com.sina.util.dnscache.score.PlugInManager;
+
+public class SuccessTimePlugin implements IPlugIn {
+
+ @Override
+ public void run(ArrayList<IpModel> list) {
+ final float dayTime = 24 * 60;// 单位是minute
+ final float bi = getWeight() / dayTime;
+ for (IpModel temp : list) {
+ if (temp.finally_success_time == null || temp.finally_success_time.equals(""))
+ continue;
+ long lastSuccTime = Long.parseLong(temp.finally_success_time);
+ long now = System.currentTimeMillis();
+ long offTime = (now - lastSuccTime) / 1000 / 60; // 单位是minute
+ if (offTime > dayTime) {
+ continue;
+ } else {
+ temp.grade += (getWeight() - (offTime * bi));
+ }
+ }
+ }
+
+ @Override
+ public float getWeight() {
+ return PlugInManager.SuccessTimePluginNum;
+ }
+
+ @Override
+ public boolean isActivated() {
+ return true;
+ }
+
+}
--- /dev/null
+package com.sina.util.dnscache.speedtest;
+
+
+public abstract class BaseSpeedTest {
+
+ public abstract int speedTest(String ip, String host);
+
+ /**
+ * 被执行的优先级
+ * @return
+ */
+ public abstract int getPriority();
+
+ /**
+ * 是否是激活状态
+ * @return
+ */
+ public abstract boolean isActivate();
+
+}
\ No newline at end of file
--- /dev/null
+package com.sina.util.dnscache.speedtest;
+
+/**
+ * Created by fenglei on 15/4/22.
+ */
+public interface ISpeedtest {
+
+ public int speedTest(String ip, String host);
+
+}
--- /dev/null
+package com.sina.util.dnscache.speedtest;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import com.sina.util.dnscache.Tools;
+import com.sina.util.dnscache.speedtest.impl.PingTest;
+import com.sina.util.dnscache.speedtest.impl.Socket80Test;
+
+/**
+ * 测速类
+ *
+ * Created by fenglei on 15/4/22.
+ */
+public class SpeedtestManager implements ISpeedtest {
+
+ /**
+ * 请求server过程中发生错误
+ */
+ public static final int OCUR_ERROR = -1;
+
+ public static final int MAX_OVERTIME_RTT = 9999;
+
+ /**测速的轮询间隔*/
+ public static long time_interval = 1 * 60 * 1000;
+
+ private ArrayList<BaseSpeedTest> mSpeedTests = new ArrayList<BaseSpeedTest>();;
+
+ public SpeedtestManager() {
+ mSpeedTests.add(new Socket80Test());
+ mSpeedTests.add(new PingTest());
+ }
+
+ /**
+ *
+ * @param url
+ * @param host
+ * @return
+ */
+ @Override
+ public int speedTest(String ip, String host) {
+ Collections.sort(mSpeedTests, new Comparator<BaseSpeedTest>() {
+ @Override
+ public int compare(BaseSpeedTest lhs, BaseSpeedTest rhs) {
+ if (lhs == null || rhs == null) {
+ return 0;
+ } else {
+ // 按照降序排序
+ return rhs.getPriority() - lhs.getPriority();
+ }
+ }
+ });
+
+ for (BaseSpeedTest st : mSpeedTests) {
+ Tools.log("TAG", "测速模块" + st.getClass().getSimpleName() + "启动," + "\n优先级是:" + st.getPriority() + "\n该模块是否开启:" + st.isActivate());
+ if (st.isActivate()) {
+ int rtt = st.speedTest(ip, host);
+ Tools.log("TAG", "测速模块" + st.getClass().getSimpleName() + "结束," + "\n测速的结果是(RTT):" + rtt);
+ if (rtt > OCUR_ERROR) {
+ return rtt;
+ }
+ }
+ }
+ return OCUR_ERROR;
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.speedtest.impl;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import android.text.TextUtils;
+
+import com.sina.util.dnscache.speedtest.BaseSpeedTest;
+import com.sina.util.dnscache.speedtest.SpeedtestManager;
+
+public class PingTest extends BaseSpeedTest{
+
+ @Override
+ public int speedTest(String ip, String host) {
+ try {
+ return Ping.runcmd("ping -c1 -s1 -w1 " + ip);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return SpeedtestManager.OCUR_ERROR;
+ }
+
+ public static class Ping {
+ // ping -c1 -s1 -w1 www.baidu.com //-w 超时单位是s
+ private static final String TAG_BYTES_FROM = "bytes from ";
+
+ public static int runcmd(String cmd) throws Exception {
+ Runtime runtime = Runtime.getRuntime();
+ Process proc = null;
+
+ final String command = cmd.trim();
+ long startTime = System.currentTimeMillis();
+ proc = runtime.exec(command);
+ proc.waitFor();
+ long endTime = System.currentTimeMillis();
+ InputStream inputStream = proc.getInputStream();
+ String result = "unknown ip";
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+ StringBuilder resultBuilder = new StringBuilder();
+ String line = "";
+ while (null != (line = reader.readLine())) {
+ resultBuilder.append(line);
+ }
+ reader.close();
+ String responseStr = resultBuilder.toString();
+ result = responseStr.toLowerCase().trim();
+ if (isValidResult(result)) {
+ return (int) (endTime - startTime);
+ }
+ return SpeedtestManager.OCUR_ERROR;
+ }
+
+ private static boolean isValidResult(String result) {
+ if (!TextUtils.isEmpty(result)) {
+ if (result.indexOf(TAG_BYTES_FROM) > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public int getPriority() {
+ return 0;
+ }
+
+ @Override
+ public boolean isActivate() {
+ return false;
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.speedtest.impl;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+import com.sina.util.dnscache.speedtest.BaseSpeedTest;
+import com.sina.util.dnscache.speedtest.SpeedtestManager;
+
+public class Socket80Test extends BaseSpeedTest {
+
+ static final int TIMEOUT = 5 * 1000;
+
+ @Override
+ public int speedTest(String ip, String host) {
+ Socket socket = null;
+ try {
+ long begin = System.currentTimeMillis();
+ Socket s1 = new Socket();
+ s1.connect(new InetSocketAddress(ip, 80), TIMEOUT);
+ long end = System.currentTimeMillis();
+ int rtt = (int) (end - begin);
+ return rtt;
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (null != socket) {
+ socket.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return SpeedtestManager.OCUR_ERROR;
+ }
+
+ @Override
+ public int getPriority() {
+ return 10;
+ }
+
+ @Override
+ public boolean isActivate() {
+ return true;
+ }
+}
--- /dev/null
+package com.sina.util.dnscache.thread;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class RealTimeThreadPool {
+ private static final Object lock = new Object();
+ private static RealTimeThreadPool mInstance;
+ private static ExecutorService executorService;
+
+ public static RealTimeThreadPool getInstance() {
+ if (null == mInstance) {
+ synchronized (lock) {
+ if (null == mInstance) {
+ mInstance = new RealTimeThreadPool();
+ executorService = new ThreadPoolExecutor(1, 100, 120, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
+ new DefaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy());
+ }
+ }
+ }
+ return mInstance;
+ }
+
+ public void execute(Runnable command) {
+ if (null != executorService && !executorService.isShutdown()) {
+ executorService.execute(command);
+ } else {
+ Thread thread = new Thread(command);
+ thread.start();
+ }
+ }
+
+ /**
+ * The default thread factory
+ */
+ static class DefaultThreadFactory implements ThreadFactory {
+ private static final AtomicInteger poolNumber = new AtomicInteger(1);
+ private final ThreadGroup group;
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+ private final String namePrefix;
+
+ DefaultThreadFactory() {
+ SecurityManager s = System.getSecurityManager();
+ group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
+ namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
+ }
+
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
+ if (t.isDaemon())
+ t.setDaemon(false);
+ if (t.getPriority() != Thread.NORM_PRIORITY)
+ t.setPriority(Thread.NORM_PRIORITY);
+ return t;
+ }
+ }
+}
--- /dev/null
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".MainActivity" >
+
+ <TextView
+ android:id="@+id/textView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text=" 输入一个需要测试的API URL:" />
+
+ <EditText
+ android:id="@+id/editText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:text="http://api.weibo.cn/2/remind/unread_count?remind_version=94&ext_all=0&c=android&i=f6fd268&s=7fe80de0&ua=Xiaomi-MI%203W__weibo__5.3.0_alpha1__android__android4.4.4&wm=3333_1001&idc=&v_f=2&from=1052895010&gsid=_2A254Mx_tDeTxGeNM7lMY9ybEzD6IHXVZaRQlrDV6PUJbrdANLVfzkWo8pgH_awAHMa74PMGrs-jUSB8TTg..&lang=zh_CN&skin=default&oldwm=3333_1001&with_settings=1&unread_message=1&with_page_group=1" />
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="测试" />
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
+
+ <item android:id="@+id/action_clear" android:title="@string/action_clear"
+ android:orderInCategory="100" />
+
+ <item android:id="@+id/action_printf_domain" android:title="@string/action_printf_domain"
+ android:orderInCategory="100" />
+
+ <item android:id="@+id/action_printf_ip" android:title="@string/action_printf_ip"
+ android:orderInCategory="100" />
+
+ <item android:id="@+id/action_settings" android:title="@string/action_settings"
+ android:orderInCategory="100" />
+
+</menu>
--- /dev/null
+<resources>
+ <string name="app_name">DNSCache</string>
+
+ <string name="hello_world">Hello world!</string>
+ <string name="action_printf_domain">打印域名表</string>
+ <string name="action_printf_ip">打印IP表</string>
+ <string name="action_clear">清除缓存</string>
+ <string name="action_settings">参数设置</string>
+</resources>