使用Xamarin Android AIDL parcelable

时间:2017-07-14 13:34:14

标签: android xamarin parcelable aidl

我在服务器和服务器之间通过AIDL传输parcelable对象时收到对象Marshall错误客户端作为两个不同的Xamarin Android应用程序(或者具有不同的服务流程):

 07-11 17:30:35.971 I/mono-stdout(23384):
 Java.Lang.IllegalStateException: Bad magic number for Bundle: 0x610072
     Java.Lang.IllegalStateException: Bad magic number for Bundle: 0x610072
       at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <3fd174ff54b146228c505f23cf75ce71>:0 
       at Java.Interop.JniEnvironment+InstanceMethods.CallObjectMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo
 method, Java.Interop.JniArgumentValue* args) [0x00069] in
 <bd30a18775d94dc8b6263aecd1ca9077>:0 
       at Android.Runtime.JNIEnv.CallObjectMethod (System.IntPtr jobject, System.IntPtr jmethod, Android.Runtime.JValue* parms)
 [0x0000e] in <9ab9faae1b4b4f0da28e7c4ac61e2c78>:0 
       at Android.OS.IParcelableCreatorInvoker.CreateFromParcel (Android.OS.Parcel source) [0x0005a] in
 <9ab9faae1b4b4f0da28e7c4ac61e2c78>:0 
       at AIDLBindingServer.IAdditionServiceStub+Proxy.GetParcelableObj () [0x0002f] in
 C:\Projects\xn\aidl\AIDLBindingLib\AIDLBindingServer\AIDLBindingServer\obj\Release\aidl\IAdditionService.cs:124

       at Xamarin.AidlDemo.Activity1.<OnStart>b__10_0 (System.Object sender, System.EventArgs e) [0x000c5] in
 C:\Projects\xn\aidl\AIDLDemoClient\AIDLDemoClient\Activity1.cs:53 
       --- End of managed Java.Lang.IllegalStateException stack trace ---
     java.lang.IllegalStateException: Bad magic number for Bundle: 0x610072
     07-11 17:30:35.976 I/mono-stdout(23384):   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw ()
 [0x0000c] in <3fd174ff54b146228c505f23cf75ce71>:0 
        at android.os.BaseBundle.readFromParcelInner(BaseBundle.java:1443)
        at android.os.BaseBundle.<init>(BaseBundle.java:128)
        at android.os.Bundle.<init>(Bundle.java:69)
        at android.os.Parcel.readBundle(Parcel.java:1879)
        at android.os.Parcel.readBundle(Parcel.java:1863)
        at android.os.Bundle$1.createFromParcel(Bundle.java:1127)
        at android.os.Bundle$1.createFromParcel(Bundle.java:1126)
        at mono.android.view.View_OnClickListenerImplementor.n_onClick(Native
 Method)
        at mono.android.view.View_OnClickListenerImplementor.onClick(View_OnClickListenerImplementor.java:30)
        at android.view.View.performClick(View.java:5637)
        at android.view.View$PerformClick.run(View.java:22429)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:
     886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
     07-11 17:30:35.976 I/mono-stdout(23384):   at Java.Interop.JniEnvironment+InstanceMethods.CallObjectMethod
 (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo
 method, Java.Interop.JniArgumentValue* args) [0x00069] in
 <bd30a18775d94dc8b6263aecd1ca9077>:0 
     07-11 17:30:35.976 I/mono-stdout(23384):   at Android.Runtime.JNIEnv.CallObjectMethod (System.IntPtr jobject,
 System.IntPtr jmethod, Android.Runtime.JValue* parms) [0x0000e] in
 <9ab9faae1b4b4f0da28e7c4ac61e2c78>:0 
     07-11 17:30:35.976 I/mono-stdout(23384):   at Android.OS.IParcelableCreatorInvoker.CreateFromParcel
 (Android.OS.Parcel source) [0x0005a] in
 <9ab9faae1b4b4f0da28e7c4ac61e2c78>:0 
     07-11 17:30:35.976 I/mono-stdout(23384):   at AIDLBindingServer.IAdditionServiceStub+Proxy.GetParcelableObj ()
 [0x0002f] in
 C:\Projects\xn\aidl\AIDLBindingLib\AIDLBindingServer\AIDLBindingServer\obj\Release\aidl\IAdditionService.cs:124

     07-11 17:30:35.976 I/mono-stdout(23384):   at Xamarin.AidlDemo.Activity1.<OnStart>b__10_0 (System.Object sender,
 System.EventArgs e) [0x000c5] in
 C:\Projects\xn\aidl\AIDLDemoClient\AIDLDemoClient\Activity1.cs:53 
     07-11 17:30:35.976 I/mono-stdout(23384):   --- End of managed Java.Lang.IllegalStateException stack trace ---
     07-11 17:30:35.977 I/mono-stdout(23384): java.lang.IllegalStateException: Bad magic number for Bundle: 0x610072
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.os.BaseBundle.readFromParcelInner(BaseBundle.java:1443)
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.os.BaseBundle.<init>(BaseBundle.java:128)
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.os.Bundle.<init>(Bundle.java:69)
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.os.Parcel.readBundle(Parcel.java:1879)
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.os.Parcel.readBundle(Parcel.java:1863)
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.os.Bundle$1.createFromParcel(Bundle.java:1127)
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.os.Bundle$1.createFromParcel(Bundle.java:1126)
     07-11 17:30:35.977 I/mono-stdout(23384):   at mono.android.view.View_OnClickListenerImplementor.n_onClick(Native
 Method)
     07-11 17:30:35.977 I/mono-stdout(23384):   at mono.android.view.View_OnClickListenerImplementor.onClick(View_OnClickListenerImplementor.java:30)
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.view.View.performClick(View.java:5637)
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.view.View$PerformClick.run(View.java:22429)
     07-11 17:30:35.977 I/mono-stdout(23384):   at android.os.Handler.handleCallback(Handler.java:751)
     07-11 17:30:35.978 I/mono-stdout(23384):   at android.os.Handler.dispatchMessage(Handler.java:95)
     07-11 17:30:35.978 I/mono-stdout(23384):   at android.os.Looper.loop(Looper.java:154)
     07-11 17:30:35.978 I/mono-stdout(23384):   at android.app.ActivityThread.main(ActivityThread.java:6119)
     07-11 17:30:35.978 I/mono-stdout(23384):   at java.lang.reflect.Method.invoke(Native Method)
     07-11 17:30:35.978 I/mono-stdout(23384):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
     07-11 17:30:35.978 I/mono-stdout(23384):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

IAdditionService.aidl

package AIDLBindingServer;

interface IAdditionService {
int add(in int value1, in int value2);
ParcelableObj  getParcelableObj();
}

ParcelableObj.aidl

package AIDLBindingServer;

parcelable ParcelableObj;

ParcelableObj.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.OS;
using Android.Runtime;
using Java.Interop;
using Java.Lang;
using Object = Java.Lang.Object;

namespace AIDLBindingServer
{
    [Register("AIDLBindingServer.ParcelableObj", DoNotGenerateAcw = false)]
    public class ParcelableObj : Object, IParcelable
    {
        /*private static readonly long serialVersionUID = -3892107077759983950L;*/
      //  static readonly int BUNDLE_MAGIC = 0x4C444E42;
        [ExportField ("CREATOR")]
        public static ParcelableObjCreator InitializeCreator()
        {
            return new ParcelableObjCreator();
        }

        public ParcelableObj()
        {
        }

        public string Name
        {
            get;
            set;
        }

        public ParcelableObj(string Name)
        {
            this.Name = Name;
        }

        #region IParcelable implementation
        public int DescribeContents()
        {
            return 0;

        }

        public void WriteToParcel(Parcel dest, ParcelableWriteFlags flags)
        {
            dest.WriteString(this.Name);
        }
        #endregion
    }

    [Register("AIDLBindingServer.ParcelableObjCreator", DoNotGenerateAcw = false)]
    public sealed class ParcelableObjCreator : Object, IParcelableCreator
    {
        public Object CreateFromParcel(Parcel source)
        {
            return new ParcelableObj(source.ReadString());
        }

        public Object[] NewArray(int size)
        {
             return new Java.Lang.Object[size];
           // throw new UnsupportedOperationException();
        }
    }
}

AdditionService.cs

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;

namespace Xamarin.AidlDemo
{
    [Service(Process = "com.xamarin.additionservice")]
    [IntentFilter(new String[] {"com.xamarin.additionservice"})]
    public class AdditionService: Service
    {
        private static readonly string Tag = "AdditionService";
        private AdditionServiceBinder _binder;

        public override void OnCreate ()
        {
            base.OnCreate ();
            Log.Debug (Tag, "Addition Service created.");
        }

        public override IBinder OnBind (Intent intent)
        {
            _binder = new AdditionServiceBinder();
            return _binder;
        }
        public override void OnDestroy ()
        {
            base.OnDestroy ();
            Log.Debug (Tag, "Addition service stopped.");
        }

    }
}

AdditionServiceBinder.cs

using Android.Util;
using System;
using AIDLBindingServer;

namespace Xamarin.AidlDemo
{
    public class AdditionServiceBinder: IAdditionServiceStub, IAdditionService
    {
        public static readonly string Tag = "AdditionServiceBinder";
        public override int Add (int value1, int value2)
        {
            Log.Debug (Tag, "AdditionService.Add({0}, {1})", value1, value2);
            return value1 + value2;
        }

        public override ParcelableObj GetParcelableObj()
        {
            /*throw new NotImplementedException();*/
            return new ParcelableObj("raheem"/*,"32"*/);
        }
    }
}

AdditionServiceConnection.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AIDLBindingCLib;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;

namespace Xamarin.AidlDemo
{
    class AdditionServiceConnection : Java.Lang.Object, IServiceConnection
    {
        Activity1 _activity;

        public AdditionServiceConnection (Activity1 activity)
        {
            _activity = activity;
        }

        public IAdditionService Service 
        {
            get; private set;
        }

        public void OnServiceConnected (ComponentName name, IBinder service)
        {
            Service =   IAdditionServiceStub.AsInterface(service);
            _activity.Service = (IAdditionService) Service;
            _activity.IsBound = Service != null;

        }

        public void OnServiceDisconnected (ComponentName name)
        {
            _activity.Service = null;
            _activity.IsBound = false;
        }
    }
}

Activity1.cs

using System;
using AIDLBindingCLib;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Util;
using Android.Widget;
using Android.OS;
using Java.Interop;

namespace Xamarin.AidlDemo
{
    [Activity (Label = "AIDL Demo Server", MainLauncher = true)]
    public class Activity1 : Activity
    {
        public static readonly String Tag = "Activity1";
        private AdditionServiceConnection _serviceConnection;

        public IAdditionService Service { get; set; }

        public bool IsBound { get; set; }


        protected override void OnStart ()
        {
            base.OnStart ();
            InitService ();

            var button1 = FindViewById<Button> (Resource.Id.buttonCalc);

            button1.Click += (sender, e) => {
                if (IsBound) {
                    var text1 = FindViewById<EditText> (Resource.Id.value1);
                    var text2 = FindViewById<EditText> (Resource.Id.value2);
                    var primitive_result = FindViewById<TextView> (Resource.Id.primitive_result);
                    var parcelable_result = FindViewById<TextView> (Resource.Id.parcelable_result);
                    var connection_result = FindViewById<TextView> (Resource.Id.connection_result);

                    int v1;
                    int v2;
                    int v3;


                    if(Int32.TryParse (text2.Text, out v2) && Int32.TryParse (text1.Text, out v1)) {
                        v3 = Service.Add (v1, v2);
                    } else {
                        v3 = 0;
                        var builder = new AlertDialog.Builder(this);
                        builder.SetMessage("Spaces or special character are not allowed");
                        builder.SetNeutralButton("OK", (source, eventArgs) => {});
                        builder.Show();
                    }
                    primitive_result.Text = v3.ToString();

                    try
                    {
                        ParcelableObj obj = Service.GetParcelableObj();
                        parcelable_result.Text= "parcelable_result:"+ obj.Name;
                    }
                    catch (Exception exception)
                    {
                        Console.WriteLine(exception);
                        parcelable_result.Text = "parcelable_result:" + exception.Message;
                    }



                } else {
                    Log.Warn (Tag, "The AdditionService is not bound");
                }

            };

        }

        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);
            SetContentView (Resource.Layout.main);
        }

        protected override void OnDestroy ()
        {
            base.OnDestroy ();
            ReleaseService ();
        }

        private void InitService ()
        {
            _serviceConnection = new AdditionServiceConnection (this);
            var additionServiceIntent = new Intent ("com.xamarin.additionservice");
            additionServiceIntent.SetPackage("AIDLDemo.AIDLDemo");
            bool ret = BindService (additionServiceIntent, _serviceConnection, Bind.AutoCreate);
            Log.Debug (Tag, "Service initialized:"+ret);
            try
            {
                var connection_result = FindViewById<TextView>(Resource.Id.connection_result);
                connection_result.Text = "Service initialized:" + ret;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);

            }

        }

        private void ReleaseService ()
        {
            if (IsBound) {
                ApplicationContext.UnbindService (_serviceConnection);
                IsBound = false;
                _serviceConnection = null;
                Log.Debug (Tag, "Service released.");
            }
        }
    }
}

生成IAdditionServiceStub

// This file is automatically generated and not supposed to be modified.
using System;
using Boolean = System.Boolean;
using String = System.String;
using List = Android.Runtime.JavaList;
using Map = Android.Runtime.JavaDictionary;

namespace Xamarin.AidlDemo
{
    public interface IAdditionService : global::Android.OS.IInterface
    {
        int Add (int value1, int value2);
        global::Xamarin.AidlDemo.ParcelableObj GetParcelableObj ();
    }

    public abstract class IAdditionServiceStub : global::Android.OS.Binder, global::Android.OS.IInterface, Xamarin.AidlDemo.IAdditionService
    {
        const string descriptor = "Xamarin.AidlDemo.IAdditionService";
        public IAdditionServiceStub ()
        {
            this.AttachInterface (this, descriptor);
        }

        public static Xamarin.AidlDemo.IAdditionService AsInterface (global::Android.OS.IBinder obj)
        {
            if (obj == null)
                return null;
            var iin = (global::Android.OS.IInterface) obj.QueryLocalInterface (descriptor);
            if (iin != null && iin is Xamarin.AidlDemo.IAdditionService)
                return (Xamarin.AidlDemo.IAdditionService) iin;
            return new Proxy (obj);
        }

        public global::Android.OS.IBinder AsBinder ()
        {
            return this;
        }

        protected override bool OnTransact (int code, global::Android.OS.Parcel data, global::Android.OS.Parcel reply, int flags)
        {
            switch (code) {
            case global::Android.OS.BinderConsts.InterfaceTransaction:
                reply.WriteString (descriptor);
                return true;

            case TransactionAdd: {
                data.EnforceInterface (descriptor);
                int arg0 = default (int);
                arg0 = data.ReadInt ();
                int arg1 = default (int);
                arg1 = data.ReadInt ();
                var result = this.Add (arg0, arg1);
                reply.WriteNoException ();
                reply.WriteInt (result);
                return true;
                }

            case TransactionGetParcelableObj: {
                data.EnforceInterface (descriptor);
                var result = this.GetParcelableObj ();
                reply.WriteNoException ();
                if (result != null) { reply.WriteInt (1); result.WriteToParcel (reply, global::Android.OS.ParcelableWriteFlags.ReturnValue); } else reply.WriteInt (0);
                return true;
                }

            }
            return base.OnTransact (code, data, reply, flags);
        }

        public class Proxy : Java.Lang.Object, Xamarin.AidlDemo.IAdditionService
        {
            global::Android.OS.IBinder remote;

            public Proxy (global::Android.OS.IBinder remote)
            {
                this.remote = remote;
            }

            public global::Android.OS.IBinder AsBinder ()
            {
                return remote;
            }

            public string GetInterfaceDescriptor ()
            {
                return descriptor;
            }

            public int Add (int value1, int value2)
            {
                global::Android.OS.Parcel __data = global::Android.OS.Parcel.Obtain ();

                global::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain ();
int __result = default (int);

                try {
                    __data.WriteInterfaceToken (descriptor);
                    __data.WriteInt (value1);
                    __data.WriteInt (value2);
                    remote.Transact (IAdditionServiceStub.TransactionAdd, __data, __reply, 0);
                    __reply.ReadException ();
                    __result = __reply.ReadInt ();

                } finally {
                    __reply.Recycle ();
                    __data.Recycle ();
                }
                return __result;

            }


            public global::Xamarin.AidlDemo.ParcelableObj GetParcelableObj ()
            {
                global::Android.OS.Parcel __data = global::Android.OS.Parcel.Obtain ();

                global::Android.OS.Parcel __reply = global::Android.OS.Parcel.Obtain ();
global::Xamarin.AidlDemo.ParcelableObj __result = default (global::Xamarin.AidlDemo.ParcelableObj);

                try {
                    __data.WriteInterfaceToken (descriptor);
                    remote.Transact (IAdditionServiceStub.TransactionGetParcelableObj, __data, __reply, 0);
                    __reply.ReadException ();
                    __result = __reply.ReadInt () != 0 ? (global::Xamarin.AidlDemo.ParcelableObj) global::Android.OS.Bundle.Creator.CreateFromParcel (__reply) : null;

                } finally {
                    __reply.Recycle ();
                    __data.Recycle ();
                }
                return __result;

            }


        }

        internal const int TransactionAdd = global::Android.OS.Binder.InterfaceConsts.FirstCallTransaction + 0;

        internal const int TransactionGetParcelableObj = global::Android.OS.Binder.InterfaceConsts.FirstCallTransaction + 1;

        public abstract int Add (int value1, int value2);

        public abstract global::Xamarin.AidlDemo.ParcelableObj GetParcelableObj ();

    }
}

让我知道如何使用Xamarin Android中的两个应用程序或进程之间的parcellable对象修复此编组错误

1 个答案:

答案 0 :(得分:1)

似乎Xamarin AIDL生成器中存在错误。

请注意IAdditionServiceStub中的这一行(在嵌套类Proxy内):

__result = __reply.ReadInt () != 0 ? (global::Xamarin.AidlDemo.ParcelableObj) global::Android.OS.Bundle.Creator.CreateFromParcel (__reply) : null;

看起来完全是胡说八道:代码使用Android.OS.Bundle.Creator.CreateFromParcel将IPC响应解码为Bundle的实例,然后尝试将结果转换为ParcelableObj

您的ParcelableObj当然不是Bundle的实例。事件(如果是,代码仍然不正确) - 创建Parcelable类的唯一合适方法是使用该类CREATOR字段,例如ParcelableObj.Creator.CreateFromParcel。使用相同的* .aidl文件创建一个Java项目,并尝试将Google的 aidl 工具生成的代码与您在上面发布的IAdditionServiceStub进行比较, - 您将自己看到问题。

我没有足够精通C#来确定错误原因,但您应该尝试升级Xamarin安装。也许错误已经修复了。如果不是,请尝试在Xamarin bugtracker上创建一个问题(如果还没有问题)。

与此同时,在Xamarin方面解决错误之前,您有几个选择。

  1. 删除生成的AIDL接口,删除* .aidl文件,手动编写IPC编组代码。 Ough。
  2. 按照this official tutorial中的说明使用Messenger + Bundle。每种方法都会有一些样板,但这种方法总体上是可用的。
  3. 或者将IPC代码移动到单独的Java库模块。如果您这样做,您应该能够使用官方的 aidl 工具或其他方式生成IPC代理实现(例如使用我为此目的编写的library)。