diff options
4 files changed, 125 insertions, 60 deletions
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index 9a73f52d5..2853bbac5 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -936,7 +936,7 @@ public class WifiConfigStore { FileOutputStream out = null; try { out = mAtomicFile.startWrite(); - FileUtils.setPermissions(mFileName, FILE_MODE, -1, -1); + FileUtils.chmod(mFileName, FILE_MODE); out.write(mWriteData); mAtomicFile.finishWrite(out); } catch (IOException e) { diff --git a/service/java/com/android/server/wifi/WifiTrafficPoller.java b/service/java/com/android/server/wifi/WifiTrafficPoller.java index 4491449e2..8349f7b13 100644 --- a/service/java/com/android/server/wifi/WifiTrafficPoller.java +++ b/service/java/com/android/server/wifi/WifiTrafficPoller.java @@ -33,67 +33,83 @@ import java.io.PrintWriter; * Polls for traffic stats and notifies the clients */ public class WifiTrafficPoller { - private static final String TAG = "WifiTrafficPoller"; - private long mTxPkts; - private long mRxPkts; - /* Tracks last reported data activity */ - private int mDataActivity; + private long mTxPkts = 0; + private long mRxPkts = 0; + + private int mLastActivity = -1; + + private static class CallbackWrapper { + public final ITrafficStateCallback callback; + /** + * On the first invocation, the callback is invoked no matter if the data activity changed + * or not. + */ + public boolean isFirstInvocation = true; - private final ExternalCallbackTracker<ITrafficStateCallback> mRegisteredCallbacks; + CallbackWrapper(ITrafficStateCallback callback) { + this.callback = callback; + } + } - WifiTrafficPoller(@NonNull Handler handler) { + private final ExternalCallbackTracker<CallbackWrapper> mRegisteredCallbacks; + + public WifiTrafficPoller(@NonNull Handler handler) { mRegisteredCallbacks = new ExternalCallbackTracker<>(handler); } /** * Add a new callback to the traffic poller. */ - public void addCallback(IBinder binder, ITrafficStateCallback callback, - int callbackIdentifier) { - if (!mRegisteredCallbacks.add(binder, callback, callbackIdentifier)) { + public void addCallback(IBinder binder, ITrafficStateCallback callback, int callbackId) { + if (!mRegisteredCallbacks.add(binder, new CallbackWrapper(callback), callbackId)) { Log.e(TAG, "Failed to add callback"); - return; } } /** * Remove an existing callback from the traffic poller. */ - public void removeCallback(int callbackIdentifier) { - mRegisteredCallbacks.remove(callbackIdentifier); + public void removeCallback(int callbackId) { + mRegisteredCallbacks.remove(callbackId); } - void notifyOnDataActivity(long txPkts, long rxPkts) { - long sent, received; - long preTxPkts = mTxPkts, preRxPkts = mRxPkts; + /** + * Notifies clients of data activity if the activity changed since the last update. + */ + public void notifyOnDataActivity(long newTxPkts, long newRxPkts) { + if (newTxPkts <= 0 && newRxPkts <= 0) { + return; + } + + long sent = newTxPkts - mTxPkts; + long received = newRxPkts - mRxPkts; int dataActivity = WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE; - mTxPkts = txPkts; - mRxPkts = rxPkts; - - if (preTxPkts > 0 || preRxPkts > 0) { - sent = mTxPkts - preTxPkts; - received = mRxPkts - preRxPkts; - if (sent > 0) { - dataActivity |= WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT; - } - if (received > 0) { - dataActivity |= WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN; - } + if (sent > 0) { + dataActivity |= WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT; + } + if (received > 0) { + dataActivity |= WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN; + } - if (dataActivity != mDataActivity) { - mDataActivity = dataActivity; - for (ITrafficStateCallback callback : mRegisteredCallbacks.getCallbacks()) { - try { - callback.onStateChanged(mDataActivity); - } catch (RemoteException e) { - // Failed to reach, skip - // Client removal is handled in WifiService - } + for (CallbackWrapper wrapper : mRegisteredCallbacks.getCallbacks()) { + // if this callback hasn't been triggered before, or the data activity changed, + // notify the callback + if (wrapper.isFirstInvocation || dataActivity != mLastActivity) { + wrapper.isFirstInvocation = false; + try { + wrapper.callback.onStateChanged(dataActivity); + } catch (RemoteException e) { + // Failed to reach, skip + // Client removal is handled in WifiService } } } + + mTxPkts = newTxPkts; + mRxPkts = newRxPkts; + mLastActivity = dataActivity; } /** @@ -102,8 +118,7 @@ public class WifiTrafficPoller { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("mTxPkts " + mTxPkts); pw.println("mRxPkts " + mRxPkts); - pw.println("mDataActivity " + mDataActivity); + pw.println("mLastActivity " + mLastActivity); pw.println("mRegisteredCallbacks " + mRegisteredCallbacks.getNumCallbacks()); } - } diff --git a/service/java/com/android/server/wifi/util/FileUtils.java b/service/java/com/android/server/wifi/util/FileUtils.java index 07b1155c3..fb8214246 100644 --- a/service/java/com/android/server/wifi/util/FileUtils.java +++ b/service/java/com/android/server/wifi/util/FileUtils.java @@ -33,31 +33,20 @@ public final class FileUtils { private static final String TAG = "FileUtils"; /** - * Set owner and mode of of given path. + * Change the mode of a file. * + * @param path path of the file * @param mode to apply through {@code chmod} - * @param uid to apply through {@code chown}, or -1 to leave unchanged - * @param gid to apply through {@code chown}, or -1 to leave unchanged * @return 0 on success, otherwise errno. */ - public static int setPermissions(String path, int mode, int uid, int gid) { + public static int chmod(String path, int mode) { try { Os.chmod(path, mode); + return 0; } catch (ErrnoException e) { - Log.w(TAG, "Failed to chmod(" + path + "): " + e); + Log.w(TAG, "Failed to chmod(" + path + ", " + mode + "): ", e); return e.errno; } - - if (uid >= 0 || gid >= 0) { - try { - Os.chown(path, uid, gid); - } catch (ErrnoException e) { - Log.w(TAG, "Failed to chown(" + path + "): " + e); - return e.errno; - } - } - - return 0; } /** @@ -80,5 +69,4 @@ public final class FileUtils { public static void stringToFile(String filename, String string) throws IOException { bytesToFile(filename, string.getBytes(StandardCharsets.UTF_8)); } - } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiTrafficPollerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiTrafficPollerTest.java index 1c7afef54..ecdf490c4 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiTrafficPollerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiTrafficPollerTest.java @@ -19,6 +19,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.net.wifi.ITrafficStateCallback; @@ -30,8 +31,6 @@ import android.os.test.TestLooper; import androidx.test.filters.SmallTest; -import com.android.server.wifi.util.ExternalCallbackTracker; - import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -50,10 +49,13 @@ public class WifiTrafficPollerTest extends WifiBaseTest { private final static long TX_PACKET_COUNT = 40; private final static long RX_PACKET_COUNT = 50; private static final int TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER = 14; + private static final int TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER2 = 42; @Mock IBinder mAppBinder; @Mock ITrafficStateCallback mTrafficStateCallback; - @Mock ExternalCallbackTracker<ITrafficStateCallback> mCallbackTracker; + + @Mock IBinder mAppBinder2; + @Mock ITrafficStateCallback mTrafficStateCallback2; /** * Called before each test @@ -148,4 +150,64 @@ public class WifiTrafficPollerTest extends WifiBaseTest { // Client should not get any message callback add failed. verify(mTrafficStateCallback, never()).onStateChanged(anyInt()); } + + /** Test that if the data activity didn't change, the client is not notified. */ + @Test + public void unchangedDataActivityNotNotified() throws Exception { + mWifiTrafficPoller.addCallback( + mAppBinder, mTrafficStateCallback, TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER); + mWifiTrafficPoller.notifyOnDataActivity(TX_PACKET_COUNT, RX_PACKET_COUNT); + + verify(mTrafficStateCallback).onStateChanged( + WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT); + + // since TX and RX both increased, should still be INOUT. But since it's the same data + // activity as before, the callback should not be triggered again. + mWifiTrafficPoller.notifyOnDataActivity(TX_PACKET_COUNT + 1, RX_PACKET_COUNT + 1); + + // still only called once + verify(mTrafficStateCallback).onStateChanged(anyInt()); + } + + /** + * If there are 2 callbacks, but the data activity only changed for one of them, only that + * callback should be triggered. + */ + @Test + public void multipleCallbacksOnlyChangedNotified() throws Exception { + mWifiTrafficPoller.addCallback( + mAppBinder, mTrafficStateCallback, TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER); + mWifiTrafficPoller.notifyOnDataActivity(TX_PACKET_COUNT, RX_PACKET_COUNT); + + verify(mTrafficStateCallback).onStateChanged( + WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT); + verify(mTrafficStateCallback2, never()).onStateChanged(anyInt()); + + mWifiTrafficPoller.addCallback( + mAppBinder2, mTrafficStateCallback2, TEST_TRAFFIC_STATE_CALLBACK_IDENTIFIER2); + mWifiTrafficPoller.notifyOnDataActivity(TX_PACKET_COUNT + 1, RX_PACKET_COUNT + 1); + + // still only called once + verify(mTrafficStateCallback).onStateChanged(anyInt()); + // called for the first time with INOUT + verify(mTrafficStateCallback2) + .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT); + // not called with anything else + verify(mTrafficStateCallback2).onStateChanged(anyInt()); + + // now only TX increased + mWifiTrafficPoller.notifyOnDataActivity(TX_PACKET_COUNT + 2, RX_PACKET_COUNT + 1); + + // called once with OUT + verify(mTrafficStateCallback) + .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT); + // called twice total + verify(mTrafficStateCallback, times(2)).onStateChanged(anyInt()); + + // called once with OUT + verify(mTrafficStateCallback2) + .onStateChanged(WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT); + // called twice total + verify(mTrafficStateCallback2, times(2)).onStateChanged(anyInt()); + } } |