diff options
Diffstat (limited to 'MdnsOffloadCmdService/src/com/android/tv/mdnsoffloadcmd/MdnsOffloadCmdService.java')
-rw-r--r-- | MdnsOffloadCmdService/src/com/android/tv/mdnsoffloadcmd/MdnsOffloadCmdService.java | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/MdnsOffloadCmdService/src/com/android/tv/mdnsoffloadcmd/MdnsOffloadCmdService.java b/MdnsOffloadCmdService/src/com/android/tv/mdnsoffloadcmd/MdnsOffloadCmdService.java new file mode 100644 index 0000000..05cfbfb --- /dev/null +++ b/MdnsOffloadCmdService/src/com/android/tv/mdnsoffloadcmd/MdnsOffloadCmdService.java @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2023 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.tv.mdnsoffloadcmd; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.RemoteException; +import android.widget.Toast; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; +import androidx.core.content.ContextCompat; + +import java.util.HexFormat; + +import device.google.atv.mdns_offload.IMdnsOffloadManager; + +public class MdnsOffloadCmdService extends Service { + private static final String TAG = MdnsOffloadCmdService.class.getSimpleName(); + + private static final String ACTION_OFFLOAD_COMMAND = + "com.android.tv.mdnsoffloadcmd.OFFLOAD_COMMAND"; + + private static final String CHANNEL_ID = "MdnsOffloadCmdService"; + + private IMdnsOffloadManager mMdnsOffloadManagerService; + private IBinder mBinder; + + @Nullable + @Override + public IBinder onBind(Intent intent) { + //We don't want any app to bind to this service. + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + mBinder = new Binder(); + setupCommandBroadcastReceiver(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + createNotificationChannel(); + + Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) + .setContentTitle("Foreground Service") + .setSmallIcon(R.drawable.notification_template_icon_low_bg) + .build(); + + bindMdnsOffloadManager(); + + startForeground(1, notification); + return START_NOT_STICKY; + } + + private void createNotificationChannel() { + NotificationChannel serviceChannel = new NotificationChannel( + CHANNEL_ID, + "Foreground Service Channel", + NotificationManager.IMPORTANCE_DEFAULT + ); + + NotificationManager manager = getSystemService(NotificationManager.class); + manager.createNotificationChannel(serviceChannel); + } + + private void registerProtocolResponse(String rawHexPacket, String iface) { + Log.d(TAG, "Registering on iface{" + iface + "} :" + rawHexPacket); + IMdnsOffloadManager.OffloadServiceInfo info = + new IMdnsOffloadManager.OffloadServiceInfo(); + info.rawOffloadPacket = HexFormat.of().parseHex(rawHexPacket); + try { + if (mMdnsOffloadManagerService == null) { + Log.e(TAG, "Offload Manager not connected"); + return; + } + int recordKey = mMdnsOffloadManagerService.addProtocolResponses(iface, info, mBinder); + Log.d(TAG, "Packet offloaded with recordKey=" + recordKey); + } catch (RemoteException e) { + Log.e(TAG, "Error while registering debug packet", e); + } + } + + private void registerPassthrough(String qname, String iface) { + Log.d(TAG, "Registering on iface{" + iface + "} passthrough:" + qname); + try { + if (mMdnsOffloadManagerService == null) { + Log.e(TAG, "Offload Manager not connected"); + return; + } + mMdnsOffloadManagerService.addToPassthroughList(iface, qname, mBinder); + } catch (RemoteException e) { + Log.e(TAG, "Error while adding passthrough qname", e); + } + } + + private void removeProtocolResponse(int recordKey) { + IMdnsOffloadManager.OffloadServiceInfo info = + new IMdnsOffloadManager.OffloadServiceInfo(); + try { + if (mMdnsOffloadManagerService == null) { + Log.e(TAG, "Offload Manager not connected"); + return; + } + mMdnsOffloadManagerService.removeProtocolResponses(recordKey, mBinder); + Log.d(TAG, "Removed record " + recordKey); + } catch (RemoteException e) { + Log.e(TAG, "Error while registering debug packet", e); + } + } + + private void removePassthrough(String qname, String iface) { + Log.d(TAG, "Removing passthrough:" + qname + " on iface{" + iface + "}"); + try { + if (mMdnsOffloadManagerService == null) { + Log.e(TAG, "Offload Manager not connected"); + return; + } + mMdnsOffloadManagerService.removeFromPassthroughList(iface, qname, mBinder); + } catch (RemoteException e) { + Log.e(TAG, "Error while removing passthrough qname", e); + } + } + + private void setupCommandBroadcastReceiver() { + BroadcastReceiver receiver = new CommandBroadcastReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_OFFLOAD_COMMAND); + registerReceiver(receiver, filter, ContextCompat.RECEIVER_EXPORTED); + } + + private class CommandBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getStringExtra("action"); + switch (action) { + case "ADD_OFFLOAD": { + String iface = intent.getStringExtra("iface"); + String rawHexPacket = intent.getStringExtra("raw_hex_packet"); + if (rawHexPacket != null && iface != null) { + registerProtocolResponse(rawHexPacket, iface); + } else { + Log.d(TAG, "Bad parameters for ADD_OFFLOAD command"); + } + break; + } + case "REMOVE_OFFLOAD": { + int recordKey = intent.getIntExtra("recordKey", -1); + if (recordKey >= 0) { + removeProtocolResponse(recordKey); + } else { + Log.d(TAG, "Bad parameters for REMOVE_OFFLOAD command"); + } + break; + } + case "ADD_PASSTHROUGH": { + String iface = intent.getStringExtra("iface"); + String qname = intent.getStringExtra("qname"); + if (iface != null && qname != null) { + registerPassthrough(qname, iface); + } else { + Log.d(TAG, "Bad parameters for ADD_PASSTHROUGH command"); + } + break; + } + case "REMOVE_PASSTHROUGH": { + String iface = intent.getStringExtra("iface"); + String qname = intent.getStringExtra("qname"); + if (iface != null && qname != null) { + removePassthrough(qname, iface); + } else { + Log.d(TAG, "Bad parameters for REMOVE_PASSTHROUGH command"); + } + break; + } + } + } + } + + + private void bindMdnsOffloadManager() { + ComponentName componentName = ComponentName.unflattenFromString( + "com.android.tv.mdnsoffloadmanager/.MdnsOffloadManagerService"); + Intent explicitIntent = new Intent(); + explicitIntent.setComponent(componentName); + boolean bindingSuccessful = bindService(explicitIntent, + mMdnsOffloadManagerServiceConnection, Context.BIND_AUTO_CREATE); + if (!bindingSuccessful) { + String msg = "Failed to bind MdnsOffloadManager."; + Log.e(TAG, msg); + throw new IllegalStateException(msg); + } + } + + + private final ServiceConnection mMdnsOffloadManagerServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + Log.i(TAG, "IMdnsOffloadManager service bound successfully."); + mMdnsOffloadManagerService = IMdnsOffloadManager.Stub.asInterface(service); + } + + public void onServiceDisconnected(ComponentName className) { + Log.e(TAG, "IMdnsOffloadManager service has unexpectedly disconnected."); + mMdnsOffloadManagerService = null; + } + }; + +} |