/* * Copyright (C) 2016 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.util; import android.net.INetd; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.SystemClock; import android.util.Log; /** * @hide */ public class NetdService { private static final String TAG = NetdService.class.getSimpleName(); private static final String NETD_SERVICE_NAME = "netd"; private static final long BASE_TIMEOUT_MS = 100; private static final long MAX_TIMEOUT_MS = 1000; /** * Return an INetd instance, or null if not available. * * It is the caller's responsibility to check for a null return value * and to handle RemoteException errors from invocations on the returned * interface if, for example, netd dies and is restarted. * * Returned instances of INetd should not be cached. * * @return an INetd instance or null. */ public static INetd getInstance() { // NOTE: ServiceManager does no caching for the netd service, // because netd is not one of the defined common services. final INetd netdInstance = INetd.Stub.asInterface( ServiceManager.getService(NETD_SERVICE_NAME)); if (netdInstance == null) { Log.w(TAG, "WARNING: returning null INetd instance."); } return netdInstance; } /** * Blocks for a specified time until an INetd instance is available. * * It is the caller's responsibility to handle RemoteException errors * from invocations on the returned interface if, for example, netd * dies after this interface was returned. * * Returned instances of INetd should not be cached. * * Special values of maxTimeoutMs include: 0, meaning try to obtain an * INetd instance only once, and -1 (or any value less than 0), meaning * try to obtain an INetd instance indefinitely. * * @param maxTimeoutMs the maximum time to spend getting an INetd instance * @return an INetd instance or null if no instance is available * within |maxTimeoutMs| milliseconds. */ public static INetd get(long maxTimeoutMs) { if (maxTimeoutMs == 0) return getInstance(); final long stop = (maxTimeoutMs > 0) ? SystemClock.elapsedRealtime() + maxTimeoutMs : Long.MAX_VALUE; long timeoutMs = 0; while (true) { final INetd netdInstance = getInstance(); if (netdInstance != null) { return netdInstance; } final long remaining = stop - SystemClock.elapsedRealtime(); if (remaining <= 0) break; // No netdInstance was received; sleep and retry. timeoutMs = Math.min(timeoutMs + BASE_TIMEOUT_MS, MAX_TIMEOUT_MS); timeoutMs = Math.min(timeoutMs, remaining); try { Thread.sleep(timeoutMs); } catch (InterruptedException e) {} } return null; } /** * Blocks until an INetd instance is available. * * It is the caller's responsibility to handle RemoteException errors * from invocations on the returned interface if, for example, netd * dies after this interface was returned. * * Returned instances of INetd should not be cached. * * @return an INetd instance. */ public static INetd get() { return get(-1); } public static interface NetdCommand { void run(INetd netd) throws RemoteException; } /** * Blocks until an INetd instance is availabe, and retries until either * the command succeeds or a runtime exception is thrown. */ public static void run(NetdCommand cmd) { while (true) { try { cmd.run(get()); return; } catch (RemoteException re) { Log.e(TAG, "error communicating with netd: " + re); } } } }