2010-07-01 12 views
22

इसलिए मैंने एंड्रॉइड ओएस के लिए एक सेवा और गतिविधि लिखी है।एंड्रॉइड रिमोट अपवाद और सेवाएं

मेरी सेवा अपनी प्रक्रिया में चल रही है, इसलिए मेरी गतिविधियां और सेवा के बीच सभी संचार आईपीसी के माध्यम से होता है। मैं इसके लिए मानक एंड्रॉइड .aidl तंत्र का उपयोग करता हूं।

अभी तक सबकुछ ठीक काम करता है। हालांकि, एआईडीएल "रिमोटएक्सप्शन फेंकता" का उपयोग कर सभी विधि स्टब्स उत्पन्न करता है इसलिए मुझे उन्हें संभालना होगा।

मैंने पूरे एंड्रॉइड स्रोत कोड पर एक त्वरित grep किया और केवल तीन मामलों को पाया जहां यह अपवाद कभी फेंक दिया गया है। ये एक अलग सेवा में हैं जिनसे मैं कनेक्ट नहीं हूं।

मैंने सी-स्रोतों की भी जांच की क्योंकि सिद्धांत में रिमोटएक्सप्शन जेएनआई इंटरफ़ेस का उपयोग करके उत्पन्न किया जा सकता है .. कुछ भी नहीं हुआ।

मैं धारणा है कि हर किसी को सिर्फ इस तरह उन्हें संभालती है:

try { 

    mService.someMethodCall (someArguments); 

    } catch (RemoteException e) { 

    e.printStackTrace(); 

    } 

यह ठोस कोड नहीं है, और मैं अपने कोड आधार में कुछ इस तरह नहीं करना चाहते।

इसके अलावा: मैंने आईपीसी के माध्यम से रिमोटएक्सप्शन फेंकने की कोशिश की और मुझे जो कुछ मिला वह एक स्टैक-ट्रेस और एक सिस्टम लॉग संदेश था जो मुझे बताता है कि अपवाद अभी तक समर्थित नहीं हैं। मेरा आवेदन अपवाद और सेवाओं है कि

:-(अपवाद एक बहुत ही अजीब राज्य में समाप्त हो गया (आधे रास्ते काम) फेंक दिया सवाल कर रहे हैं कभी नहीं देखा था:

  • क्या ये अपवाद कभी फेंक दिया हो

  • क्या कभी किसी ने देखा इस तरह के एक कोशिश पकड़ ब्लॉक एक RemoteException पकड़ने गया है?

  • यह हो सकता है कि वे मौजूद नहीं है और है कि हम सिर्फ इसलिए कि "RemoteException फेंकता" उन लोगों के साथ निपटने के लिए मजबूर कर रहे हैं एआईडीएल कंपाइलर के अंदर मृत कोड या बाएं ओवर है?

अस्वीकरण: मैंने पूरे स्रोत-कोड को नहीं पढ़ा है। मैंने रिमोटएक्सप्शन की घटनाओं को खोजने के लिए जीआरपी का इस्तेमाल किया, इसलिए मैंने अलग-अलग व्हाइटस्पेस उपयोग के कारण कुछ याद किया होगा।

उत्तर

49

इन अपवादों को वास्तव में फेंक दिया जाता है और आपको उस स्थिति को संभालने के लिए उचित प्रयास/पकड़ तर्क लिखना चाहिए जहां एक सेवा पर आपके द्वारा लगाई गई दूरस्थ विधि पूरी नहीं हुई थी।

जहां तक ​​आपकी जांच, आप मूल स्रोतों को देखकर सही रास्ते पर थे। आपने जो अनदेखा किया हो वह है कि android.os.RemoteException वास्तव में अन्य बाइंडर से संबंधित अपवादों के लिए एक बेस क्लास है और यह एक उप-वर्ग है, android.os.DeadObjectException, जिसे native code of Binder के भीतर फेंक दिया गया है।

एक गतिविधि इस अपवाद को देखेगी यदि यह किसी अन्य प्रक्रिया में चल रही सेवा का उपयोग करती है जो अनुरोध करने के बीच में मर जाती है। मैं Marko Gargenta's AIDLDemo example में निम्नलिखित मामूली परिवर्तन करके स्वयं को साबित करने में सक्षम था।

सबसे पहले, सुनिश्चित करें कि एंड्रॉइडमैनीफेस्ट अपडेट करके सेवा स्वयं की प्रक्रिया में चलती है।xml:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.marakana" android:versionCode="1" android:versionName="1.0"> 
    <application android:icon="@drawable/icon" android:label="@string/app_name" 
     android:theme="@android:style/Theme.Light"> 
     <activity android:name=".AIDLDemo" android:label="@string/app_name"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN" /> 
       <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
     </activity> 
     <!--ADD THE android:process TAG TO THE SERVICE--> 
     <service android:name=".AdditionService" android:process=":process2"/> 
    </application> 
    <uses-sdk android:minSdkVersion="3" /> 
</manifest> 

तो समय से पहले ही बाहर निकलने के लिए add विधि को संशोधित:

@Override 
public IBinder onBind(Intent intent) { 

    return new IAdditionService.Stub() { 
     /** 
     * Implementation of the add() method 
     */ 
     public int add(int value1, int value2) throws RemoteException { 
      Log.d(TAG, String.format("AdditionService.add(%d, %d)", value1, 
        value2)); 

      System.exit(-1); // KILL THE PROCESS BEFORE IT CAN RESPOND 

      return value1 + value2; 
     } 

    }; 
} 

logcat में आप सेवा प्रक्रिया मरने देखते हैं, गतिविधि एक DeadObjectException प्राप्त करते हैं, और अंत में सिस्टम सेवा प्रक्रिया respawn।

D/AdditionService(1379): AdditionService.add(1, 1) 
I/AndroidRuntime(1379): AndroidRuntime onExit calling exit(-1) 
D/Zygote ( 32): Process 1379 exited cleanly (255) 
I/ActivityManager( 58): Process com.marakana:process2 (pid 1379) has died. 
W/ActivityManager( 58): Scheduling restart of crashed service com.marakana/.AdditionService in 5000ms 
D/AIDLDemo(1372): onClick failed with: android.os.DeadObjectException 
W/System.err(1372): android.os.DeadObjectException 
W/System.err(1372): at android.os.BinderProxy.transact(Native Method) 
W/System.err(1372): at com.marakana.IAdditionService$Stub$Proxy.add(IAdditionService.java:95) 
W/System.err(1372): at com.marakana.AIDLDemo$1.onClick(AIDLDemo.java:81) 
W/System.err(1372): at android.view.View.performClick(View.java:2408) 
W/System.err(1372): at android.view.View$PerformClick.run(View.java:8816) 
W/System.err(1372): at android.os.Handler.handleCallback(Handler.java:587) 
W/System.err(1372): at android.os.Handler.dispatchMessage(Handler.java:92) 
W/System.err(1372): at android.os.Looper.loop(Looper.java:123) 
W/System.err(1372): at android.app.ActivityThread.main(ActivityThread.java:4627) 
W/System.err(1372): at java.lang.reflect.Method.invokeNative(Native Method) 
W/System.err(1372): at java.lang.reflect.Method.invoke(Method.java:521) 
W/System.err(1372): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 
W/System.err(1372): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 
W/System.err(1372): at dalvik.system.NativeStart.main(Native Method) 
D/AIDLDemo(1372): onServiceDisconnected() disconnected 
I/ActivityManager( 58): Start proc com.marakana:process2 for service com.marakana/.AdditionService: pid=1399 uid=10037 gids={1015} 
D/AdditionService(1399): onCreate() 
D/AIDLDemo(1372): onServiceConnected() connected 

मैं कल्पना होगा अगर आपकी सेवा एक ही प्रक्रिया अपनी गतिविधि के रूप में आप इस अपवाद को कभी नहीं देख सकता है, लेकिन उसके बाद फिर से करता है, तो उस मामले तो आप शायद AIDL साथ परेशान कर नहीं किया जाएगा थे में चल रहा था।

इसके अतिरिक्त, जैसा कि आपने पाया, एंड्रॉइड प्रक्रियाओं के बीच अपवादों को सुरंग नहीं करता है। यदि आपको किसी कॉलिंग गतिविधि पर किसी त्रुटि को संवाद करने की आवश्यकता है तो आपको अन्य माध्यमों का उपयोग करने की आवश्यकता है।

+1

हाय टिम। क्या अच्छा जवाब है! मेरी सेवा एक अलग प्रक्रिया में चल रही थी, और मैंने तनाव परीक्षण के दौरान यहां और वहां DeadObjectExceptions को देखा है। वैसे भी जब मैंने खोल का उपयोग किया और सेवा प्रक्रिया को मार दिया, जबकि एक बाध्य आवेदन चल रहा था। DeadObjectException हमेशा मेरी todo-list पर रहा है। अब जब मुझे पता है कि वे केवल रिमोटएक्सप्शन के उप-वर्ग हैं, मुझे पता है कि क्या करना है .. आपको बहुत धन्यवाद। अगर कोई और भी अंतर्दृष्टिपूर्ण होता है तो मैं एक और दिन के लिए खुला प्रश्न छोड़ देता हूं! चीयर्स, निल्स –

+0

@Nils Pipenbrinck Glad मैं मदद कर सकता था। साथ ही, अब आपने मेरा जवाब स्वीकार कर लिया है, क्या मैं आपको बक्षीस देने के लिए भी परेशान कर सकता हूं? –

+0

मुझे पता नहीं था कि आपको इसे पुराना है। मैंने सोचा कि यह उत्तर से जुड़ा हुआ है .. :-) –

1

"अपवाद अभी तक प्रक्रियाओं में समर्थित नहीं हैं" यहां कुंजी है। रिमोटएक्सप्शन वास्तव में फेंक दिया जाता है, लेकिन सीधे नहीं। हर आपकी रिमोट सेवा में अपवाद को संभालने के दौरान अपवाद कॉल किया जा रहा है जिसके परिणामस्वरूप आपके आवेदन द्वारा रिमोटएक्सप्शन प्राप्त किया जा रहा है।

5

प्रक्रिया रिमोट ऑब्जेक्ट होस्ट करने की प्रक्रिया अब उपलब्ध नहीं है, जिसका आमतौर पर प्रक्रिया क्रैश हो जाती है, तो रिमोट एक्सेप्शन फेंक दिया जाता है।

हालांकि, पिछली टिप्पणी, और आधिकारिक एंड्रॉइड दस्तावेज भी डेडऑब्जेक्ट एक्सेप्शन के बारे में गलत है जो क्लाइंट को वापस फेंक दिया गया एकमात्र अपवाद है। आपके एआईडीएल सेवा कार्यान्वयन में फेंकने वाले कुछ प्रकार के रनटाइम अपवादों को ग्राहक को वापस भेज दिया जाएगा और वहां पुनर्स्थापित किया जाएगा। यदि आप Binder.execTransact() विधि को देखते हैं, तो आप देखेंगे कि यह RuntimeException को पकड़ता है और क्लाइंट को कुछ चुनिंदा कुछ पास करता है।

रनटाइम अपवाद जो इस विशेष उपचार को प्राप्त करते हैं नीचे सूचीबद्ध हैं। आप सत्यापित करने के लिए Parcel.writeException भी देख सकते हैं। उस विधि का उपयोग बाइंडर वर्ग द्वारा पार्सल में अपवाद को मार्शल करने के लिए किया जाता है और इसे वापस क्लाइंट में स्थानांतरित कर दिया जाता है, जहां इसे पार्सल.readException के हिस्से के रूप में पुनर्स्थापित किया जाएगा।

  • SecurityException
  • BadParcelableException
  • IllegalArgumentException
  • NullPointerException
  • IllegalStateException
  • NetworkOnMainThreadException
  • UnsupportedOperationException

मैं दुर्घटना से इस व्यवहार पर ठोकर खाई, मैं क्लाइंट पक्ष पर अप्रत्याशित अपवाद देख रहा था, और जब मेरी IllegalStateException पर हो तो मेरी सेवा क्रैश नहीं हो रही थी। पूर्ण लेखन: https://blog.classycode.com/dealing-with-exceptions-in-aidl-9ba904c6d63

संबंधित मुद्दे