Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c75d4af authored by Robert Greenwalt's avatar Robert Greenwalt
Browse files

Fix network-feature timeout code.

Track requests independently with seperate timers.  Clean up on expiration
by just stopping that particular request, not immediately restoring the default.

bug: 2127590
parent 7db7e6a0
Loading
Loading
Loading
Loading
+118 −73
Original line number Diff line number Diff line
@@ -439,6 +439,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        return tracker != null && tracker.setRadio(turnOn);
    }

    /**
     * Used to notice when the calling process dies so we can self-expire
     *
     * Also used to know if the process has cleaned up after itself when
     * our auto-expire timer goes off.  The timer has a link to an object.
     *
     */
    private class FeatureUser implements IBinder.DeathRecipient {
        int mNetworkType;
        String mFeature;
@@ -453,6 +460,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            mBinder = binder;
            mPid = getCallingPid();
            mUid = getCallingUid();

            try {
                mBinder.linkToDeath(this, 0);
            } catch (RemoteException e) {
@@ -467,11 +475,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        public void binderDied() {
            Log.d(TAG, "ConnectivityService FeatureUser binderDied(" +
                    mNetworkType + ", " + mFeature + ", " + mBinder);
            stopUsingNetworkFeature(mNetworkType, mFeature, mPid, mUid);
            stopUsingNetworkFeature(this, false);
        }

        public void expire() {
            Log.d(TAG, "ConnectivityService FeatureUser expire(" +
                    mNetworkType + ", " + mFeature + ", " + mBinder);
            stopUsingNetworkFeature(this, false);
        }
    }

    // javadoc from interface
    public int startUsingNetworkFeature(int networkType, String feature,
            IBinder binder) {
        if (DBG) {
@@ -483,9 +497,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            return Phone.APN_REQUEST_FAILED;
        }

        synchronized (mFeatureUsers) {
            mFeatureUsers.add(new FeatureUser(networkType, feature, binder));
        }
        FeatureUser f = new FeatureUser(networkType, feature, binder);

        // TODO - move this into the MobileDataStateTracker
        int usedNetworkType = networkType;
@@ -513,10 +525,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                    return Phone.APN_TYPE_NOT_AVAILABLE;
                }

                synchronized(this) {
                    mFeatureUsers.add(f);
                    if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
                        // this gets used for per-pid dns when connected
                        mNetRequestersPids[usedNetworkType].add(currentPid);
                    }
                }
                mHandler.sendMessageDelayed(mHandler.obtainMessage(
                        NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
                        f), getRestoreDefaultNetworkDelay());


                if ((ni.isConnectedOrConnecting() == true) &&
                        !network.isTeardownRequested()) {
@@ -533,22 +552,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                // check if the radio in play can make another contact
                // assume if cannot for now

                // since we have to drop the default on this radio, setup
                // an automatic event to switch back
                if(mHandler.hasMessages(NetworkStateTracker.
                        EVENT_RESTORE_DEFAULT_NETWORK, radio) ||
                        radio.getNetworkInfo().isConnectedOrConnecting()) {
                    mHandler.removeMessages(NetworkStateTracker.
                            EVENT_RESTORE_DEFAULT_NETWORK,
                            radio);
                    mHandler.sendMessageDelayed(mHandler.obtainMessage(
                            NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
                            radio), getRestoreDefaultNetworkDelay());
                }
                if (DBG) Log.d(TAG, "reconnecting to special network");
                network.reconnect();
                return Phone.APN_REQUEST_STARTED;
            } else {
                synchronized(this) {
                    mFeatureUsers.add(f);
                }
                mHandler.sendMessageDelayed(mHandler.obtainMessage(
                        NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK,
                        f), getRestoreDefaultNetworkDelay());

                return network.startUsingNetworkFeature(feature,
                        getCallingPid(), getCallingUid());
            }
@@ -556,13 +570,43 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        return Phone.APN_TYPE_NOT_AVAILABLE;
    }

    // javadoc from interface
    public int stopUsingNetworkFeature(int networkType, String feature) {
        return stopUsingNetworkFeature(networkType, feature, getCallingPid(),
                getCallingUid());
        int pid = getCallingPid();
        int uid = getCallingUid();

        FeatureUser u = null;
        boolean found = false;

        synchronized(this) {
            for (int i = 0; i < mFeatureUsers.size() ; i++) {
                u = (FeatureUser)mFeatureUsers.get(i);
                if (uid == u.mUid && pid == u.mPid &&
                        networkType == u.mNetworkType &&
                        TextUtils.equals(feature, u.mFeature)) {
                    found = true;
                    break;
                }
            }
        }
        if (found && u != null) {
            // stop regardless of how many other time this proc had called start
            return stopUsingNetworkFeature(u, true);
        } else {
            // none found!
            return 1;
        }
    }

    private int stopUsingNetworkFeature(int networkType, String feature,
            int pid, int uid) {
    private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) {
        int networkType = u.mNetworkType;
        String feature = u.mFeature;
        int pid = u.mPid;
        int uid = u.mUid;

        NetworkStateTracker tracker = null;
        boolean callTeardown = false;  // used to carry our decision outside of sync block

        if (DBG) {
            Log.d(TAG, "stopUsingNetworkFeature for net " + networkType +
                    ": " + feature);
@@ -572,15 +616,29 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            return -1;
        }

        synchronized (mFeatureUsers) {
            for (int i=0; i < mFeatureUsers.size(); i++) {
                FeatureUser u = (FeatureUser)mFeatureUsers.get(i);
                if (uid == u.mUid && pid == u.mPid &&
                        networkType == u.mNetworkType &&
                        TextUtils.equals(feature, u.mFeature)) {
        // need to link the mFeatureUsers list with the mNetRequestersPids state in this
        // sync block
        synchronized(this) {
            // check if this process still has an outstanding start request
            if (!mFeatureUsers.contains(u)) {
                return 1;
            }
            u.unlinkDeathRecipient();
                    mFeatureUsers.remove(i);
                    break;
            mFeatureUsers.remove(mFeatureUsers.indexOf(u));
            // If we care about duplicate requests, check for that here.
            //
            // This is done to support the extension of a request - the app
            // can request we start the network feature again and renew the
            // auto-shutoff delay.  Normal "stop" calls from the app though
            // do not pay attention to duplicate requests - in effect the
            // API does not refcount and a single stop will counter multiple starts.
            if (ignoreDups == false) {
                for (int i = 0; i < mFeatureUsers.size() ; i++) {
                    FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
                    if (x.mUid == u.mUid && x.mPid == u.mPid &&
                            x.mNetworkType == u.mNetworkType &&
                            TextUtils.equals(x.mFeature, u.mFeature)) {
                        return 1;
                    }
                }
            }
@@ -598,29 +656,25 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                    usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
                }
            }
        NetworkStateTracker tracker =  mNetTrackers[usedNetworkType];
            tracker =  mNetTrackers[usedNetworkType];
            if(usedNetworkType != networkType) {
                Integer currentPid = new Integer(pid);
            if (mNetRequestersPids[usedNetworkType].remove(currentPid)) {
                reassessPidDns(pid, true);
            }
                mNetRequestersPids[usedNetworkType].remove(currentPid);
                if (mNetRequestersPids[usedNetworkType].size() != 0) {
                    if (DBG) Log.d(TAG, "not tearing down special network - " +
                           "others still using it");
                    return 1;
                }
                callTeardown = true;
            }
        }

        if (callTeardown) {
            tracker.teardown();
            NetworkStateTracker radio = mNetTrackers[networkType];
            // Check if we want to revert to the default
            if (mHandler.hasMessages(NetworkStateTracker.
                    EVENT_RESTORE_DEFAULT_NETWORK, radio)) {
                mHandler.removeMessages(NetworkStateTracker.
                        EVENT_RESTORE_DEFAULT_NETWORK, radio);
                radio.reconnect();
            }
            return 1;
        } else {
            // do it the old fashioned way
            return tracker.stopUsingNetworkFeature(feature, pid, uid);
        }
    }
@@ -1231,17 +1285,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                    // fill me in
                    break;
                case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK:
                    for (NetworkStateTracker net : mNetTrackers) {
                        NetworkInfo i = net.getNetworkInfo();
                        if (i.isConnected() &&
                                !mNetAttributes[i.getType()].isDefault()) {
                            if (DBG) {
                                Log.d(TAG, "tearing down " + i +
                                        " to restore the default network");
                            }
                            teardown(net);
                        }
                    }
                    FeatureUser u = (FeatureUser)msg.obj;
                    u.expire();
                    break;
            }
        }