2010-07-01 6 views
22

Android OS 용 서비스 및 활동을 작성했습니다.Android 원격 예외 및 서비스

내 서비스는 자체 프로세스로 실행되므로 내 활동과 서비스 간의 모든 통신은 IPC를 통해 이루어집니다. 나는 이것을 위해 표준 Android .aidl 메커니즘을 사용한다.

지금까지 모든 것이 잘 작동합니다. 그러나 AIDL은 "throws RemoteException"을 사용하여 모든 메소드 스텁을 생성하므로 처리해야합니다.

전체 안드로이드 소스 코드에서 빠른 grep을했고,이 예외가 던져지는 세 가지 경우 만 발견했습니다. 이것들은 내가 연결하지 않는 다른 서비스에 있습니다.

이론적으로 JNI 인터페이스를 사용하여 RemoteExceptions을 생성 할 수 있기 때문에 C 소스도 확인했습니다. 아무 것도 나타나지 않았습니다.

나는 모든 사람들이 그냥이처럼 그들을 처리하는 인상이 있습니다

try { 

    mService.someMethodCall (someArguments); 

    } catch (RemoteException e) { 

    e.printStackTrace(); 

    } 

이 고체 코드가 아닙니다, 그리고 내 코드베이스에서이 같은 것을 원하지 않는다.

그 외 : IPC 자신을 통해 RemoteException을 던지려고했는데 예외가 아직 지원되지 않는다고 말하는 스택 추적 및 시스템 로그 메시지가있었습니다. 내 응용 프로그램은 예외

:-((중간 작업) 아주 이상한 상태로 결국 예외를 던진 서비스 질문은 본 적이 :

  • 이 예외가 이제까지 던져 수행을

  • 이 (가) "는 RemoteException을 던졌습니다"때문에 우리가 그들과 거래를 강요하는 것을

  • 는 그들이 존재하지 않는 것이 될 수 있을까요? 누구도 그런 시도-catch 블록은 RemoteException을 잡기 본 사람과 AIDL 컴파일러에서 코드가 죽었거나 왼쪽에 있습니까?

Disclamer : 전체 소스 코드를 읽지 않았습니다. Grep를 사용하여 RemoteException이 발생 했으므로 다른 공백 사용으로 인해 일부를 놓친 것일 수 있습니다.

답변

49

이러한 예외는 실제로 발생하며 서비스에서 호출 한 원격 메서드가 완료되지 않은 상황을 처리하기 위해 적절한 try/catch 논리를 작성해야합니다.

귀하의 조사에서 귀하는 원산지 정보를 조사한 바 있습니다. 간과 할 수있는 것은 android.os.RemoteException이 실제로 다른 바인더 관련 예외에 대한 기본 클래스이고 서브 클래스 인 android.os.DeadObjectException이며 native code of Binder 내에 발생한다는 것입니다.

요청을 수행하는 도중 다른 프로세스에서 실행되는 서비스를 사용하는 경우 활동에서이 예외가 발생합니다. Marko Gargenta's AIDLDemo example에 다음과 같이 사소한 변경을하면이 사실을 스스로 증명할 수있었습니다.

먼저 AndroidManifest를 업데이트하여 서비스가 자체 프로세스에서 실행되는지 확인하십시오.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; 
     } 

    }; 
} 

당신은 서비스 프로세스 다이를 참조 활동은 DeadObjectException을 받고, 궁극적으로 시스템은 서비스 프로세스를 리스폰.

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로 귀찮게되지 않을 경우라면 활동과 같은 프로세스에서 실행중인 경우 내가 상상.

또한 발견 한대로 Android는 프로세스 간의 예외를 터널링하지 않습니다. 호출하는 활동에 오류를 다시 전달해야하는 경우 다른 방법을 사용해야합니다.

+1

안녕하세요. 멋진 답변입니다. 내 서비스가 다른 프로세스에서 실행 중이었고 스트레스 테스트 중에 DeadObjectExceptions이 여기 저기에서 보였습니다. 항상 바인드 된 응용 프로그램이 실행되는 동안 쉘을 사용하여 서비스 프로세스를 중단했습니다. DeadObjectException은 항상 todo-list에있었습니다. 이제는 RemoteException의 서브 클래스에 불과하다는 것을 알았으니 어떻게해야할지 알았습니다. 고맙습니다. 누군가가 더 통찰력이있는 경우에 대비하여 다른 날을 위해 질문을 공개합니다! 건배, Nils –

+0

@Nils Pipenbrinck Glad 도와 줄 수 있습니다. 또한, 당신이 나의 대답을 받아 들였기 때문에 현상금을 수여 할 수 있을까요? –

+0

나는 당신이 당신에게 그것을 수여해야한다는 것을 몰랐습니다. 나는 그것이 대답에 묶여 있다고 생각 : ..-) –

1

"예외가 아직 프로세스간에 지원되지 않습니다."가 핵심 요소입니다. RemoteException은 실제로 발생하지만 직접적으로 발생하지는 않습니다. EVERY aidl 호출이 처리되는 동안 원격 서비스에서 예외가 발생하면 응용 프로그램에서 RemoteException을 수신하게됩니다.

5

원격 개체를 호스팅하는 프로세스가 더 이상 사용 가능하지 않으면 RemoteException이 throw되며, 이는 일반적으로 프로세스가 손상되었음을 나타냅니다.

그러나 앞의 주석과 공식 Android 설명서는 DeadObjectException이 클라이언트에 던져진 유일한 예외입니다. AIDL 서비스 구현에 던져진 RuntimeExceptions의 일부 유형은 클라이언트로 다시 전달되어 다시 전달됩니다. Binder.execTransact() 메서드를 살펴보면 RuntimeException을 catch하고 일부만 다시 클라이언트로 전달한다는 것을 알 수 있습니다.

이 특수 처리를받는 RuntimeExceptions는 다음과 같습니다. 확인을 위해 Parcel.writeException을 검사 할 수도 있습니다. 이 메서드는 Binder 클래스가 예외를 Parcel로 마샬링하고 클라이언트로 다시 전송합니다.이 메서드는 Parcel.readException의 일부로 다시 throw됩니다.

  • 에 SecurityException
  • BadParcelableException
  • 는 IllegalArgumentException
  • NullPointerException이
  • IllegalStateException이
  • NetworkOnMainThreadException
  • UnsupportedOperationException를
,

우발적 인 사고로 우연히 마주 쳤습니다. 클라이언트 측에서 예기치 않은 예외가 발생하여 IllegalStateException이 발생하면 서비스가 중단되지 않았습니다. 전체 기사 작성 : https://blog.classycode.com/dealing-with-exceptions-in-aidl-9ba904c6d63