• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.net.module.util;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.net.LinkAddress;
22 import android.net.LinkProperties;
23 import android.net.RouteInfo;
24 import android.text.TextUtils;
25 
26 import java.net.InetAddress;
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Objects;
32 import java.util.function.Function;
33 
34 /**
35  * Collection of link properties utilities.
36  * @hide
37  */
38 public final class LinkPropertiesUtils {
39 
40     /**
41      * @param <T> The type of data to compare.
42      */
43     public static class CompareResult<T> {
44         public final List<T> removed = new ArrayList<>();
45         public final List<T> added = new ArrayList<>();
46 
CompareResult()47         public CompareResult() {}
48 
CompareResult(@ullable Collection<T> oldItems, @Nullable Collection<T> newItems)49         public CompareResult(@Nullable Collection<T> oldItems, @Nullable Collection<T> newItems) {
50             if (oldItems != null) {
51                 removed.addAll(oldItems);
52             }
53             if (newItems != null) {
54                 for (T newItem : newItems) {
55                     if (!removed.remove(newItem)) {
56                         added.add(newItem);
57                     }
58                 }
59             }
60         }
61 
62         @Override
toString()63         public String toString() {
64             return "removed=[" + TextUtils.join(",", removed)
65                     + "] added=[" + TextUtils.join(",", added)
66                     + "]";
67         }
68     }
69 
70     /**
71      * Generic class to compare two lists of items of type {@code T} whose properties can change.
72      * The items to be compared must provide a way to calculate a corresponding key of type
73      * {@code K} such that if (and only if) an old and a new item have the same key, then the new
74      * item is an update of the old item. Both the old list and the new list may not contain more
75      * than one item with the same key, and may not contain any null items.
76      *
77      * @param <K> A class that represents the key of the items to be compared.
78      * @param <T> The class that represents the object to be compared.
79      */
80     public static class CompareOrUpdateResult<K, T> {
81         public final List<T> added = new ArrayList<>();
82         public final List<T> removed = new ArrayList<>();
83         public final List<T> updated = new ArrayList<>();
84 
85         /**
86          * Compares two lists of items.
87          * @param oldItems the old list of items.
88          * @param newItems the new list of items.
89          * @param keyCalculator a {@link Function} that calculates an item's key.
90          */
CompareOrUpdateResult(Collection<T> oldItems, Collection<T> newItems, Function<T, K> keyCalculator)91         public CompareOrUpdateResult(Collection<T> oldItems, Collection<T> newItems,
92                 Function<T, K> keyCalculator) {
93             HashMap<K, T> updateTracker = new HashMap<>();
94 
95             if (oldItems != null) {
96                 for (T oldItem : oldItems) {
97                     updateTracker.put(keyCalculator.apply(oldItem), oldItem);
98                 }
99             }
100 
101             if (newItems != null) {
102                 for (T newItem : newItems) {
103                     T oldItem = updateTracker.remove(keyCalculator.apply(newItem));
104                     if (oldItem != null) {
105                         if (!oldItem.equals(newItem)) {
106                             // Update of existing item.
107                             updated.add(newItem);
108                         }
109                     } else {
110                         // New item.
111                         added.add(newItem);
112                     }
113                 }
114             }
115 
116             removed.addAll(updateTracker.values());
117         }
118 
119         @Override
toString()120         public String toString() {
121             return "removed=[" + TextUtils.join(",", removed)
122                     + "] added=[" + TextUtils.join(",", added)
123                     + "] updated=[" + TextUtils.join(",", updated)
124                     + "]";
125         }
126     }
127 
128     /**
129      * Compares the addresses in {@code left} LinkProperties with {@code right}
130      * LinkProperties, examining only addresses on the base link.
131      *
132      * @param left A LinkProperties with the old list of addresses.
133      * @param right A LinkProperties with the new list of addresses.
134      * @return the differences between the addresses.
135      */
compareAddresses( @ullable LinkProperties left, @Nullable LinkProperties right)136     public static @NonNull CompareResult<LinkAddress> compareAddresses(
137             @Nullable LinkProperties left, @Nullable LinkProperties right) {
138         /*
139          * Duplicate the LinkAddresses into removed, we will be removing
140          * address which are common between mLinkAddresses and target
141          * leaving the addresses that are different. And address which
142          * are in target but not in mLinkAddresses are placed in the
143          * addedAddresses.
144          */
145         return new CompareResult<>(left != null ? left.getLinkAddresses() : null,
146                 right != null ? right.getLinkAddresses() : null);
147     }
148 
149     /**
150      * Compares {@code left} {@code LinkProperties} allLinkAddresses against the {@code right}.
151      *
152      * @param left A LinkProperties or null
153      * @param right A LinkProperties or null
154      * @return {@code true} if both are identical, {@code false} otherwise.
155      * @see LinkProperties#getAllLinkAddresses()
156      */
isIdenticalAllLinkAddresses(@ullable LinkProperties left, @Nullable LinkProperties right)157     public static boolean isIdenticalAllLinkAddresses(@Nullable LinkProperties left,
158             @Nullable LinkProperties right) {
159         if (left == right) return true;
160         if (left == null || right == null) return false;
161         final List<LinkAddress> leftAddresses = left.getAllLinkAddresses();
162         final List<LinkAddress> rightAddresses = right.getAllLinkAddresses();
163         if (leftAddresses.size() != rightAddresses.size()) return false;
164         return leftAddresses.containsAll(rightAddresses);
165     }
166 
167    /**
168      * Compares {@code left} {@code LinkProperties} interface addresses against the {@code right}.
169      *
170      * @param left A LinkProperties.
171      * @param right LinkProperties to be compared with {@code left}.
172      * @return {@code true} if both are identical, {@code false} otherwise.
173      */
isIdenticalAddresses(@onNull LinkProperties left, @NonNull LinkProperties right)174     public static boolean isIdenticalAddresses(@NonNull LinkProperties left,
175             @NonNull LinkProperties right) {
176         final Collection<InetAddress> leftAddresses = left.getAddresses();
177         final Collection<InetAddress> rightAddresses = right.getAddresses();
178         return (leftAddresses.size() == rightAddresses.size())
179                     ? leftAddresses.containsAll(rightAddresses) : false;
180     }
181 
182     /**
183      * Compares {@code left} {@code LinkProperties} DNS addresses against the {@code right}.
184      *
185      * @param left A LinkProperties.
186      * @param right A LinkProperties to be compared with {@code left}.
187      * @return {@code true} if both are identical, {@code false} otherwise.
188      */
isIdenticalDnses(@onNull LinkProperties left, @NonNull LinkProperties right)189     public static boolean isIdenticalDnses(@NonNull LinkProperties left,
190             @NonNull LinkProperties right) {
191         final Collection<InetAddress> leftDnses = left.getDnsServers();
192         final Collection<InetAddress> rightDnses = right.getDnsServers();
193 
194         final String leftDomains = left.getDomains();
195         final String rightDomains = right.getDomains();
196         if (leftDomains == null) {
197             if (rightDomains != null) return false;
198         } else {
199             if (!leftDomains.equals(rightDomains)) return false;
200         }
201         return (leftDnses.size() == rightDnses.size())
202                 ? leftDnses.containsAll(rightDnses) : false;
203     }
204 
205     /**
206      * Compares {@code left} {@code LinkProperties} HttpProxy against the {@code right}.
207      *
208      * @param left A LinkProperties.
209      * @param right A LinkProperties to be compared with {@code left}.
210      * @return {@code true} if both are identical, {@code false} otherwise.
211      */
isIdenticalHttpProxy(@onNull LinkProperties left, @NonNull LinkProperties right)212     public static boolean isIdenticalHttpProxy(@NonNull LinkProperties left,
213             @NonNull LinkProperties right) {
214         return Objects.equals(left.getHttpProxy(), right.getHttpProxy());
215     }
216 
217     /**
218      * Compares {@code left} {@code LinkProperties} interface name against the {@code right}.
219      *
220      * @param left A LinkProperties.
221      * @param right A LinkProperties to be compared with {@code left}.
222      * @return {@code true} if both are identical, {@code false} otherwise.
223      */
isIdenticalInterfaceName(@onNull LinkProperties left, @NonNull LinkProperties right)224     public static boolean isIdenticalInterfaceName(@NonNull LinkProperties left,
225             @NonNull LinkProperties right) {
226         return TextUtils.equals(left.getInterfaceName(), right.getInterfaceName());
227     }
228 
229     /**
230      * Compares {@code left} {@code LinkProperties} Routes against the {@code right}.
231      *
232      * @param left A LinkProperties.
233      * @param right A LinkProperties to be compared with {@code left}.
234      * @return {@code true} if both are identical, {@code false} otherwise.
235      */
isIdenticalRoutes(@onNull LinkProperties left, @NonNull LinkProperties right)236     public static boolean isIdenticalRoutes(@NonNull LinkProperties left,
237             @NonNull LinkProperties right) {
238         final Collection<RouteInfo> leftRoutes = left.getRoutes();
239         final Collection<RouteInfo> rightRoutes = right.getRoutes();
240         return (leftRoutes.size() == rightRoutes.size())
241                 ? leftRoutes.containsAll(rightRoutes) : false;
242     }
243 }
244