1 package com.android.tv.mdnsoffloadmanager;
2 
3 import android.util.Log;
4 
5 import androidx.annotation.NonNull;
6 import androidx.annotation.WorkerThread;
7 
8 import java.io.PrintWriter;
9 import java.util.Collection;
10 import java.util.Collections;
11 import java.util.HashSet;
12 import java.util.List;
13 import java.util.Set;
14 
15 @WorkerThread
16 public class InterfaceOffloadManager {
17 
18     private static final String TAG = InterfaceOffloadManager.class.getSimpleName();
19 
20     private final String mNetworkInterface;
21     private final OffloadIntentStore mOffloadIntentStore;
22     private final OffloadWriter mOffloadWriter;
23     private final Set<Integer> mCurrentOffloadKeys = new HashSet<>();
24     private final Set<String> mCurrentPassthroughQNames = new HashSet<>();
25     private boolean mIsNetworkAvailable = false;
26 
InterfaceOffloadManager( @onNull String networkInterface, @NonNull OffloadIntentStore offloadIntentStore, @NonNull OffloadWriter offloadWriter)27     InterfaceOffloadManager(
28             @NonNull String networkInterface,
29             @NonNull OffloadIntentStore offloadIntentStore,
30             @NonNull OffloadWriter offloadWriter) {
31         mNetworkInterface = networkInterface;
32         mOffloadIntentStore = offloadIntentStore;
33         mOffloadWriter = offloadWriter;
34     }
35 
onVendorServiceConnected()36     void onVendorServiceConnected() {
37         refreshProtocolResponses();
38         refreshPassthroughList();
39     }
40 
onAppIdAllowlistUpdated()41     void onAppIdAllowlistUpdated() {
42         refreshProtocolResponses();
43         refreshPassthroughList();
44     }
45 
onNetworkAvailable()46     void onNetworkAvailable() {
47         String msg = "Network interface {" + mNetworkInterface + "} is connected." +
48                 " Offloading all stored data.";
49         Log.d(TAG, msg);
50         mIsNetworkAvailable = true;
51         refreshProtocolResponses();
52         refreshPassthroughList();
53     }
54 
onNetworkLost()55     void onNetworkLost() {
56         String msg = "Network interface {" + mNetworkInterface + "} was disconnected."
57                 + " Clearing all associated data.";
58         Log.d(TAG, msg);
59         mIsNetworkAvailable = false;
60         clearProtocolResponses();
61         clearPassthroughList();
62     }
63 
onVendorServiceDisconnected()64     void onVendorServiceDisconnected() {
65         mCurrentOffloadKeys.clear();
66         mCurrentPassthroughQNames.clear();
67     }
68 
refreshProtocolResponses()69     void refreshProtocolResponses() {
70         if (!mIsNetworkAvailable) {
71             return;
72         }
73         applyOffloadIntents(mOffloadIntentStore.getOffloadIntentsForInterface(mNetworkInterface));
74     }
75 
refreshPassthroughList()76     void refreshPassthroughList() {
77         if (!mIsNetworkAvailable) {
78             return;
79         }
80         applyPassthroughIntents(
81                 mOffloadIntentStore.getPassthroughIntentsForInterface(mNetworkInterface));
82     }
83 
clearProtocolResponses()84     private void clearProtocolResponses() {
85         applyOffloadIntents(Collections.emptySet());
86     }
87 
clearPassthroughList()88     private void clearPassthroughList() {
89         applyPassthroughIntents(Collections.emptyList());
90     }
91 
applyOffloadIntents(Collection<OffloadIntentStore.OffloadIntent> offloadIntents)92     private void applyOffloadIntents(Collection<OffloadIntentStore.OffloadIntent> offloadIntents) {
93         if (!mOffloadWriter.isVendorServiceConnected()) {
94             Log.e(TAG, "Vendor service disconnected, cannot apply mDNS offload state");
95             return;
96         }
97         Collection<Integer> deleted = mOffloadWriter.deleteOffloadData(mCurrentOffloadKeys);
98         mCurrentOffloadKeys.removeAll(deleted);
99         Collection<Integer> offloaded = mOffloadWriter.writeOffloadData(
100                 mNetworkInterface, offloadIntents);
101         mCurrentOffloadKeys.addAll(offloaded);
102     }
103 
applyPassthroughIntents( List<OffloadIntentStore.PassthroughIntent> passthroughIntents)104     private void applyPassthroughIntents(
105             List<OffloadIntentStore.PassthroughIntent> passthroughIntents) {
106         if (!mOffloadWriter.isVendorServiceConnected()){
107             Log.e(TAG, "Vendor service disconnected, cannot apply mDNS passthrough state");
108             return;
109         }
110         Collection<String> deleted = mOffloadWriter.deletePassthroughData(
111                 mNetworkInterface, mCurrentPassthroughQNames);
112         mCurrentPassthroughQNames.removeAll(deleted);
113         Collection<String> added = mOffloadWriter.writePassthroughData(
114                 mNetworkInterface, passthroughIntents);
115         mCurrentPassthroughQNames.addAll(added);
116     }
117 
118     @WorkerThread
dump(PrintWriter writer)119     void dump(PrintWriter writer) {
120         writer.println("InterfaceOffloadManager[%s]:".formatted(mNetworkInterface));
121         writer.println("mIsNetworkAvailable=%b".formatted(mIsNetworkAvailable));
122         writer.println("current offload keys:");
123         mCurrentOffloadKeys.forEach(key -> writer.println("* %d".formatted(key)));
124         writer.println("current passthrough qnames:");
125         mCurrentPassthroughQNames.forEach(qname -> writer.println("* %s".formatted(qname)));
126         writer.println();
127     }
128 
129 }
130