【问题标题】:How the same code is shared between two processes in Android?Android 中的两个进程之间如何共享相同的代码?
【发布时间】:2020-06-06 22:40:06
【问题描述】:

我的 android 项目中有一个 util 类,它看起来像这样,

public class MyUtil {
    public static final String TAG = "tim";
    static IBinder mIBinder1 = new Binder();

    public static void printHelloWorld() {
        Log.i(TAG, "Just printing hello world from my util" + mIBinder1.toString());
    }
}

我有一个服务在同一个应用程序中的单独进程 (:one) 下运行,看起来像这样,

public class MyService extends Service {

    public static final String TAG = "tim";

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
       return new IMyAidlInterface.Stub() {

           @Override
           public void printHelloWorld() throws RemoteException {
               Log.i(TAG, "This is just printing hello world");
               MyUtil.printHelloWorld();
           }
       };
    }
}

当我在应用程序(进程 p1)和服务类(进程 p1:one)的 util 类中调用 printHelloWorld() 时,我可以看到 mBinder1 对象的相同值,以便跨进程打印相同的值.

一般来说,当我们在进程之间进行通信时,我们会进行 IPC 调用。这里如何在进程之间共享 util 代码?当它们在同一个应用程序中时,如何在进程之间共享代码?

我无法理解。在这方面的一些帮助会非常有帮助。

【问题讨论】:

    标签: android process ipc aidl android-binder


    【解决方案1】:

    Binder 实例在进程之间共享。

    虽然Binder实例在MyUtil类中是静态的, 应用程序和服务进程都有自己的MyUtil 代码副本。

    因此,应用进程为其MyUtil 类创建了1 个静态对象, 并且服务进程为其MyUtil 类创建另一个静态对象。

    让我们看看它的实际效果。

    1.在单独的进程中运行服务

    这是 AndroidManifest.xml。

    <manifest
        package="com.lakindu.staticobjectbehavior">
    
        <application>
    
            <service
                android:name=".MyService"
                android:process=":myservice" />
    
        </application>
    </manifest>
    

    MyService.java

    public class MyService extends Service {
        private static final String TAG = "mytest_MyService";
    
        private final IBinder mBinder = new IMyService.Stub() {
    
            @Override
            public void printHelloWorld() throws RemoteException {
                Log.i(TAG, "This is just printing hello world");
                MyUtil.printHelloWorld();
            }
    
        };
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    }
    

    MyUtil.java

    public class MyUtil {
        private static final String TAG = "mytest_MyUtil";
    
        private static final IBinder mMyBinder = new MyBinder();
    
        public static void printHelloWorld() {
            Log.i(TAG, "Just printing hello world from my util" + mMyBinder.toString());
        }
    }
    

    MyBinder 只是一个 Binder,每次创建对象时都会记录一条消息。

    MyBinder.java

    public class MyBinder extends Binder {
        private static final String TAG = "mytest_MyBinder";
    
        public MyBinder() {
            Log.d(TAG, "Creating MyBinder object");
        }
    }
    

    为了测试,我编写了这个 Android 仪器测试。

    app/src/androidTest/StaticObjectBehaviorTest.java

    import org.junit.runner.RunWith;
    import androidx.test.ext.junit.runners.AndroidJUnit4;
    import org.junit.Rule;
    import org.junit.Test;
    import androidx.test.platform.app.InstrumentationRegistry;
    
    @RunWith(AndroidJUnit4.class)
    public class StaticObjectBehaviorTest {
    
        @Rule
        public final ServiceTestRule mServiceRule = new ServiceTestRule();
    
        @Test
        public void objectCreation() throws TimeoutException, RemoteException {
            // Context of the app under test.
            Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
    
            // Calling MyUtil class in test app process.
            MyUtil.printHelloWorld();
    
            Intent intent = new Intent(appContext, MyService.class);
            IBinder binder = mServiceRule.bindService(intent);
            assertNotNull(binder);
            IMyService myService = IMyService.Stub.asInterface(binder);
            assertNotNull(myService);
    
            // Using service proxy to call MyUtil class in service process.
            myService.printHelloWorld();
        }
    
    }
    

    检查日志。

    $ adb logcat | grep "mytest_"
    
    [PID]
    13054 D mytest_MyBinder: Creating MyBinder object
    13054 I mytest_MyUtil: Just printing hello world from my utilcom.lakindu.staticobjectbehavior.MyBinder@5c24fc2
    13089 I mytest_MyService: This is just printing hello world
    13089 D mytest_MyBinder: Creating MyBinder object
    13089 I mytest_MyUtil: Just printing hello world from my utilcom.lakindu.staticobjectbehavior.MyBinder@2723e12
    

    如您所见,每个进程都创建了 2 个 Binder 对象。

    2。在同一进程中运行服务

    只需更改 AndroidManifest.xml。

    <manifest
        package="com.lakindu.staticobjectbehavior">
    
        <application>
    
            <service
                android:name=".MyService" />
    
        </application>
    </manifest>
    

    没有代码更改。

    检查日志。

    $ adb logcat | grep "mytest_"
    
    [PID]
    13202 D mytest_MyBinder: Creating MyBinder object
    13202 I mytest_MyUtil: Just printing hello world from my utilcom.lakindu.staticobjectbehavior.MyBinder@5c24fc2
    13202 I mytest_MyService: This is just printing hello world
    13202 I mytest_MyUtil: Just printing hello world from my utilcom.lakindu.staticobjectbehavior.MyBinder@5c24fc2
    

    在同一进程中运行时,只会创建一个 Binder 实例。

    【讨论】:

    • 但是我也注意到电源管理器也是如此,PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 当我从任何进程打印 pm.toString 时,它会返回相同的值。
    • 我读到的原因是 binder 在 binder 驱动程序中分配内存(在内核级别),并且在进程之间共享相同的内存(共享内存),在 java 对象级别 toString 方法是被覆盖以提供相同的 hashCode 值。
    • 在我看来,我们正在偏离本次讨论的原始主题。最初我们讨论的是 2 个不同的进程如何在 Android 应用程序级别拥有同一个类的 2 个不同副本。但是这个问题询问不同进程之间在哪里共享相同的 Android 框架资源,以及如何共享。如果您为此 PowerManager 提问创建一个新问题,社区将能够看到您的问题并为您提供满意的答案。我认为您的问题是一个很好的问题,我将不得不对此进行研究才能为您提供答案。
    猜你喜欢
    • 2012-01-03
    • 2012-07-03
    • 1970-01-01
    • 2014-07-05
    • 2020-07-09
    • 1970-01-01
    • 2022-01-03
    • 2011-01-18
    • 1970-01-01
    相关资源
    最近更新 更多