summaryrefslogtreecommitdiff
path: root/common/framework/com/android/net/module/util/LinkPropertiesUtils.java
blob: e271f6490291258fa8016a7933a83d735da05639 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*
 * Copyright (C) 2019 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 com.android.net.module.util;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
import android.text.TextUtils;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

/**
 * Collection of link properties utilities.
 * @hide
 */
public final class LinkPropertiesUtils {

    /**
     * @param <T> The type of data to compare.
     */
    public static class CompareResult<T> {
        public final List<T> removed = new ArrayList<>();
        public final List<T> added = new ArrayList<>();

        public CompareResult() {}

        public CompareResult(@Nullable Collection<T> oldItems, @Nullable Collection<T> newItems) {
            if (oldItems != null) {
                removed.addAll(oldItems);
            }
            if (newItems != null) {
                for (T newItem : newItems) {
                    if (!removed.remove(newItem)) {
                        added.add(newItem);
                    }
                }
            }
        }

        @Override
        public String toString() {
            return "removed=[" + TextUtils.join(",", removed)
                    + "] added=[" + TextUtils.join(",", added)
                    + "]";
        }
    }

    /**
     * Generic class to compare two lists of items of type {@code T} whose properties can change.
     * The items to be compared must provide a way to calculate a corresponding key of type
     * {@code K} such that if (and only if) an old and a new item have the same key, then the new
     * item is an update of the old item. Both the old list and the new list may not contain more
     * than one item with the same key, and may not contain any null items.
     *
     * @param <K> A class that represents the key of the items to be compared.
     * @param <T> The class that represents the object to be compared.
     */
    public static class CompareOrUpdateResult<K, T> {
        public final List<T> added = new ArrayList<>();
        public final List<T> removed = new ArrayList<>();
        public final List<T> updated = new ArrayList<>();

        /**
         * Compares two lists of items.
         * @param oldItems the old list of items.
         * @param newItems the new list of items.
         * @param keyCalculator a {@link Function} that calculates an item's key.
         */
        public CompareOrUpdateResult(Collection<T> oldItems, Collection<T> newItems,
                Function<T, K> keyCalculator) {
            HashMap<K, T> updateTracker = new HashMap<>();

            if (oldItems != null) {
                for (T oldItem : oldItems) {
                    updateTracker.put(keyCalculator.apply(oldItem), oldItem);
                }
            }

            if (newItems != null) {
                for (T newItem : newItems) {
                    T oldItem = updateTracker.remove(keyCalculator.apply(newItem));
                    if (oldItem != null) {
                        if (!oldItem.equals(newItem)) {
                            // Update of existing item.
                            updated.add(newItem);
                        }
                    } else {
                        // New item.
                        added.add(newItem);
                    }
                }
            }

            removed.addAll(updateTracker.values());
        }

        @Override
        public String toString() {
            return "removed=[" + TextUtils.join(",", removed)
                    + "] added=[" + TextUtils.join(",", added)
                    + "] updated=[" + TextUtils.join(",", updated)
                    + "]";
        }
    }

    /**
     * Compares the addresses in {@code left} LinkProperties with {@code right}
     * LinkProperties, examining only addresses on the base link.
     *
     * @param left A LinkProperties with the old list of addresses.
     * @param right A LinkProperties with the new list of addresses.
     * @return the differences between the addresses.
     */
    public static @NonNull CompareResult<LinkAddress> compareAddresses(
            @Nullable LinkProperties left, @Nullable LinkProperties right) {
        /*
         * Duplicate the LinkAddresses into removed, we will be removing
         * address which are common between mLinkAddresses and target
         * leaving the addresses that are different. And address which
         * are in target but not in mLinkAddresses are placed in the
         * addedAddresses.
         */
        return new CompareResult<>(left != null ? left.getLinkAddresses() : null,
                right != null ? right.getLinkAddresses() : null);
    }

    /**
     * Compares {@code left} {@code LinkProperties} allLinkAddresses against the {@code right}.
     *
     * @param left A LinkProperties or null
     * @param right A LinkProperties or null
     * @return {@code true} if both are identical, {@code false} otherwise.
     * @see LinkProperties#getAllLinkAddresses()
     */
    public static boolean isIdenticalAllLinkAddresses(@Nullable LinkProperties left,
            @Nullable LinkProperties right) {
        if (left == right) return true;
        if (left == null || right == null) return false;
        final List<LinkAddress> leftAddresses = left.getAllLinkAddresses();
        final List<LinkAddress> rightAddresses = right.getAllLinkAddresses();
        if (leftAddresses.size() != rightAddresses.size()) return false;
        return leftAddresses.containsAll(rightAddresses);
    }

   /**
     * Compares {@code left} {@code LinkProperties} interface addresses against the {@code right}.
     *
     * @param left A LinkProperties.
     * @param right LinkProperties to be compared with {@code left}.
     * @return {@code true} if both are identical, {@code false} otherwise.
     */
    public static boolean isIdenticalAddresses(@NonNull LinkProperties left,
            @NonNull LinkProperties right) {
        final Collection<InetAddress> leftAddresses = left.getAddresses();
        final Collection<InetAddress> rightAddresses = right.getAddresses();
        return (leftAddresses.size() == rightAddresses.size())
                    ? leftAddresses.containsAll(rightAddresses) : false;
    }

    /**
     * Compares {@code left} {@code LinkProperties} DNS addresses against the {@code right}.
     *
     * @param left A LinkProperties.
     * @param right A LinkProperties to be compared with {@code left}.
     * @return {@code true} if both are identical, {@code false} otherwise.
     */
    public static boolean isIdenticalDnses(@NonNull LinkProperties left,
            @NonNull LinkProperties right) {
        final Collection<InetAddress> leftDnses = left.getDnsServers();
        final Collection<InetAddress> rightDnses = right.getDnsServers();

        final String leftDomains = left.getDomains();
        final String rightDomains = right.getDomains();
        if (leftDomains == null) {
            if (rightDomains != null) return false;
        } else {
            if (!leftDomains.equals(rightDomains)) return false;
        }
        return (leftDnses.size() == rightDnses.size())
                ? leftDnses.containsAll(rightDnses) : false;
    }

    /**
     * Compares {@code left} {@code LinkProperties} HttpProxy against the {@code right}.
     *
     * @param left A LinkProperties.
     * @param right A LinkProperties to be compared with {@code left}.
     * @return {@code true} if both are identical, {@code false} otherwise.
     */
    public static boolean isIdenticalHttpProxy(@NonNull LinkProperties left,
            @NonNull LinkProperties right) {
        return Objects.equals(left.getHttpProxy(), right.getHttpProxy());
    }

    /**
     * Compares {@code left} {@code LinkProperties} interface name against the {@code right}.
     *
     * @param left A LinkProperties.
     * @param right A LinkProperties to be compared with {@code left}.
     * @return {@code true} if both are identical, {@code false} otherwise.
     */
    public static boolean isIdenticalInterfaceName(@NonNull LinkProperties left,
            @NonNull LinkProperties right) {
        return TextUtils.equals(left.getInterfaceName(), right.getInterfaceName());
    }

    /**
     * Compares {@code left} {@code LinkProperties} Routes against the {@code right}.
     *
     * @param left A LinkProperties.
     * @param right A LinkProperties to be compared with {@code left}.
     * @return {@code true} if both are identical, {@code false} otherwise.
     */
    public static boolean isIdenticalRoutes(@NonNull LinkProperties left,
            @NonNull LinkProperties right) {
        final Collection<RouteInfo> leftRoutes = left.getRoutes();
        final Collection<RouteInfo> rightRoutes = right.getRoutes();
        return (leftRoutes.size() == rightRoutes.size())
                ? leftRoutes.containsAll(rightRoutes) : false;
    }
}