@@ -13,12 +13,14 @@ import (
1313
1414// mockTransport captures the last Transact call and returns a predetermined reply.
1515type mockTransport struct {
16- lastHandle uint32
17- lastCode binder.TransactionCode
18- lastFlags binder.TransactionFlags
19- lastData * parcel.Parcel
20- replyFunc func () * parcel.Parcel
21- err error
16+ lastHandle uint32
17+ lastCode binder.TransactionCode
18+ lastFlags binder.TransactionFlags
19+ lastData * parcel.Parcel
20+ replyFunc func () * parcel.Parcel
21+ err error
22+ lastReceiver binder.TransactionReceiver
23+ nextCookie uintptr
2224}
2325
2426func (m * mockTransport ) Transact (
@@ -38,8 +40,13 @@ func (m *mockTransport) Transact(
3840 return m .replyFunc (), nil
3941}
4042
41- func (m * mockTransport ) AcquireHandle (_ context.Context , _ uint32 ) error { return nil }
42- func (m * mockTransport ) ReleaseHandle (_ context.Context , _ uint32 ) error { return nil }
43+ func (m * mockTransport ) AcquireHandle (_ context.Context , _ uint32 ) error { return nil }
44+ func (m * mockTransport ) ReleaseHandle (_ context.Context , _ uint32 ) error { return nil }
45+ func (m * mockTransport ) RegisterReceiver (_ context.Context , receiver binder.TransactionReceiver ) uintptr {
46+ m .lastReceiver = receiver
47+ m .nextCookie ++
48+ return m .nextCookie
49+ }
4350
4451func (m * mockTransport ) RequestDeathNotification (
4552 _ context.Context ,
@@ -262,3 +269,118 @@ func TestGetService_TransportError(t *testing.T) {
262269 assert .Nil (t , result )
263270 assert .ErrorIs (t , err , assert .AnError )
264271}
272+
273+ // mockReceiver is a minimal TransactionReceiver for testing.
274+ type mockReceiver struct {}
275+
276+ func (r * mockReceiver ) OnTransaction (
277+ _ context.Context ,
278+ _ binder.TransactionCode ,
279+ _ * parcel.Parcel ,
280+ ) (* parcel.Parcel , error ) {
281+ return parcel .New (), nil
282+ }
283+
284+ func TestAddService (t * testing.T ) {
285+ ctx := context .Background ()
286+
287+ mt := & mockTransport {
288+ replyFunc : buildSuccessReply (func (_ * parcel.Parcel ) {}),
289+ }
290+
291+ receiver := & mockReceiver {}
292+ sm := New (mt )
293+ err := sm .AddService (ctx , ServiceName ("my.new.service" ), receiver , true , 4 )
294+ require .NoError (t , err )
295+
296+ // Verify the receiver was registered.
297+ assert .Equal (t , binder .TransactionReceiver (receiver ), mt .lastReceiver )
298+
299+ // Verify we sent to handle 0 (ServiceManager) with correct code.
300+ assert .Equal (t , uint32 (0 ), mt .lastHandle )
301+ assert .Equal (t , binder .FirstCallTransaction , mt .lastCode )
302+ assert .Equal (t , binder .TransactionFlags (0 ), mt .lastFlags )
303+
304+ // Verify the sent parcel data.
305+ mt .lastData .SetPosition (0 )
306+
307+ token , err := mt .lastData .ReadInterfaceToken ()
308+ require .NoError (t , err )
309+ assert .Equal (t , serviceManagerDescriptor , token )
310+
311+ svcName , err := mt .lastData .ReadString16 ()
312+ require .NoError (t , err )
313+ assert .Equal (t , "my.new.service" , svcName )
314+
315+ // Read the local binder object (flat_binder_object).
316+ handle , err := mt .lastData .ReadStrongBinder ()
317+ require .NoError (t , err )
318+ // The cookie is 1 (first call to RegisterReceiver on this mock).
319+ assert .Equal (t , uint32 (1 ), handle )
320+
321+ // allowIsolated = true -> 1
322+ allowIsolated , err := mt .lastData .ReadInt32 ()
323+ require .NoError (t , err )
324+ assert .Equal (t , int32 (1 ), allowIsolated )
325+
326+ // dumpPriority = 4
327+ dumpPriority , err := mt .lastData .ReadInt32 ()
328+ require .NoError (t , err )
329+ assert .Equal (t , int32 (4 ), dumpPriority )
330+ }
331+
332+ func TestAddService_NotIsolated (t * testing.T ) {
333+ ctx := context .Background ()
334+
335+ mt := & mockTransport {
336+ replyFunc : buildSuccessReply (func (_ * parcel.Parcel ) {}),
337+ }
338+
339+ sm := New (mt )
340+ err := sm .AddService (ctx , ServiceName ("isolated.service" ), & mockReceiver {}, false , 0 )
341+ require .NoError (t , err )
342+
343+ // Verify allowIsolated is written as 0.
344+ mt .lastData .SetPosition (0 )
345+ _ , _ = mt .lastData .ReadInterfaceToken ()
346+ _ , _ = mt .lastData .ReadString16 ()
347+ _ , _ = mt .lastData .ReadStrongBinder ()
348+
349+ allowIsolated , err := mt .lastData .ReadInt32 ()
350+ require .NoError (t , err )
351+ assert .Equal (t , int32 (0 ), allowIsolated )
352+ }
353+
354+ func TestAddService_StatusError (t * testing.T ) {
355+ ctx := context .Background ()
356+
357+ mt := & mockTransport {
358+ replyFunc : func () * parcel.Parcel {
359+ p := parcel .New ()
360+ binder .WriteStatus (p , & aidlerrors.StatusError {
361+ Exception : aidlerrors .ExceptionSecurity ,
362+ Message : "not allowed" ,
363+ })
364+ p .SetPosition (0 )
365+ return p
366+ },
367+ }
368+
369+ sm := New (mt )
370+ err := sm .AddService (ctx , ServiceName ("blocked.service" ), & mockReceiver {}, false , 0 )
371+ require .Error (t , err )
372+ assert .Contains (t , err .Error (), "not allowed" )
373+ }
374+
375+ func TestAddService_TransportError (t * testing.T ) {
376+ ctx := context .Background ()
377+
378+ mt := & mockTransport {
379+ err : assert .AnError ,
380+ }
381+
382+ sm := New (mt )
383+ err := sm .AddService (ctx , ServiceName ("fail.service" ), & mockReceiver {}, false , 0 )
384+ require .Error (t , err )
385+ assert .ErrorIs (t , err , assert .AnError )
386+ }
0 commit comments