diff options
24 files changed, 1141 insertions, 168 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 53883b1..aa207e8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3047,8 +3047,7 @@ public final class ActivityThread { } } } else { - // TODO - Slog.w(TAG, "Native heap dump not yet implemented"); + Debug.dumpNativeHeap(dhd.fd.getFileDescriptor()); } } diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 5fd5315..e74db67 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -29,6 +29,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyIntents; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo; +import android.net.NetworkProperties; import android.telephony.TelephonyManager; import android.util.Log; import android.text.TextUtils; @@ -55,7 +56,7 @@ public class MobileDataStateTracker implements NetworkStateTracker { private boolean mTeardownRequested = false; private Handler mTarget; private Context mContext; - private String mInterfaceName; + private NetworkProperties mNetworkProperties; private boolean mPrivateDnsRouteSet = false; private int mDefaultGatewayAddr = 0; private boolean mDefaultRouteSet = false; @@ -101,14 +102,6 @@ public class MobileDataStateTracker implements NetworkStateTracker { return sDnsPropNames; } - /** - * Return the name of our network interface. - * @return the name of our interface. - */ - public String getInterfaceName() { - return mInterfaceName; - } - public boolean isPrivateDnsRouteSet() { return mPrivateDnsRouteSet; } @@ -211,9 +204,11 @@ public class MobileDataStateTracker implements NetworkStateTracker { } setDetailedState(DetailedState.DISCONNECTED, reason, apnName); - if (mInterfaceName != null) { - NetworkUtils.resetConnections(mInterfaceName); + if (mNetworkProperties != null) { + NetworkUtils.resetConnections(mNetworkProperties.getInterface(). + getName()); } + // TODO - check this // can't do this here - ConnectivityService needs it to clear stuff // it's ok though - just leave it to be refreshed next time // we connect. @@ -229,9 +224,11 @@ public class MobileDataStateTracker implements NetworkStateTracker { setDetailedState(DetailedState.SUSPENDED, reason, apnName); break; case CONNECTED: - mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY); - if (mInterfaceName == null) { - Log.d(TAG, "CONNECTED event did not supply interface name."); + mNetworkProperties = intent.getParcelableExtra( + Phone.DATA_NETWORK_PROPERTIES_KEY); + if (mNetworkProperties == null) { + Log.d(TAG, + "CONNECTED event did not supply network properties."); } setDetailedState(DetailedState.CONNECTED, reason, apnName); break; @@ -565,4 +562,8 @@ public class MobileDataStateTracker implements NetworkStateTracker { return null; } } + + public NetworkProperties getNetworkProperties() { + return mNetworkProperties; + } } diff --git a/core/java/android/net/NetworkProperties.aidl b/core/java/android/net/NetworkProperties.aidl new file mode 100644 index 0000000..07aac6e --- /dev/null +++ b/core/java/android/net/NetworkProperties.aidl @@ -0,0 +1,22 @@ +/* +** +** Copyright (C) 2009 Qualcomm Innovation Center, Inc. All Rights Reserved. +** Copyright (C) 2009 The Android Open Source Project +** +** 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 android.net; + +parcelable NetworkProperties; + diff --git a/core/java/android/net/NetworkProperties.java b/core/java/android/net/NetworkProperties.java new file mode 100644 index 0000000..56e1f1a --- /dev/null +++ b/core/java/android/net/NetworkProperties.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * 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 android.net; + +import android.os.Parcelable; +import android.os.Parcel; +import android.util.Log; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; + +/** + * Describes the properties of a network interface or single address + * of an interface. + * TODO - consider adding optional fields like Apn and ApnType + * @hide + */ +public class NetworkProperties implements Parcelable { + + private NetworkInterface mIface; + private Collection<InetAddress> mAddresses; + private Collection<InetAddress> mDnses; + private InetAddress mGateway; + private ProxyProperties mHttpProxy; + + public NetworkProperties() { + clear(); + } + + public synchronized void setInterface(NetworkInterface iface) { + mIface = iface; + } + public synchronized NetworkInterface getInterface() { + return mIface; + } + public synchronized String getInterfaceName() { + return (mIface == null ? null : mIface.getName()); + } + + public synchronized void addAddress(InetAddress address) { + mAddresses.add(address); + } + public synchronized Collection<InetAddress> getAddresses() { + return mAddresses; + } + + public synchronized void addDns(InetAddress dns) { + mDnses.add(dns); + } + public synchronized Collection<InetAddress> getDnses() { + return mDnses; + } + + public synchronized void setGateway(InetAddress gateway) { + mGateway = gateway; + } + public synchronized InetAddress getGateway() { + return mGateway; + } + + public synchronized void setHttpProxy(ProxyProperties proxy) { + mHttpProxy = proxy; + } + public synchronized ProxyProperties getHttpProxy() { + return mHttpProxy; + } + + public synchronized void clear() { + mIface = null; + mAddresses = new ArrayList<InetAddress>(); + mDnses = new ArrayList<InetAddress>(); + mGateway = null; + mHttpProxy = null; + } + + /** + * Implement the Parcelable interface + * @hide + */ + public int describeContents() { + return 0; + } + + public synchronized String toString() { + String ifaceName = (mIface == null ? "" : "InterfaceName: " + mIface.getName() + " "); + + String ip = "IpAddresses: ["; + for (InetAddress addr : mAddresses) ip += addr.toString() + ","; + ip += "] "; + + String dns = "DnsAddresses: ["; + for (InetAddress addr : mDnses) dns += addr.toString() + ","; + dns += "] "; + + String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); + String gateway = (mGateway == null ? "" : "Gateway: " + mGateway.toString() + " "); + + return ifaceName + ip + gateway + dns + proxy; + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public synchronized void writeToParcel(Parcel dest, int flags) { + dest.writeString(getInterfaceName()); + dest.writeInt(mAddresses.size()); + for(InetAddress a : mAddresses) { + dest.writeString(a.getHostName()); + dest.writeByteArray(a.getAddress()); + } + dest.writeInt(mDnses.size()); + for(InetAddress d : mDnses) { + dest.writeString(d.getHostName()); + dest.writeByteArray(d.getAddress()); + } + if (mGateway != null) { + dest.writeByte((byte)1); + dest.writeString(mGateway.getHostName()); + dest.writeByteArray(mGateway.getAddress()); + } else { + dest.writeByte((byte)0); + } + if (mHttpProxy != null) { + dest.writeByte((byte)1); + dest.writeParcelable(mHttpProxy, flags); + } else { + dest.writeByte((byte)0); + } + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public static final Creator<NetworkProperties> CREATOR = + new Creator<NetworkProperties>() { + public NetworkProperties createFromParcel(Parcel in) { + NetworkProperties netProp = new NetworkProperties(); + String iface = in.readString(); + if (iface != null) { + try { + netProp.setInterface(NetworkInterface.getByName(iface)); + } catch (Exception e) { + return null; + } + } + int addressCount = in.readInt(); + for (int i=0; i<addressCount; i++) { + try { + netProp.addAddress(InetAddress.getByAddress(in.readString(), + in.createByteArray())); + } catch (UnknownHostException e) { } + } + addressCount = in.readInt(); + for (int i=0; i<addressCount; i++) { + try { + netProp.addDns(InetAddress.getByAddress(in.readString(), + in.createByteArray())); + } catch (UnknownHostException e) { } + } + if (in.readByte() == 1) { + try { + netProp.setGateway(InetAddress.getByAddress(in.readString(), + in.createByteArray())); + } catch (UnknownHostException e) {} + } + if (in.readByte() == 1) { + netProp.setHttpProxy((ProxyProperties)in.readParcelable(null)); + } + return netProp; + } + + public NetworkProperties[] newArray(int size) { + return new NetworkProperties[size]; + } + }; +} diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index cd8e7f1..44215e7 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -46,20 +46,15 @@ public interface NetworkStateTracker { public NetworkInfo getNetworkInfo(); /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. + * Fetch NetworkProperties for the network */ - public String getTcpBufferSizesPropName(); + public NetworkProperties getNetworkProperties(); /** - * Return the DNS property names for this network. - */ - public String[] getDnsPropNames(); - - /** - * Fetch interface name of the interface + * Return the system properties name associated with the tcp buffer sizes + * for this network. */ - public String getInterfaceName(); + public String getTcpBufferSizesPropName(); /** * Check if private DNS route is set for the network diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index a3ae01b..564bc1f 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -32,13 +32,37 @@ public class NetworkUtils { public native static int disableInterface(String interfaceName); /** Add a route to the specified host via the named interface. */ - public native static int addHostRoute(String interfaceName, int hostaddr); + public static int addHostRoute(String interfaceName, InetAddress hostaddr) { + int v4Int = v4StringToInt(hostaddr.getHostAddress()); + if (v4Int != 0) { + return addHostRouteNative(interfaceName, v4Int); + } else { + return -1; + } + } + private native static int addHostRouteNative(String interfaceName, int hostaddr); /** Add a default route for the named interface. */ - public native static int setDefaultRoute(String interfaceName, int gwayAddr); + public static int setDefaultRoute(String interfaceName, InetAddress gwayAddr) { + int v4Int = v4StringToInt(gwayAddr.getHostAddress()); + if (v4Int != 0) { + return setDefaultRouteNative(interfaceName, v4Int); + } else { + return -1; + } + } + private native static int setDefaultRouteNative(String interfaceName, int hostaddr); /** Return the gateway address for the default route for the named interface. */ - public native static int getDefaultRoute(String interfaceName); + public static InetAddress getDefaultRoute(String interfaceName) { + int addr = getDefaultRouteNative(interfaceName); + try { + return InetAddress.getByAddress(v4IntToArray(addr)); + } catch (UnknownHostException e) { + return null; + } + } + private native static int getDefaultRouteNative(String interfaceName); /** Remove host routes that uses the named interface. */ public native static int removeHostRoutes(String interfaceName); @@ -105,27 +129,30 @@ public class NetworkUtils { private native static boolean configureNative( String interfaceName, int ipAddress, int netmask, int gateway, int dns1, int dns2); - /** - * Look up a host name and return the result as an int. Works if the argument - * is an IP address in dot notation. Obviously, this can only be used for IPv4 - * addresses. - * @param hostname the name of the host (or the IP address) - * @return the IP address as an {@code int} in network byte order - */ - public static int lookupHost(String hostname) { - InetAddress inetAddress; + // The following two functions are glue to tie the old int-based address scheme + // to the new InetAddress scheme. They should go away when we go fully to InetAddress + // TODO - remove when we switch fully to InetAddress + public static byte[] v4IntToArray(int addr) { + byte[] addrBytes = new byte[4]; + addrBytes[0] = (byte)(addr & 0xff); + addrBytes[1] = (byte)((addr >> 8) & 0xff); + addrBytes[2] = (byte)((addr >> 16) & 0xff); + addrBytes[3] = (byte)((addr >> 24) & 0xff); + return addrBytes; + } + + public static int v4StringToInt(String str) { + int result = 0; + String[] array = str.split("\\."); + if (array.length != 4) return 0; try { - inetAddress = InetAddress.getByName(hostname); - } catch (UnknownHostException e) { - return -1; + result = Integer.parseInt(array[3]); + result = (result << 8) + Integer.parseInt(array[2]); + result = (result << 8) + Integer.parseInt(array[1]); + result = (result << 8) + Integer.parseInt(array[0]); + } catch (NumberFormatException e) { + return 0; } - byte[] addrBytes; - int addr; - addrBytes = inetAddress.getAddress(); - addr = ((addrBytes[3] & 0xff) << 24) - | ((addrBytes[2] & 0xff) << 16) - | ((addrBytes[1] & 0xff) << 8) - | (addrBytes[0] & 0xff); - return addr; + return result; } } diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java new file mode 100644 index 0000000..6828dd4 --- /dev/null +++ b/core/java/android/net/ProxyProperties.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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 android.net; + + +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * A container class for the http proxy info + * @hide + */ +public class ProxyProperties implements Parcelable { + + private InetAddress mProxy; + private int mPort; + private String mExclusionList; + + public ProxyProperties() { + } + + public synchronized InetAddress getAddress() { + return mProxy; + } + public synchronized void setAddress(InetAddress proxy) { + mProxy = proxy; + } + + public synchronized int getPort() { + return mPort; + } + public synchronized void setPort(int port) { + mPort = port; + } + + public synchronized String getExclusionList() { + return mExclusionList; + } + public synchronized void setExclusionList(String exclusionList) { + mExclusionList = exclusionList; + } + + /** + * Implement the Parcelable interface + * @hide + */ + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public synchronized void writeToParcel(Parcel dest, int flags) { + if (mProxy != null) { + dest.writeByte((byte)1); + dest.writeString(mProxy.getHostName()); + dest.writeByteArray(mProxy.getAddress()); + } else { + dest.writeByte((byte)0); + } + dest.writeInt(mPort); + dest.writeString(mExclusionList); + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public static final Creator<ProxyProperties> CREATOR = + new Creator<ProxyProperties>() { + public ProxyProperties createFromParcel(Parcel in) { + ProxyProperties proxyProperties = new ProxyProperties(); + if (in.readByte() == 1) { + try { + proxyProperties.setAddress(InetAddress.getByAddress(in.readString(), + in.createByteArray())); + } catch (UnknownHostException e) {} + } + proxyProperties.setPort(in.readInt()); + proxyProperties.setExclusionList(in.readString()); + return proxyProperties; + } + + public ProxyProperties[] newArray(int size) { + return new ProxyProperties[size]; + } + }; + +}; diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index d6b6d72..d23b161 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -767,6 +767,13 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo } /** + * Writes native heap data to the specified file descriptor. + * + * @hide + */ + public static native void dumpNativeHeap(FileDescriptor fd); + + /** * Returns the number of sent transactions from this process. * @return The number of sent transactions or -1 if it could not read t. */ diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 2d120e8..e26a090 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -421,7 +421,7 @@ public abstract class WallpaperService extends Service { } /** - * Convenience for {@link SurfaceHolder.Callback#surfaceRedrawNeeded + * Convenience for {@link SurfaceHolder.Callback2#surfaceRedrawNeeded * SurfaceHolder.Callback.surfaceRedrawNeeded()}. */ public void onSurfaceRedrawNeeded(SurfaceHolder holder) { diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index feb0dad..3cde9d6 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -222,10 +222,10 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface }, { "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface }, - { "addHostRoute", "(Ljava/lang/String;I)I", (void *)android_net_utils_addHostRoute }, + { "addHostRouteNative", "(Ljava/lang/String;I)I", (void *)android_net_utils_addHostRoute }, { "removeHostRoutes", "(Ljava/lang/String;)I", (void *)android_net_utils_removeHostRoutes }, - { "setDefaultRoute", "(Ljava/lang/String;I)I", (void *)android_net_utils_setDefaultRoute }, - { "getDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_getDefaultRoute }, + { "setDefaultRouteNative", "(Ljava/lang/String;I)I", (void *)android_net_utils_setDefaultRoute }, + { "getDefaultRouteNative", "(Ljava/lang/String;)I", (void *)android_net_utils_getDefaultRoute }, { "removeDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_removeDefaultRoute }, { "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections }, { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp }, diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 3ee404a..4a877d2 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define LOG_TAG "android.os.Debug" #include "JNIHelp.h" #include "jni.h" #include "utils/misc.h" @@ -24,6 +25,8 @@ #include <unistd.h> #include <time.h> #include <sys/time.h> +#include <errno.h> +#include <assert.h> #ifdef HAVE_MALLOC_H #include <malloc.h> @@ -274,6 +277,176 @@ jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz); jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz); jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz); + +#ifdef HAVE_ANDROID_OS +/* pulled out of bionic */ +extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, + size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); +extern "C" void free_malloc_leak_info(uint8_t* info); +#define SIZE_FLAG_ZYGOTE_CHILD (1<<31) +#define BACKTRACE_SIZE 32 + +/* + * This is a qsort() callback. + * + * See dumpNativeHeap() for comments about the data format and sort order. + */ +static int compareHeapRecords(const void* vrec1, const void* vrec2) +{ + const size_t* rec1 = (const size_t*) vrec1; + const size_t* rec2 = (const size_t*) vrec2; + size_t size1 = *rec1; + size_t size2 = *rec2; + + if (size1 < size2) { + return 1; + } else if (size1 > size2) { + return -1; + } + + intptr_t* bt1 = (intptr_t*)(rec1 + 2); + intptr_t* bt2 = (intptr_t*)(rec2 + 2); + for (size_t idx = 0; idx < BACKTRACE_SIZE; idx++) { + intptr_t addr1 = bt1[idx]; + intptr_t addr2 = bt2[idx]; + if (addr1 == addr2) { + if (addr1 == 0) + break; + continue; + } + if (addr1 < addr2) { + return -1; + } else if (addr1 > addr2) { + return 1; + } + } + + return 0; +} + +/* + * The get_malloc_leak_info() call returns an array of structs that + * look like this: + * + * size_t size + * size_t allocations + * intptr_t backtrace[32] + * + * "size" is the size of the allocation, "backtrace" is a fixed-size + * array of function pointers, and "allocations" is the number of + * allocations with the exact same size and backtrace. + * + * The entries are sorted by descending total size (i.e. size*allocations) + * then allocation count. For best results with "diff" we'd like to sort + * primarily by individual size then stack trace. Since the entries are + * fixed-size, and we're allowed (by the current implementation) to mangle + * them, we can do this in place. + */ +static void dumpNativeHeap(FILE* fp) +{ + uint8_t* info = NULL; + size_t overallSize, infoSize, totalMemory, backtraceSize; + + get_malloc_leak_info(&info, &overallSize, &infoSize, &totalMemory, + &backtraceSize); + if (info == NULL) { + fprintf(fp, "Native heap dump not available. To enable, run these" + " commands (requires root):\n"); + fprintf(fp, "$ adb shell setprop libc.debug.malloc 1\n"); + fprintf(fp, "$ adb shell stop\n"); + fprintf(fp, "$ adb shell start\n"); + return; + } + assert(infoSize != 0); + assert(overallSize % infoSize == 0); + + fprintf(fp, "Android Native Heap Dump v1.0\n\n"); + + size_t recordCount = overallSize / infoSize; + fprintf(fp, "Total memory: %zu\n", totalMemory); + fprintf(fp, "Allocation records: %zd\n", recordCount); + if (backtraceSize != BACKTRACE_SIZE) { + fprintf(fp, "WARNING: mismatched backtrace sizes (%d vs. %d)\n", + backtraceSize, BACKTRACE_SIZE); + } + fprintf(fp, "\n"); + + /* re-sort the entries */ + qsort(info, recordCount, infoSize, compareHeapRecords); + + /* dump the entries to the file */ + const uint8_t* ptr = info; + for (size_t idx = 0; idx < recordCount; idx++) { + size_t size = *(size_t*) ptr; + size_t allocations = *(size_t*) (ptr + sizeof(size_t)); + intptr_t* backtrace = (intptr_t*) (ptr + sizeof(size_t) * 2); + + fprintf(fp, "z %d sz %8zu num %4zu bt", + (size & SIZE_FLAG_ZYGOTE_CHILD) != 0, + size & ~SIZE_FLAG_ZYGOTE_CHILD, + allocations); + for (size_t bt = 0; bt < backtraceSize; bt++) { + if (backtrace[bt] == 0) { + break; + } else { + fprintf(fp, " %08x", backtrace[bt]); + } + } + fprintf(fp, "\n"); + + ptr += infoSize; + } + + fprintf(fp, "END\n"); + free_malloc_leak_info(info); +} +#endif /*HAVE_ANDROID_OS*/ + +/* + * Dump the native heap, writing human-readable output to the specified + * file descriptor. + */ +static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz, + jobject fileDescriptor) +{ + if (fileDescriptor == NULL) { + jniThrowNullPointerException(env, NULL); + return; + } + int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor); + if (origFd < 0) { + jniThrowRuntimeException(env, "Invalid file descriptor"); + return; + } + + /* dup() the descriptor so we don't close the original with fclose() */ + int fd = dup(origFd); + if (fd < 0) { + LOGW("dup(%d) failed: %s\n", origFd, strerror(errno)); + jniThrowRuntimeException(env, "dup() failed"); + return; + } + + FILE* fp = fdopen(fd, "w"); + if (fp == NULL) { + LOGW("fdopen(%d) failed: %s\n", fd, strerror(errno)); + close(fd); + jniThrowRuntimeException(env, "fdopen() failed"); + return; + } + +#ifdef HAVE_ANDROID_OS + LOGD("Native heap dump starting...\n"); + dumpNativeHeap(fp); + LOGD("Native heap dump complete.\n"); +#else + fprintf(fp, "Native heap dump not available on this platform\n"); +#endif + + fclose(fp); +} + + /* * JNI registration. */ @@ -289,6 +462,8 @@ static JNINativeMethod gMethods[] = { (void*) android_os_Debug_getDirtyPages }, { "getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)V", (void*) android_os_Debug_getDirtyPagesPid }, + { "dumpNativeHeap", "(Ljava/io/FileDescriptor;)V", + (void*) android_os_Debug_dumpNativeHeap }, { "getBinderSentTransactions", "()I", (void*) android_os_Debug_getBinderSentTransactions }, { "getBinderReceivedTransactions", "()I", @@ -320,4 +495,4 @@ int register_android_os_Debug(JNIEnv *env) return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods)); } -}; +}; // namespace android diff --git a/native/include/android/sensor.h b/native/include/android/sensor.h new file mode 100644 index 0000000..4291d3e --- /dev/null +++ b/native/include/android/sensor.h @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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. + */ + + +#ifndef ANDROID_SENSOR_H +#define ANDROID_SENSOR_H + +/****************************************************************** + * + * IMPORTANT NOTICE: + * + * This file is part of Android's set of stable system headers + * exposed by the Android NDK (Native Development Kit). + * + * Third-party source AND binary code relies on the definitions + * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. + * + * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) + * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS + * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY + * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES + */ + +/* + * Structures and functions to receive and process sensor events in + * native code. + * + */ + +#include <sys/types.h> + +#include <android/looper.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Sensor types + * (keep in sync with hardware/sensor.h) + */ + +enum { + ASENSOR_TYPE_ACCELEROMETER = 1, + ASENSOR_TYPE_MAGNETIC_FIELD = 2, + ASENSOR_TYPE_GYROSCOPE = 4, + ASENSOR_TYPE_LIGHT = 5, + ASENSOR_TYPE_PROXIMITY = 8 +}; + +/* + * Sensor accuracy measure + */ +enum { + ASENSOR_STATUS_UNRELIABLE = 0, + ASENSOR_STATUS_ACCURACY_LOW = 1, + ASENSOR_STATUS_ACCURACY_MEDIUM = 2, + ASENSOR_STATUS_ACCURACY_HIGH = 3 +}; + +/* + * A few useful constants + */ + +/* Earth's gravity in m/s^2 */ +#define ASENSOR_STANDARD_GRAVITY (9.80665f) +/* Maximum magnetic field on Earth's surface in uT */ +#define ASENSOR_MAGNETIC_FIELD_EARTH_MAX (60.0f) +/* Minimum magnetic field on Earth's surface in uT*/ +#define ASENSOR_MAGNETIC_FIELD_EARTH_MIN (30.0f) + +/* + * A sensor event. + */ + +typedef struct ASensorVector { + union { + float v[3]; + struct { + float x; + float y; + float z; + }; + }; + int8_t status; + uint8_t reserved[3]; +} ASensorVector; + +typedef struct ASensorEvent { + int sensor; + int32_t reserved0; + union { + float data[16]; + ASensorVector acceleration; + ASensorVector magnetic; + float temperature; + float distance; + float light; + }; + int64_t timestamp; + int32_t reserved1[4]; +} ASensorEvent; + + +struct ASensorManager; +typedef struct ASensorManager ASensorManager; + +struct ASensorEventQueue; +typedef struct ASensorEventQueue ASensorEventQueue; + +struct ASensor; +typedef struct ASensor ASensor; + +/*****************************************************************************/ + +/* + * Get a reference to the sensor manager. ASensorManager is a singleton. + * + * Example: + * + * ASensorManager* sensorManager = ASensorManager_getInstance(); + * + */ +ASensorManager* ASensorManager_getInstance(); + + +/* + * Returns the list of available sensors. + */ +int ASensorManager_getSensorList(ASensorManager* manager, ASensor** list); + +/* + * Returns the default sensor for the given type, or NULL if no sensor + * of that type exist. + */ +ASensor* ASensorManager_getDefaultSensor(ASensorManager* manager, int type); + +/* + * Creates a new sensor event queue and associate it with a looper. + */ +ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager, + ALooper* looper, ALooper_callbackFunc* callback, void* data); + +/* + * Destroys the event queue and free all resources associated to it. + */ +int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue); + + +/*****************************************************************************/ + +/* + * Enable the selected sensor. Returns a negative error code on failure. + */ +int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor* sensor); + +/* + * Disable the selected sensor. Returns a negative error code on failure. + */ +int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor* sensor); + +/* + * Sets the delivery rate of events in microseconds for the given sensor. + * Note that this is a hint only, generally event will arrive at a higher + * rate. + * Returns a negative error code on failure. + */ +int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor* sensor, int32_t usec); + +/* + * Returns true if there are one or more events available in the + * sensor queue. Returns 1 if the queue has events; 0 if + * it does not have events; and a negative value if there is an error. + */ +int ASensorEventQueue_hasEvents(ASensorEventQueue* queue); + +/* + * Returns the next available events from the queue. Returns a negative + * value if no events are available or an error has occurred, otherwise + * the number of events returned. + * + * Examples: + * ASensorEvent event; + * ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1); + * + * ASensorEvent eventBuffer[8]; + * ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8); + * + */ +ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, + ASensorEvent* events, size_t count); + + +/*****************************************************************************/ + +/* + * Returns this sensor's name (non localized) + */ +const char* ASensor_getName(ASensor* sensor); + +/* + * Returns this sensor's vendor's name (non localized) + */ +const char* ASensor_getVendor(ASensor* sensor); + +/* + * Return this sensor's type + */ +int ASensor_getType(ASensor* sensor); + +/* + * Returns this sensors's resolution + */ +float ASensor_getResolution(ASensor* sensor); + + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_SENSOR_H diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 2ff231d..41207f7 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -222,6 +222,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback // underlying surface is created and destroyed SurfaceHolder holder = getHolder(); holder.addCallback(this); + // setFormat is done by SurfaceView in SDK 2.3 and newer. Uncomment + // this statement if back-porting to 2.2 or older: + // holder.setFormat(PixelFormat.RGB_565); + // // setType is not needed for SDK 2.0 or newer. Uncomment this // statement if back-porting this code to older SDKs. // holder.setType(SurfaceHolder.SURFACE_TYPE_GPU); @@ -1103,7 +1107,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback mRenderer = renderer; } - @Override public void run() { setName("GLThread " + getId()); @@ -1154,6 +1157,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback boolean sizeChanged = false; boolean wantRenderNotification = false; boolean doRenderNotification = false; + boolean askedToReleaseEglContext = false; int w = 0; int h = 0; Runnable event = null; @@ -1179,6 +1183,17 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } } + // Do we need to give up the EGL context? + if (mShouldReleaseEglContext) { + if (LOG_SURFACE) { + Log.i("GLThread", "releasing EGL context because asked to tid=" + getId()); + } + stopEglSurfaceLocked(); + stopEglContextLocked(); + mShouldReleaseEglContext = false; + askedToReleaseEglContext = true; + } + // Have we lost the EGL context? if (lostEglContext) { stopEglSurfaceLocked(); @@ -1228,6 +1243,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } if (doRenderNotification) { + if (LOG_SURFACE) { + Log.i("GLThread", "sending render notification tid=" + getId()); + } wantRenderNotification = false; doRenderNotification = false; mRenderComplete = true; @@ -1235,22 +1253,24 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } // Ready to draw? - if ((!mPaused) && mHasSurface - && (mWidth > 0) && (mHeight > 0) - && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) { + if (readyToDraw()) { // If we don't have an EGL context, try to acquire one. - if ((! mHaveEglContext) && sGLThreadManager.tryAcquireEglContextLocked(this)) { - try { - mEglHelper.start(); - } catch (RuntimeException t) { - sGLThreadManager.releaseEglContextLocked(this); - throw t; - } - mHaveEglContext = true; - createEglContext = true; + if (! mHaveEglContext) { + if (askedToReleaseEglContext) { + askedToReleaseEglContext = false; + } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) { + try { + mEglHelper.start(); + } catch (RuntimeException t) { + sGLThreadManager.releaseEglContextLocked(this); + throw t; + } + mHaveEglContext = true; + createEglContext = true; - sGLThreadManager.notifyAll(); + sGLThreadManager.notifyAll(); + } } if (mHaveEglContext && !mHaveEglSurface) { @@ -1265,6 +1285,9 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback w = mWidth; h = mHeight; wantRenderNotification = true; + if (LOG_SURFACE) { + Log.i("GLThread", "noticing that we want render notification tid=" + getId()); + } if (DRAW_TWICE_AFTER_SIZE_CHANGED) { // We keep mRequestRender true so that we draw twice after the size changes. @@ -1284,7 +1307,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback // By design, this is the only place in a GLThread thread where we wait(). if (LOG_THREADS) { - Log.i("GLThread", "waiting tid=" + getId()); + Log.i("GLThread", "waiting tid=" + getId() + + " mHaveEglContext: " + mHaveEglContext + + " mHaveEglSurface: " + mHaveEglSurface + + " mPaused: " + mPaused + + " mHasSurface: " + mHasSurface + + " mWaitingForSurface: " + mWaitingForSurface + + " mWidth: " + mWidth + + " mHeight: " + mHeight + + " mRequestRender: " + mRequestRender + + " mRenderMode: " + mRenderMode); } sGLThreadManager.wait(); } @@ -1326,7 +1358,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } if (LOG_RENDERER_DRAW_FRAME) { - Log.w("GLThread", "onDrawFrame"); + Log.w("GLThread", "onDrawFrame tid=" + getId()); } mRenderer.onDrawFrame(gl); if (!mEglHelper.swap()) { @@ -1352,6 +1384,16 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } } + public boolean ableToDraw() { + return mHaveEglContext && mHaveEglSurface && readyToDraw(); + } + + private boolean readyToDraw() { + return (!mPaused) && mHasSurface + && (mWidth > 0) && (mHeight > 0) + && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY)); + } + public void setRenderMode(int renderMode) { if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) { throw new IllegalArgumentException("renderMode"); @@ -1461,9 +1503,10 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback sGLThreadManager.notifyAll(); // Wait for thread to react to resize and render a frame - while (! mExited && !mPaused && !mRenderComplete ) { + while (! mExited && !mPaused && !mRenderComplete + && (mGLThread != null && mGLThread.ableToDraw())) { if (LOG_SURFACE) { - Log.i("Main thread", "onWindowResize waiting for render complete."); + Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + mGLThread.getId()); } try { sGLThreadManager.wait(); @@ -1490,6 +1533,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback } } + public void requestReleaseEglContextLocked() { + mShouldReleaseEglContext = true; + sGLThreadManager.notifyAll(); + } + /** * Queue an "event" to be run on the GL rendering thread. * @param r the runnable to be run on the GL rendering thread. @@ -1514,6 +1562,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback private boolean mWaitingForSurface; private boolean mHaveEglContext; private boolean mHaveEglSurface; + private boolean mShouldReleaseEglContext; private int mWidth; private int mHeight; private int mRenderMode; @@ -1598,6 +1647,13 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback if (mMultipleGLESContextsAllowed) { return true; } + // Notify the owning thread that it should release the context. + // TODO: implement a fairness policy. Currently + // if the owning thread is drawing continuously it will just + // reacquire the EGL context. + if (mEglOwner != null) { + mEglOwner.requestReleaseEglContextLocked(); + } return false; } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9ff7de6..9c504fe 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -26,6 +26,7 @@ import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.MobileDataStateTracker; import android.net.NetworkInfo; +import android.net.NetworkProperties; import android.net.NetworkStateTracker; import android.net.wifi.WifiStateTracker; import android.net.NetworkUtils; @@ -51,7 +52,10 @@ import java.io.FileDescriptor; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -741,6 +745,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * specified host is to be routed * @param hostAddress the IP address of the host to which the route is * desired + * todo - deprecate (only v4!) * @return {@code true} on success, {@code false} on failure */ public boolean requestRouteToHost(int networkType, int hostAddress) { @@ -757,7 +762,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } return false; } - return addHostRoute(tracker, hostAddress); + try { + InetAddress addr = InetAddress.getByAddress(NetworkUtils.v4IntToArray(hostAddress)); + return addHostRoute(tracker, addr); + } catch (UnknownHostException e) {} + return false; } /** @@ -765,22 +774,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { * host via the mobile data network. * @param hostAddress the IP address of the host to which the route is desired, * in network byte order. + * TODO - deprecate * @return {@code true} on success, {@code false} on failure */ - private boolean addHostRoute(NetworkStateTracker nt, int hostAddress) { + private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress) { if (nt.getNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI) { return false; } - String interfaceName = nt.getInterfaceName(); + NetworkProperties p = nt.getNetworkProperties(); + if (p == null) return false; + String interfaceName = p.getInterfaceName(); if (DBG) { - Slog.d(TAG, "Requested host route to " + Integer.toHexString(hostAddress) + - "(" + interfaceName + ")"); + Slog.d(TAG, "Requested host route to " + hostAddress + "(" + interfaceName + ")"); } - if (interfaceName != null && hostAddress != -1) { + if (interfaceName != null) { return NetworkUtils.addHostRoute(interfaceName, hostAddress) == 0; } else { + if (DBG) Slog.e(TAG, "addHostRoute failed due to null interface name"); return false; } } @@ -1251,21 +1263,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void addPrivateDnsRoutes(NetworkStateTracker nt) { - String interfaceName = nt.getInterfaceName(); boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet(); + NetworkProperties p = nt.getNetworkProperties(); + if (p == null) return; + String interfaceName = p.getInterfaceName(); if (DBG) { Slog.d(TAG, "addPrivateDnsRoutes for " + nt + "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet); } - String[] dnsList = getNameServerList(nt.getDnsPropNames()); if (interfaceName != null && !privateDnsRouteSet) { - for (String addrString : dnsList) { - int addr = NetworkUtils.lookupHost(addrString); - if (addr != -1 && addr != 0) { - if (DBG) Slog.d(TAG, " adding "+addrString+" ("+addr+")"); - NetworkUtils.addHostRoute(interfaceName, addr); - } + Collection<InetAddress> dnsList = p.getDnses(); + for (InetAddress dns : dnsList) { + if (DBG) Slog.d(TAG, " adding " + dns); + NetworkUtils.addHostRoute(interfaceName, dns); } nt.privateDnsRouteSet(true); } @@ -1274,7 +1285,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void removePrivateDnsRoutes(NetworkStateTracker nt) { // TODO - we should do this explicitly but the NetUtils api doesnt // support this yet - must remove all. No worse than before - String interfaceName = nt.getInterfaceName(); + NetworkProperties p = nt.getNetworkProperties(); + if (p == null) return; + String interfaceName = p.getInterfaceName(); boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet(); if (interfaceName != null && privateDnsRouteSet) { if (DBG) { @@ -1286,61 +1299,42 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - /** - * Return the IP addresses of the DNS servers available for this - * network interface. - * @param propertyNames the names of the system properties whose values - * give the IP addresses. Properties with no values are skipped. - * @return an array of {@code String}s containing the IP addresses - * of the DNS servers, in dot-notation. This may have fewer - * non-null entries than the list of names passed in, since - * some of the passed-in names may have empty values. - */ - String[] getNameServerList(String[] propertyNames) { - String[] dnsAddresses = new String[propertyNames.length]; - int i, j; - - for (i = 0, j = 0; i < propertyNames.length; i++) { - String value = SystemProperties.get(propertyNames[i]); - // The GSM layer sometimes sets a bogus DNS server address of - // 0.0.0.0 - if (!TextUtils.isEmpty(value) && !TextUtils.equals(value, "0.0.0.0")) { - dnsAddresses[j++] = value; - } - } - return dnsAddresses; - } private void addDefaultRoute(NetworkStateTracker nt) { - String interfaceName = nt.getInterfaceName(); - int defaultGatewayAddr = nt.getDefaultGatewayAddr(); + NetworkProperties p = nt.getNetworkProperties(); + if (p == null) return; + String interfaceName = p.getInterfaceName(); + InetAddress defaultGatewayAddr = p.getGateway(); boolean defaultRouteSet = nt.isDefaultRouteSet(); - NetworkInfo networkInfo = nt.getNetworkInfo(); - if ((interfaceName != null) && (defaultGatewayAddr != 0) && - defaultRouteSet == false) { - if (DBG) { + if ((interfaceName != null) && (defaultGatewayAddr != null ) && + (defaultRouteSet == false)) { + boolean error = (NetworkUtils.setDefaultRoute(interfaceName, defaultGatewayAddr) < 0); + + if (DBG && !error) { + NetworkInfo networkInfo = nt.getNetworkInfo(); Slog.d(TAG, "addDefaultRoute for " + networkInfo.getTypeName() + " (" + interfaceName + "), GatewayAddr=" + defaultGatewayAddr); } - NetworkUtils.setDefaultRoute(interfaceName, defaultGatewayAddr); - nt.defaultRouteSet(true); + nt.defaultRouteSet(!error); } } public void removeDefaultRoute(NetworkStateTracker nt) { - String interfaceName = nt.getInterfaceName(); + NetworkProperties p = nt.getNetworkProperties(); + if (p == null) return; + String interfaceName = p.getInterfaceName(); boolean defaultRouteSet = nt.isDefaultRouteSet(); - NetworkInfo networkInfo = nt.getNetworkInfo(); if (interfaceName != null && defaultRouteSet == true) { - if (DBG) { + boolean error = (NetworkUtils.removeDefaultRoute(interfaceName) < 0); + if (DBG && !error) { + NetworkInfo networkInfo = nt.getNetworkInfo(); Slog.d(TAG, "removeDefaultRoute for " + networkInfo.getTypeName() + " (" + interfaceName + ")"); } - NetworkUtils.removeDefaultRoute(interfaceName); - nt.defaultRouteSet(false); + nt.defaultRouteSet(error); } } @@ -1430,12 +1424,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkStateTracker nt = mNetTrackers[i]; if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { + NetworkProperties p = nt.getNetworkProperties(); + if (p == null) continue; List pids = mNetRequestersPids[i]; for (int j=0; j<pids.size(); j++) { Integer pid = (Integer)pids.get(j); if (pid.intValue() == myPid) { - String[] dnsList = getNameServerList(nt.getDnsPropNames()); - writePidDns(dnsList, myPid); + Collection<InetAddress> dnses = p.getDnses(); + writePidDns(dnses, myPid); if (doBump) { bumpDns(); } @@ -1457,12 +1453,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void writePidDns(String[] dnsList, int pid) { + private void writePidDns(Collection <InetAddress> dnses, int pid) { int j = 1; - for (String dns : dnsList) { - if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { - SystemProperties.set("net.dns" + j++ + "." + pid, dns); - } + for (InetAddress dns : dnses) { + SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress()); } } @@ -1488,17 +1482,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkStateTracker nt = mNetTrackers[netType]; if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { - String[] dnsList = getNameServerList(nt.getDnsPropNames()); + NetworkProperties p = nt.getNetworkProperties(); + if (p == null) continue; + Collection<InetAddress> dnses = p.getDnses(); if (mNetAttributes[netType].isDefault()) { int j = 1; - for (String dns : dnsList) { - if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { - if (DBG) { - Slog.d(TAG, "adding dns " + dns + " for " + - nt.getNetworkInfo().getTypeName()); - } - SystemProperties.set("net.dns" + j++, dns); + for (InetAddress dns : dnses) { + if (DBG) { + Slog.d(TAG, "adding dns " + dns + " for " + + nt.getNetworkInfo().getTypeName()); } + SystemProperties.set("net.dns" + j++, dns.getHostAddress()); } for (int k=j ; k<mNumDnsEntries; k++) { if (DBG) Slog.d(TAG, "erasing net.dns" + k); @@ -1510,7 +1504,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { List pids = mNetRequestersPids[netType]; for (int y=0; y< pids.size(); y++) { Integer pid = (Integer)pids.get(y); - writePidDns(dnsList, pid.intValue()); + writePidDns(dnses, pid.intValue()); } } } diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index b1ca785..f42bc8b 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -19,6 +19,7 @@ package com.android.server; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.net.NetworkProperties; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -34,6 +35,7 @@ import android.util.Slog; import java.util.ArrayList; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.net.NetworkInterface; import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.ITelephonyRegistry; @@ -90,7 +92,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private ArrayList<String> mConnectedApns; - private String mDataConnectionInterfaceName = ""; + private NetworkProperties mDataConnectionProperties; private Bundle mCellLocation = new Bundle(); @@ -353,7 +355,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } public void notifyDataConnection(int state, boolean isDataConnectivityPossible, - String reason, String apn, String apnType, String interfaceName, int networkType) { + String reason, String apn, String apnType, NetworkProperties networkProperties, + int networkType) { if (!checkNotifyPermission("notifyDataConnection()" )) { return; } @@ -380,7 +383,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataConnectionPossible = isDataConnectivityPossible; mDataConnectionReason = reason; mDataConnectionApn = apn; - mDataConnectionInterfaceName = interfaceName; + mDataConnectionProperties = networkProperties; if (mDataConnectionNetworkType != networkType) { mDataConnectionNetworkType = networkType; modified = true; @@ -400,7 +403,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn, - apnType, interfaceName); + apnType, networkProperties); } public void notifyDataConnectionFailed(String reason, String apnType) { @@ -487,7 +490,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println(" mDataConnectionPossible=" + mDataConnectionPossible); pw.println(" mDataConnectionReason=" + mDataConnectionReason); pw.println(" mDataConnectionApn=" + mDataConnectionApn); - pw.println(" mDataConnectionInterfaceName=" + mDataConnectionInterfaceName); + pw.println(" mDataConnectionProperties=" + mDataConnectionProperties); pw.println(" mCellLocation=" + mCellLocation); pw.println("registrations: count=" + recordCount); for (Record r : mRecords) { @@ -561,7 +564,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible, - String reason, String apn, String apnType, String interfaceName) { + String reason, String apn, String apnType, NetworkProperties networkProperties) { // Note: not reporting to the battery stats service here, because the // status bar takes care of that after taking into account all of the // required info. @@ -574,9 +577,15 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (reason != null) { intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason); } + if (networkProperties != null) { + intent.putExtra(Phone.DATA_NETWORK_PROPERTIES_KEY, networkProperties); + NetworkInterface iface = networkProperties.getInterface(); + if (iface != null) { + intent.putExtra(Phone.DATA_IFACE_NAME_KEY, iface.getName()); + } + } intent.putExtra(Phone.DATA_APN_KEY, apn); intent.putExtra(Phone.DATA_APN_TYPE_KEY, apnType); - intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName); mContext.sendStickyBroadcast(intent); } diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index e71fe2e..06807c6 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.app.PendingIntent; +import android.net.NetworkProperties; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; @@ -26,6 +27,10 @@ import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; import android.util.Log; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; import java.util.ArrayList; /** @@ -191,6 +196,9 @@ public abstract class DataConnectionTracker extends Handler { /** indication of our availability (preconditions to trysetupData are met) **/ protected boolean mAvailability = false; + /** all our network properties (dns, gateway, ip, etc) */ + protected NetworkProperties mNetworkProperties; + /** * Default constructor */ @@ -424,6 +432,15 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void setState(State s); + protected NetworkProperties getNetworkProperties(String apnType) { + int id = apnTypeToId(apnType); + if (isApnIdEnabled(id)) { + return mNetworkProperties; + } else { + return null; + } + } + // tell all active apns of the current condition protected void notifyDataConnection(String reason) { for (int id = 0; id < APN_NUM_TYPES; id++) { @@ -668,5 +685,43 @@ public abstract class DataConnectionTracker extends Handler { } } + protected NetworkProperties makeNetworkProperties(DataConnection connection) { + NetworkProperties properties = new NetworkProperties(); + try { + properties.setInterface(NetworkInterface.getByName(connection.getInterface())); + } catch (SocketException e) { + Log.e(LOG_TAG, "SocketException creating NetworkInterface: " + e); + } catch (NullPointerException e) { + Log.e(LOG_TAG, "NPE trying to makeNetworkProperties: " + e); + } + + try { + properties.addAddress(InetAddress.getByName(connection.getIpAddress())); + } catch (UnknownHostException e) { + Log.e(LOG_TAG, "UnknownHostException setting IpAddress: " + e); + } catch (SecurityException e) { + Log.e(LOG_TAG, "SecurityException setting IpAddress: " + e); + } + + try { + properties.setGateway(InetAddress.getByName(connection.getGatewayAddress())); + } catch (UnknownHostException e) { + Log.e(LOG_TAG, "UnknownHostException setting GatewayAddress: " + e); + } catch (SecurityException e) { + Log.e(LOG_TAG, "SecurityException setting GatewayAddress: " + e); + } + try { + String[] dnsStrings = connection.getDnsServers(); + for (int i = 0; i<dnsStrings.length; i++) { + properties.addDns(InetAddress.getByName(dnsStrings[i])); + } + } catch (UnknownHostException e) { + Log.e(LOG_TAG, "UnknownHostException setting DnsAddress: " + e); + } catch (SecurityException e) { + Log.e(LOG_TAG, "SecurityException setting DnsAddress: " + e); + } + // TODO - set Proxy info + return properties; + } } diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index 0646101..382c19f 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.net.NetworkProperties; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -107,13 +108,17 @@ public class DefaultPhoneNotifier implements PhoneNotifier { // use apnType as the key to which connection we're talking about. // pass apnType back up to fetch particular for this one. TelephonyManager telephony = TelephonyManager.getDefault(); + NetworkProperties networkProperties = null; + if (state == Phone.DataState.CONNECTED) { + networkProperties = sender.getNetworkProperties(apnType); + } try { mRegistry.notifyDataConnection( convertDataState(state), sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), apnType, - sender.getInterfaceName(null), + networkProperties, ((telephony!=null) ? telephony.getNetworkType() : TelephonyManager.NETWORK_TYPE_UNKNOWN)); } catch (RemoteException ex) { diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 79c2b40..f7b70ee 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.content.Intent; +import android.net.NetworkProperties; import android.os.Bundle; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -32,7 +33,8 @@ interface ITelephonyRegistry { void notifyCallForwardingChanged(boolean cfi); void notifyDataActivity(int state); void notifyDataConnection(int state, boolean isDataConnectivityPossible, - String reason, String apn, String apnType, String interfaceName, int networkType); + String reason, String apn, String apnType, in NetworkProperties networkProperties, + int networkType); void notifyDataConnectionFailed(String reason, String apnType); void notifyCellLocation(in Bundle cellLocation); } diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 7029031..769b2fc 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.content.Context; import android.content.SharedPreferences; +import android.net.NetworkProperties; import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; @@ -101,6 +102,7 @@ public interface Phone { static final String STATE_CHANGE_REASON_KEY = "reason"; static final String DATA_APN_TYPE_KEY = "apnType"; static final String DATA_APN_KEY = "apn"; + static final String DATA_NETWORK_PROPERTIES_KEY = "dataProperties"; static final String DATA_IFACE_NAME_KEY = "iface"; static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable"; @@ -319,6 +321,11 @@ public interface Phone { String getActiveApn(); /** + * Return the NetworkProperties for the named apn or null if not available + */ + NetworkProperties getNetworkProperties(String apnType); + + /** * Get current signal strength. No change notification available on this * interface. Use <code>PhoneStateNotifier</code> or an equivalent. * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu). diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index cf80691..e5968a7 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -21,6 +21,7 @@ import android.app.IActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.SharedPreferences; +import android.net.NetworkProperties; import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Handler; @@ -955,6 +956,10 @@ public abstract class PhoneBase extends Handler implements Phone { return mDataConnection.getActiveApnTypes(); } + public NetworkProperties getNetworkProperties(String apnType) { + return mDataConnection.getNetworkProperties(apnType); + } + public String getActiveApn() { return mDataConnection.getActiveApnString(); } diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index fb2a938..d84859c 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -21,6 +21,7 @@ import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.net.NetworkProperties; import android.os.Handler; import android.os.Message; import android.os.SystemProperties; @@ -211,6 +212,10 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.getActiveApnTypes(); } + public NetworkProperties getNetworkProperties(String apnType) { + return mActivePhone.getNetworkProperties(apnType); + } + public String getActiveApn() { return mActivePhone.getActiveApn(); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index bd103d4..8a3af3b 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -53,6 +53,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.ServiceStateTracker; +import java.net.NetworkInterface; import java.util.ArrayList; /** @@ -736,6 +737,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } if (ar.exception == null) { + mNetworkProperties = makeNetworkProperties(mActiveDataConnection); + // everything is setup notifyDefaultData(reason); } else { diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 6826fa8..c76da80 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -30,6 +30,8 @@ import android.database.Cursor; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.NetworkInfo; +import android.net.NetworkProperties; +import android.net.ProxyProperties; import android.net.TrafficStats; import android.net.Uri; import android.net.wifi.WifiManager; @@ -58,6 +60,9 @@ import com.android.internal.telephony.EventLogTags; import com.android.internal.telephony.DataConnection.FailCause; import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; import java.util.ArrayList; /** @@ -1133,6 +1138,25 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } if (ar.exception == null) { + mNetworkProperties = makeNetworkProperties(mActivePdp); + + ApnSetting apn = mActivePdp.getApn(); + if (apn.proxy != null && apn.proxy.length() != 0) { + try { + ProxyProperties proxy = new ProxyProperties(); + proxy.setAddress(InetAddress.getByName(apn.proxy)); + proxy.setPort(Integer.parseInt(apn.port)); + mNetworkProperties.setHttpProxy(proxy); + } catch (UnknownHostException e) { + Log.e(LOG_TAG, "UnknownHostException making ProxyProperties: " + e); + } catch (SecurityException e) { + Log.e(LOG_TAG, "SecurityException making ProxyProperties: " + e); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "NumberFormatException making ProxyProperties (" + apn.port + + "): " + e); + } + } + // everything is setup if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { SystemProperties.set("gsm.defaultpdpcontext.active", "true"); diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 5b4faf9..5780a04 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -30,6 +30,7 @@ import android.net.NetworkUtils; import android.net.ConnectivityManager; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; +import android.net.NetworkProperties; import android.os.Message; import android.os.Parcelable; import android.os.Handler; @@ -54,6 +55,9 @@ import android.content.Context; import android.database.ContentObserver; import com.android.internal.app.IBatteryStats; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; @@ -211,6 +215,7 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { private boolean mDisconnectExpected; private DhcpHandler mDhcpTarget; private DhcpInfo mDhcpInfo; + private NetworkProperties mNetworkProperties; private int mLastSignalLevel = -1; private String mLastBssid; private String mLastSsid; @@ -315,7 +320,6 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { private String mInterfaceName; private static String LS = System.getProperty("line.separator"); - private static String[] sDnsPropNames; private Handler mTarget; private Context mContext; private boolean mPrivateDnsRouteSet = false; @@ -379,10 +383,7 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { mSettingsObserver = new SettingsObserver(new Handler()); mInterfaceName = SystemProperties.get("wifi.interface", "tiwlan0"); - sDnsPropNames = new String[] { - "dhcp." + mInterfaceName + ".dns1", - "dhcp." + mInterfaceName + ".dns2" - }; + mNetworkProperties = new NetworkProperties(); mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); } @@ -477,15 +478,6 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { } /** - * Return the IP addresses of the DNS servers available for the WLAN - * network interface. - * @return a list of DNS addresses, with no holes. - */ - public String[] getDnsPropNames() { - return sDnsPropNames; - } - - /** * Return the name of our WLAN network interface. * @return the name of our interface. */ @@ -901,6 +893,7 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { } setDetailedState(DetailedState.DISCONNECTED); setSupplicantState(SupplicantState.UNINITIALIZED); + mNetworkProperties.clear(); mHaveIpAddress = false; mObtainingIpAddress = false; if (died) { @@ -1008,6 +1001,7 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { reconnectCommand(); } } else if (newState == SupplicantState.DISCONNECTED) { + mNetworkProperties.clear(); mHaveIpAddress = false; if (isDriverStopped() || mDisconnectExpected) { handleDisconnectedState(DetailedState.DISCONNECTED, true); @@ -1192,6 +1186,7 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { } mReconnectCount = 0; mHaveIpAddress = true; + configureNetworkProperties(); mObtainingIpAddress = false; mWifiInfo.setIpAddress(mDhcpInfo.ipAddress); mLastSignalLevel = -1; // force update of signal strength @@ -1217,6 +1212,7 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { // [31- 1] Reserved for future use // [ 0- 0] Interface configuration succeeded (1) or failed (0) EventLog.writeEvent(EVENTLOG_INTERFACE_CONFIGURATION_STATE_CHANGED, 0); + mNetworkProperties.clear(); mHaveIpAddress = false; mWifiInfo.setIpAddress(0); mObtainingIpAddress = false; @@ -1289,6 +1285,49 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { return disabledNetwork; } + + private void configureNetworkProperties() { + try { + mNetworkProperties.setInterface(NetworkInterface.getByName(mInterfaceName)); + } catch (SocketException e) { + Log.e(TAG, "SocketException creating NetworkInterface from " + mInterfaceName + + ". e=" + e); + return; + } catch (NullPointerException e) { + Log.e(TAG, "NPE creating NetworkInterface. e=" + e); + return; + } + // TODO - fix this for v6 + try { + mNetworkProperties.addAddress(InetAddress.getByAddress( + NetworkUtils.v4IntToArray(mDhcpInfo.ipAddress))); + } catch (UnknownHostException e) { + Log.e(TAG, "Exception setting IpAddress using " + mDhcpInfo + ", e=" + e); + } + + try { + mNetworkProperties.setGateway(InetAddress.getByAddress(NetworkUtils.v4IntToArray( + mDhcpInfo.gateway))); + } catch (UnknownHostException e) { + Log.e(TAG, "Exception setting Gateway using " + mDhcpInfo + ", e=" + e); + } + + try { + mNetworkProperties.addDns(InetAddress.getByAddress( + NetworkUtils.v4IntToArray(mDhcpInfo.dns1))); + } catch (UnknownHostException e) { + Log.e(TAG, "Exception setting Dns1 using " + mDhcpInfo + ", e=" + e); + } + try { + mNetworkProperties.addDns(InetAddress.getByAddress( + NetworkUtils.v4IntToArray(mDhcpInfo.dns2))); + + } catch (UnknownHostException e) { + Log.e(TAG, "Exception setting Dns2 using " + mDhcpInfo + ", e=" + e); + } + // TODO - add proxy info + } + private void configureInterface() { checkPollTimer(); mLastSignalLevel = -1; @@ -1300,11 +1339,9 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { } else { int event; if (NetworkUtils.configureInterface(mInterfaceName, mDhcpInfo)) { - mHaveIpAddress = true; event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED; if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration succeeded"); } else { - mHaveIpAddress = false; event = EVENT_INTERFACE_CONFIGURATION_FAILED; if (LOCAL_LOGD) Log.v(TAG, "Static IP configuration failed"); } @@ -1339,6 +1376,7 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { */ public void resetConnections(boolean disableInterface) { if (LOCAL_LOGD) Log.d(TAG, "Reset connections and stopping DHCP"); + mNetworkProperties.clear(); mHaveIpAddress = false; mObtainingIpAddress = false; mWifiInfo.setIpAddress(0); @@ -2282,11 +2320,12 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { mNotificationRepeatTime = 0; mNumScansSinceNetworkStateChange = 0; } - + @Override public String toString() { StringBuffer sb = new StringBuffer(); - sb.append("interface ").append(mInterfaceName); + + sb.append(mNetworkProperties.toString()); sb.append(" runState="); if (mRunState >= 1 && mRunState <= mRunStateNames.length) { sb.append(mRunStateNames[mRunState-1]); @@ -2366,7 +2405,7 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { setBluetoothCoexistenceMode( WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED); } - + powerMode = getPowerMode(); if (powerMode < 0) { // Handle the case where supplicant driver does not support @@ -2588,4 +2627,8 @@ public class WifiStateTracker extends Handler implements NetworkStateTracker { Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1; } } + + public NetworkProperties getNetworkProperties() { + return mNetworkProperties; + } } |