| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build android |
| |
| package discovery |
| import ( |
| "bytes" |
| "unsafe" |
| |
| "v.io/v23/context" |
| |
| "v.io/x/ref/lib/discovery" |
| "v.io/x/ref/runtime/factories/android" |
| |
| jcontext "v.io/x/jni/v23/context" |
| jutil "v.io/x/jni/util" |
| |
| "third_party/go/tool/android_arm/src/runtime" |
| ) |
| |
| // #include "jni.h" |
| import "C" |
| |
| var ( |
| androidContextSign = jutil.ClassSign("android.content.Context") |
| contextSign = jutil.ClassSign("io.v.v23.Context") |
| advertisementSign = jutil.ClassSign("io.v.x.ref.lib.discovery.Advertisement") |
| uuidSign = jutil.ClassSign("java.util.UUID") |
| scanHandlerSign = jutil.ClassSign("io.v.impl.google.lib.discovery.ScanHandler") |
| ) |
| |
| |
| func NewPluginCreator(env jutil.Env, context C.jobject) func(string) (discovery.Plugin, error) { |
| // Reference Java VPrincipal; it will be de-referenced when the Go Principal |
| // created below is garbage-collected (through the finalizer callback we |
| // setup just below). |
| jContext = jutil.NewGlobalRef(env, context) |
| return func(host string) (discovery.Plugin, error) { |
| env, freeFunc := jutil.GetEnv() |
| defer freeFunc() |
| jPlugin, err := jutil.NewObject(env, jBlePluginClass, []jutil.Sign{androidContextSign}, context) |
| |
| jutil.DeleteGlobalRef(env, jContext) |
| if err != nil { |
| return nil, err |
| } |
| jplugin = jutil.NewGlobalRef(env, jPlugin) |
| p := &plugin{ |
| trigger: discovery.NewTrigger(), |
| jPlugin: jPlugin, |
| } |
| runtime.SetFinalizer(p, func(p *plugin) { |
| env, freeFunc := jutil.GetEnv() |
| defer freeFunc() |
| jutil.DeleteGlobalRef(env, p.jPlugin) |
| }) |
| return p, nil |
| } |
| |
| } |
| |
| type plugin struct { |
| trigger *discovery.Trigger |
| jPlugin C.jobject |
| } |
| |
| // Plugin is the basic interface for a plugin to discovery service. |
| // All implementation should be goroutine-safe. |
| type Plugin interface { |
| // Advertise advertises the advertisement. Advertising will continue until |
| // the context is canceled or exceeds its deadline. done should be called |
| // once when advertising is done or canceled. |
| Advertise(ctx *context.T, ad Advertisement, done func()) error |
| |
| // Scan scans services that match the service uuid and returns scanned |
| // advertisements to the channel. A zero-value service uuid means any service. |
| // Scanning will continue until the context is canceled or exceeds its |
| // deadline. done should be called once when scanning is done or canceled. |
| // |
| // TODO(jhahn): Pass a filter on service attributes. |
| Scan(ctx *context.T, serviceUuid Uuid, ch chan<- Advertisement, done func()) error |
| } |
| func (p *plugin) Advertise(ctx *context.T, ad discovery.Advertisement, done func()) error { |
| env, freeFunc := jutil.GetEnv() |
| defer freeFunc() |
| jContext, err := jcontext.NewJavaContext(env, ctx) |
| if err != nil { |
| return err |
| } |
| jAdv, err := jutil.JVomCopy(env, ad, jAdvertisementClass) |
| if err != nil { |
| return err |
| } |
| |
| err := jutil.CallVoidMethod(env, p.jPlugin, "addAdvertisesment", []jutil.Sign{contextSign, advertisementSign}, jContext, jAdv) |
| |
| p.trigger.Add(done, ctx.Done()) |
| |
| return err |
| } |
| |
| func (p *plugin) Scan(ctx *context.T, serviceUuid discovery.Uuid, ch chan<- discovery.Advertisement, done func()) error { |
| env, freeFunc := jutil.GetEnv() |
| defer freeFunc() |
| jContext, err := jcontext.NewJavaContext(env, ctx) |
| if err != nil { |
| return err |
| } |
| |
| jUuid, err := convertToJavaUUID(env, serviceUuid) |
| |
| if err != nil { |
| return err |
| } |
| |
| |
| chPtr := &ch |
| jutil.GoRef(chPtr) |
| jNativeScanHandler, err := jutil.NewObject(env, jNativeScanHandlerClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(chPtr))) |
| if err != nil { |
| return err |
| } |
| |
| err = jutil.CallVoidMethod(env, p.jPlugin, "addScanner", []jutil.Sign{contextSign, uuidSign, scanHandlerSign}, |
| jContext, jUuid, jNativeScanHandler) |
| |
| if err != nil { |
| return err |
| } |
| p.trigger.Add(done, ctx.Done()) |
| return nil |
| } |
| |
| |
| func convertToJavaUUID(env, jutil.Env, uuid discovery.Uuid) (C.jobject, error) { |
| buf := bytes.NewBuffer(uuid) |
| var high, low int64 |
| binary.Read(buf, binary.BigEndian, &high) |
| binary.Read(buf, binary.BigEndian, &low) |
| jUUID, err := jutil.NewObject(env, jUUIDClass, []jutil.Sign{jutil.LongSign, jutil.LongSign}, high, low) |
| } |