18568db534118fc14cc28100306d51626464ff319Jesse Wilson/*
28568db534118fc14cc28100306d51626464ff319Jesse Wilson * Copyright (C) 2011 The Android Open Source Project
38568db534118fc14cc28100306d51626464ff319Jesse Wilson *
48568db534118fc14cc28100306d51626464ff319Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
58568db534118fc14cc28100306d51626464ff319Jesse Wilson * you may not use this file except in compliance with the License.
68568db534118fc14cc28100306d51626464ff319Jesse Wilson * You may obtain a copy of the License at
78568db534118fc14cc28100306d51626464ff319Jesse Wilson *
88568db534118fc14cc28100306d51626464ff319Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
98568db534118fc14cc28100306d51626464ff319Jesse Wilson *
108568db534118fc14cc28100306d51626464ff319Jesse Wilson * Unless required by applicable law or agreed to in writing, software
118568db534118fc14cc28100306d51626464ff319Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
128568db534118fc14cc28100306d51626464ff319Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138568db534118fc14cc28100306d51626464ff319Jesse Wilson * See the License for the specific language governing permissions and
148568db534118fc14cc28100306d51626464ff319Jesse Wilson * limitations under the License.
158568db534118fc14cc28100306d51626464ff319Jesse Wilson */
168568db534118fc14cc28100306d51626464ff319Jesse Wilson
178568db534118fc14cc28100306d51626464ff319Jesse Wilsonpackage com.android.server;
188568db534118fc14cc28100306d51626464ff319Jesse Wilson
1962a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkeyimport android.os.SystemProperties;
2062a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkeyimport android.util.Log;
21b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkeyimport android.util.Slog;
22b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
238568db534118fc14cc28100306d51626464ff319Jesse Wilsonimport dalvik.system.SocketTagger;
2462a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey
258568db534118fc14cc28100306d51626464ff319Jesse Wilsonimport java.io.FileDescriptor;
268568db534118fc14cc28100306d51626464ff319Jesse Wilsonimport java.net.SocketException;
278568db534118fc14cc28100306d51626464ff319Jesse Wilson
288568db534118fc14cc28100306d51626464ff319Jesse Wilson/**
298568db534118fc14cc28100306d51626464ff319Jesse Wilson * Assigns tags to sockets for traffic stats.
308568db534118fc14cc28100306d51626464ff319Jesse Wilson */
318568db534118fc14cc28100306d51626464ff319Jesse Wilsonpublic final class NetworkManagementSocketTagger extends SocketTagger {
3262a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey    private static final String TAG = "NetworkManagementSocketTagger";
3362a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey    private static final boolean LOGD = false;
348568db534118fc14cc28100306d51626464ff319Jesse Wilson
3562a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey    /**
3662a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey     * {@link SystemProperties} key that indicates if {@code qtaguid} bandwidth
3762a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey     * controls have been enabled.
3862a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey     */
3962a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey    // TODO: remove when always enabled, or once socket tagging silently fails.
4062a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey    public static final String PROP_QTAGUID_ENABLED = "net.qtaguid_enabled";
418568db534118fc14cc28100306d51626464ff319Jesse Wilson
428568db534118fc14cc28100306d51626464ff319Jesse Wilson    private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() {
4362a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey        @Override
4462a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey        protected SocketTags initialValue() {
458568db534118fc14cc28100306d51626464ff319Jesse Wilson            return new SocketTags();
468568db534118fc14cc28100306d51626464ff319Jesse Wilson        }
478568db534118fc14cc28100306d51626464ff319Jesse Wilson    };
488568db534118fc14cc28100306d51626464ff319Jesse Wilson
498568db534118fc14cc28100306d51626464ff319Jesse Wilson    public static void install() {
508568db534118fc14cc28100306d51626464ff319Jesse Wilson        SocketTagger.set(new NetworkManagementSocketTagger());
518568db534118fc14cc28100306d51626464ff319Jesse Wilson    }
528568db534118fc14cc28100306d51626464ff319Jesse Wilson
538568db534118fc14cc28100306d51626464ff319Jesse Wilson    public static void setThreadSocketStatsTag(int tag) {
548568db534118fc14cc28100306d51626464ff319Jesse Wilson        threadSocketTags.get().statsTag = tag;
558568db534118fc14cc28100306d51626464ff319Jesse Wilson    }
568568db534118fc14cc28100306d51626464ff319Jesse Wilson
57eaef351afcd586d5a84e80455f12f72fd12213efAlon Albert    public static int getThreadSocketStatsTag() {
58eaef351afcd586d5a84e80455f12f72fd12213efAlon Albert        return threadSocketTags.get().statsTag;
59eaef351afcd586d5a84e80455f12f72fd12213efAlon Albert    }
60eaef351afcd586d5a84e80455f12f72fd12213efAlon Albert
618568db534118fc14cc28100306d51626464ff319Jesse Wilson    public static void setThreadSocketStatsUid(int uid) {
628568db534118fc14cc28100306d51626464ff319Jesse Wilson        threadSocketTags.get().statsUid = uid;
638568db534118fc14cc28100306d51626464ff319Jesse Wilson    }
648568db534118fc14cc28100306d51626464ff319Jesse Wilson
6562a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey    @Override
6662a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey    public void tag(FileDescriptor fd) throws SocketException {
678568db534118fc14cc28100306d51626464ff319Jesse Wilson        final SocketTags options = threadSocketTags.get();
6862a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey        if (LOGD) {
69a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey            Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x"
70a63ba59260cd1bb3f5c16e395ace45a61f1d4461Jeff Sharkey                    + Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid);
718568db534118fc14cc28100306d51626464ff319Jesse Wilson        }
7298a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall        // TODO: skip tagging when options would be no-op
7398a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall        tagSocketFd(fd, options.statsTag, options.statsUid);
748568db534118fc14cc28100306d51626464ff319Jesse Wilson    }
758568db534118fc14cc28100306d51626464ff319Jesse Wilson
7698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall    private void tagSocketFd(FileDescriptor fd, int tag, int uid) {
7798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall        if (tag == -1 && uid == -1) return;
7898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall
79418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey        if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
80418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            final int errno = native_tagSocketFd(fd, tag, uid);
81418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            if (errno < 0) {
82418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey                Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", "
83418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey                      + tag + ", " +
84418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey                      + uid + ") failed with errno" + errno);
85418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            }
868568db534118fc14cc28100306d51626464ff319Jesse Wilson        }
878568db534118fc14cc28100306d51626464ff319Jesse Wilson    }
888568db534118fc14cc28100306d51626464ff319Jesse Wilson
8962a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey    @Override
9062a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey    public void untag(FileDescriptor fd) throws SocketException {
9162a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey        if (LOGD) {
9262a2c8fed9cc74e9fa03871e0022205560a681a1Jeff Sharkey            Log.i(TAG, "untagSocket(" + fd.getInt$() + ")");
938568db534118fc14cc28100306d51626464ff319Jesse Wilson        }
9498a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall        unTagSocketFd(fd);
958568db534118fc14cc28100306d51626464ff319Jesse Wilson    }
968568db534118fc14cc28100306d51626464ff319Jesse Wilson
9798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall    private void unTagSocketFd(FileDescriptor fd) {
9836bd9844f88cd0eb90e94b45bf5b4aa27d4d5628JP Abgrall        final SocketTags options = threadSocketTags.get();
9998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall        if (options.statsTag == -1 && options.statsUid == -1) return;
10098a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall
101418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey        if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
102418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            final int errno = native_untagSocketFd(fd);
103418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            if (errno < 0) {
104418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey                Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno);
105418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            }
10698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall        }
1078568db534118fc14cc28100306d51626464ff319Jesse Wilson    }
1088568db534118fc14cc28100306d51626464ff319Jesse Wilson
1098568db534118fc14cc28100306d51626464ff319Jesse Wilson    public static class SocketTags {
1108568db534118fc14cc28100306d51626464ff319Jesse Wilson        public int statsTag = -1;
1118568db534118fc14cc28100306d51626464ff319Jesse Wilson        public int statsUid = -1;
1128568db534118fc14cc28100306d51626464ff319Jesse Wilson    }
1138568db534118fc14cc28100306d51626464ff319Jesse Wilson
114b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static void setKernelCounterSet(int uid, int counterSet) {
115418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey        if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
116418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            final int errno = native_setCounterSet(counterSet, uid);
117418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            if (errno < 0) {
118418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey                Log.w(TAG, "setKernelCountSet(" + uid + ", " + counterSet + ") failed with errno "
119418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey                        + errno);
120418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            }
121b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        }
122b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
123b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
124b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    public static void resetKernelUidStats(int uid) {
125418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey        if (SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) {
126418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            int errno = native_deleteTagData(0, uid);
127418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            if (errno < 0) {
128418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey                Slog.w(TAG, "problem clearing counters for uid " + uid + " : errno " + errno);
129418d12dc8f2c518b673ebc522de4af6f7dbf0bf3Jeff Sharkey            }
130b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey        }
131b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey    }
132b5d55e302d2253e4bfb233ea705caf258cdc4cb9Jeff Sharkey
1338568db534118fc14cc28100306d51626464ff319Jesse Wilson    /**
1348568db534118fc14cc28100306d51626464ff319Jesse Wilson     * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming
1358568db534118fc14cc28100306d51626464ff319Jesse Wilson     * format like {@code 0x7fffffff00000000}.
1368568db534118fc14cc28100306d51626464ff319Jesse Wilson     */
1378568db534118fc14cc28100306d51626464ff319Jesse Wilson    public static int kernelToTag(String string) {
1382d6c580262ba1c19fc4f20c3566889e332fbdcb6Jeff Sharkey        int length = string.length();
1392d6c580262ba1c19fc4f20c3566889e332fbdcb6Jeff Sharkey        if (length > 10) {
1402d6c580262ba1c19fc4f20c3566889e332fbdcb6Jeff Sharkey            return Long.decode(string.substring(0, length - 8)).intValue();
1412d6c580262ba1c19fc4f20c3566889e332fbdcb6Jeff Sharkey        } else {
1422d6c580262ba1c19fc4f20c3566889e332fbdcb6Jeff Sharkey            return 0;
1432d6c580262ba1c19fc4f20c3566889e332fbdcb6Jeff Sharkey        }
1448568db534118fc14cc28100306d51626464ff319Jesse Wilson    }
14598a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall
14698a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall    private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid);
14798a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall    private static native int native_untagSocketFd(FileDescriptor fd);
14898a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall    private static native int native_setCounterSet(int uid, int counterSetNum);
14998a4f7e7e12effb78b3d1035e5a670ccbbf5bca1JP Abgrall    private static native int native_deleteTagData(int tag, int uid);
1508568db534118fc14cc28100306d51626464ff319Jesse Wilson}
151