/* Copyright 2012 Google Inc.
*
* 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.mobiperf.measurements;
import com.mobiperf.Config;
import com.mobiperf.Logger;
import com.mobiperf.MeasurementDesc;
import com.mobiperf.MeasurementError;
import com.mobiperf.MeasurementResult;
import com.mobiperf.MeasurementTask;
import com.mobiperf.util.MeasurementJsonConvertor;
import com.mobiperf.util.PhoneUtils;
import android.content.Context;
import java.io.InvalidClassException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.InvalidParameterException;
import java.util.Date;
import java.util.Map;
/**
* Measures the DNS lookup time
*/
public class DnsLookupTask extends MeasurementTask {
// Type name for internal use
public static final String TYPE = "dns_lookup";
// Human readable name for the task
public static final String DESCRIPTOR = "DNS lookup";
// Since it's very hard to calculate the data consumed by this task
// directly, we use a fixed value. This is on the high side.
public static final int AVG_DATA_USAGE_BYTE=2000;
/**
* The description of DNS lookup measurement
*/
public static class DnsLookupDesc extends MeasurementDesc {
public String target;
private String server;
public DnsLookupDesc(String key, Date startTime, Date endTime,
double intervalSec, long count, long priority, Map<String, String> params) {
super(DnsLookupTask.TYPE, key, startTime, endTime, intervalSec, count,
priority, params);
initializeParams(params);
if (this.target == null || this.target.length() == 0) {
throw new InvalidParameterException("LookupDnsTask cannot be created due " +
" to null target string");
}
}
/*
* @see com.google.wireless.speed.speedometer.MeasurementDesc#getType()
*/
@Override
public String getType() {
return DnsLookupTask.TYPE;
}
@Override
protected void initializeParams(Map<String, String> params) {
if (params == null) {
return;
}
this.target = params.get("target");
this.server = params.get("server");
}
}
public DnsLookupTask(MeasurementDesc desc, Context parent) {
super(new DnsLookupDesc(desc.key, desc.startTime, desc.endTime, desc.intervalSec,
desc.count, desc.priority, desc.parameters), parent);
}
/**
* Returns a copy of the DnsLookupTask
*/
@Override
public MeasurementTask clone() {
MeasurementDesc desc = this.measurementDesc;
DnsLookupDesc newDesc = new DnsLookupDesc(desc.key, desc.startTime, desc.endTime,
desc.intervalSec, desc.count, desc.priority, desc.parameters);
return new DnsLookupTask(newDesc, parent);
}
@Override
public MeasurementResult call() throws MeasurementError {
long t1, t2;
long totalTime = 0;
InetAddress resultInet = null;
int successCnt = 0;
for (int i = 0; i < Config.DEFAULT_DNS_COUNT_PER_MEASUREMENT; i++) {
try {
DnsLookupDesc taskDesc = (DnsLookupDesc) this.measurementDesc;
Logger.i("Running DNS Lookup for target " + taskDesc.target);
Date startTime = new Date();
t1 = System.currentTimeMillis();
InetAddress inet = InetAddress.getByName(taskDesc.target);
t2 = System.currentTimeMillis();
if (inet != null) {
totalTime += (t2 - t1);
resultInet = inet;
successCnt++;
}
this.progress = 100 * i / Config.DEFAULT_DNS_COUNT_PER_MEASUREMENT;
} catch (UnknownHostException e) {
throw new MeasurementError("Cannot resovle domain name");
}
}
if (resultInet != null) {
Logger.i("Successfully resolved target address");
PhoneUtils phoneUtils = PhoneUtils.getPhoneUtils();
MeasurementResult result = new MeasurementResult(phoneUtils.getDeviceInfo().deviceId,
phoneUtils.getDeviceProperty(), DnsLookupTask.TYPE, System.currentTimeMillis() * 1000,
true, this.measurementDesc);
result.addResult("address", resultInet.getHostAddress());
result.addResult("real_hostname", resultInet.getCanonicalHostName());
result.addResult("time_ms", totalTime / successCnt);
Logger.i(MeasurementJsonConvertor.toJsonString(result));
return result;
} else {
throw new MeasurementError("Cannot resovle domain name");
}
}
@SuppressWarnings("rawtypes")
public static Class getDescClass() throws InvalidClassException {
return DnsLookupDesc.class;
}
@Override
public String getType() {
return DnsLookupTask.TYPE;
}
@Override
public String getDescriptor() {
return DESCRIPTOR;
}
@Override
public String toString() {
DnsLookupDesc desc = (DnsLookupDesc) measurementDesc;
return "[DNS Lookup]\n Target: " + desc.target + "\n Interval (sec): " + desc.intervalSec
+ "\n Next run: " + desc.startTime;
}
@Override
public void stop() {
//There is nothing we need to do to stop the DNS measurement
}
/**
* Since it is hard to get the amount of data sent directly,
* use a fixed value. The data consumed is usually small, and the fixed
* value is a conservative estimate.
*
* TODO find a better way to get this value
*/
@Override
public long getDataConsumed() {
return AVG_DATA_USAGE_BYTE;
}
}