├── .gitignore ├── .idea ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── baronzhang │ │ └── ipc │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── baronzhang │ │ │ └── ipc │ │ │ ├── Book.java │ │ │ ├── client │ │ │ └── ClientActivity.java │ │ │ ├── proxy │ │ │ └── Proxy.java │ │ │ └── server │ │ │ ├── BookManager.java │ │ │ ├── RemoteService.java │ │ │ └── Stub.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_client.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── baronzhang │ └── ipc │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HelloBinder 2 | 3 | 推荐阅读: 4 | 5 | * [写给 Android 应用工程师的 Binder 原理剖析](https://mp.weixin.qq.com/s?__biz=MzU4ODM2MjczNA==&mid=2247483735&idx=1&sn=202bcc94cc581d91e77728afe674fdfe&chksm=fddca7d6caab2ec0c1a08e25dc1acf5aaf257365f64d5c50c37aae4ead919fdbc11062575f9f&scene=38#wechat_redirect) 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | defaultConfig { 6 | applicationId "com.baronzhang.ipc" 7 | minSdkVersion 15 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:26.1.0' 24 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.1' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 28 | } 29 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/baronzhang/ipc/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.baronzhang.ipc; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.baronzhang.ipc", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/baronzhang/ipc/Book.java: -------------------------------------------------------------------------------- 1 | package com.baronzhang.ipc; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | /** 7 | * @author baronzhang (baron[dot]zhanglei[at]gmail[dot]com) 8 | * 2017/10/17 9 | */ 10 | public class Book implements Parcelable { 11 | 12 | private int price; 13 | private String name; 14 | 15 | public int getPrice() { 16 | return price; 17 | } 18 | 19 | public void setPrice(int price) { 20 | this.price = price; 21 | } 22 | 23 | public String getName() { 24 | return name; 25 | } 26 | 27 | public void setName(String name) { 28 | this.name = name; 29 | } 30 | 31 | @Override 32 | public int describeContents() { 33 | return 0; 34 | } 35 | 36 | @Override 37 | public void writeToParcel(Parcel dest, int flags) { 38 | dest.writeInt(this.price); 39 | dest.writeString(this.name); 40 | } 41 | 42 | public Book() { 43 | } 44 | 45 | protected Book(Parcel in) { 46 | this.price = in.readInt(); 47 | this.name = in.readString(); 48 | } 49 | 50 | public static final Creator CREATOR = new Creator() { 51 | @Override 52 | public Book createFromParcel(Parcel source) { 53 | return new Book(source); 54 | } 55 | 56 | @Override 57 | public Book[] newArray(int size) { 58 | return new Book[size]; 59 | } 60 | }; 61 | 62 | @Override 63 | public String toString() { 64 | return "Book{" + 65 | "price=" + price + 66 | ", name='" + name + '\'' + 67 | '}'; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/baronzhang/ipc/client/ClientActivity.java: -------------------------------------------------------------------------------- 1 | package com.baronzhang.ipc.client; 2 | 3 | import android.content.ComponentName; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.ServiceConnection; 7 | import android.os.IBinder; 8 | import android.os.RemoteException; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.os.Bundle; 11 | import android.util.Log; 12 | import android.view.View; 13 | import android.widget.Button; 14 | 15 | import com.baronzhang.ipc.Book; 16 | import com.baronzhang.ipc.R; 17 | import com.baronzhang.ipc.server.BookManager; 18 | import com.baronzhang.ipc.server.RemoteService; 19 | import com.baronzhang.ipc.server.Stub; 20 | 21 | import java.util.List; 22 | 23 | public class ClientActivity extends AppCompatActivity { 24 | 25 | private BookManager bookManager; 26 | private boolean isConnection = false; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_client); 32 | 33 | Button btn = findViewById(R.id.btn); 34 | btn.setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View view) { 37 | if (!isConnection) { 38 | attemptToBindService(); 39 | return; 40 | } 41 | 42 | if (bookManager == null) 43 | return; 44 | 45 | try { 46 | Book book = new Book(); 47 | book.setPrice(101); 48 | book.setName("编码"); 49 | bookManager.addBook(book); 50 | 51 | Log.d("ClientActivity", bookManager.getBooks().toString()); 52 | } catch (RemoteException e) { 53 | e.printStackTrace(); 54 | } 55 | 56 | } 57 | }); 58 | } 59 | 60 | private void attemptToBindService() { 61 | 62 | Intent intent = new Intent(this, RemoteService.class); 63 | intent.setAction("com.baronzhang.ipc.server"); 64 | bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); 65 | } 66 | 67 | private ServiceConnection serviceConnection = new ServiceConnection() { 68 | @Override 69 | public void onServiceConnected(ComponentName name, IBinder service) { 70 | isConnection = true; 71 | bookManager = Stub.asInterface(service); 72 | if (bookManager != null) { 73 | try { 74 | List books = bookManager.getBooks(); 75 | Log.d("ClientActivity", books.toString()); 76 | } catch (RemoteException e) { 77 | e.printStackTrace(); 78 | } 79 | } 80 | } 81 | 82 | @Override 83 | public void onServiceDisconnected(ComponentName name) { 84 | isConnection = false; 85 | } 86 | }; 87 | 88 | @Override 89 | protected void onStart() { 90 | super.onStart(); 91 | if (!isConnection) { 92 | attemptToBindService(); 93 | } 94 | } 95 | 96 | @Override 97 | protected void onStop() { 98 | super.onStop(); 99 | if (isConnection) { 100 | unbindService(serviceConnection); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/java/com/baronzhang/ipc/proxy/Proxy.java: -------------------------------------------------------------------------------- 1 | package com.baronzhang.ipc.proxy; 2 | 3 | import android.os.IBinder; 4 | import android.os.Parcel; 5 | import android.os.RemoteException; 6 | 7 | import com.baronzhang.ipc.Book; 8 | import com.baronzhang.ipc.server.BookManager; 9 | import com.baronzhang.ipc.server.Stub; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * @author baronzhang (baron[dot]zhanglei[at]gmail[dot]com) 15 | * 05/01/2018 16 | */ 17 | public class Proxy implements BookManager { 18 | 19 | private static final String DESCRIPTOR = "com.baronzhang.ipc.server.BookManager"; 20 | 21 | private IBinder remote; 22 | 23 | public Proxy(IBinder remote) { 24 | 25 | this.remote = remote; 26 | } 27 | 28 | public String getInterfaceDescriptor() { 29 | return DESCRIPTOR; 30 | } 31 | 32 | @Override 33 | public List getBooks() throws RemoteException { 34 | Parcel data = Parcel.obtain(); 35 | Parcel replay = Parcel.obtain(); 36 | List result; 37 | 38 | try { 39 | data.writeInterfaceToken(DESCRIPTOR); 40 | remote.transact(Stub.TRANSAVTION_getBooks, data, replay, 0); 41 | replay.readException(); 42 | result = replay.createTypedArrayList(Book.CREATOR); 43 | } finally { 44 | replay.recycle(); 45 | data.recycle(); 46 | } 47 | return result; 48 | } 49 | 50 | @Override 51 | public void addBook(Book book) throws RemoteException { 52 | 53 | Parcel data = Parcel.obtain(); 54 | Parcel replay = Parcel.obtain(); 55 | 56 | try { 57 | data.writeInterfaceToken(DESCRIPTOR); 58 | if (book != null) { 59 | data.writeInt(1); 60 | book.writeToParcel(data, 0); 61 | } else { 62 | data.writeInt(0); 63 | } 64 | remote.transact(Stub.TRANSAVTION_addBook, data, replay, 0); 65 | replay.readException(); 66 | } finally { 67 | replay.recycle(); 68 | data.recycle(); 69 | } 70 | } 71 | 72 | @Override 73 | public IBinder asBinder() { 74 | return remote; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/baronzhang/ipc/server/BookManager.java: -------------------------------------------------------------------------------- 1 | package com.baronzhang.ipc.server; 2 | 3 | import android.os.IInterface; 4 | import android.os.RemoteException; 5 | 6 | import com.baronzhang.ipc.Book; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 这个类用来定义服务端 RemoteService 具备什么样的能力 12 | * 13 | * @author baronzhang (baron[dot]zhanglei[at]gmail[dot]com) 14 | * 05/01/2018 15 | */ 16 | public interface BookManager extends IInterface { 17 | 18 | List getBooks() throws RemoteException; 19 | 20 | void addBook(Book book) throws RemoteException; 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/baronzhang/ipc/server/RemoteService.java: -------------------------------------------------------------------------------- 1 | package com.baronzhang.ipc.server; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.IBinder; 6 | import android.os.RemoteException; 7 | import android.util.Log; 8 | 9 | import com.baronzhang.ipc.Book; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | public class RemoteService extends Service { 15 | 16 | private List books = new ArrayList<>(); 17 | 18 | public RemoteService() { 19 | } 20 | 21 | @Override 22 | public void onCreate() { 23 | super.onCreate(); 24 | 25 | Book book = new Book(); 26 | book.setName("三体"); 27 | book.setPrice(88); 28 | books.add(book); 29 | } 30 | 31 | @Override 32 | public IBinder onBind(Intent intent) { 33 | return bookManager; 34 | } 35 | 36 | private final Stub bookManager = new Stub() { 37 | @Override 38 | public List getBooks() throws RemoteException { 39 | synchronized (this) { 40 | if (books != null) { 41 | return books; 42 | } 43 | return new ArrayList<>(); 44 | } 45 | } 46 | 47 | @Override 48 | public void addBook(Book book) throws RemoteException { 49 | synchronized (this) { 50 | if (books == null) { 51 | books = new ArrayList<>(); 52 | } 53 | 54 | if (book == null) 55 | return; 56 | 57 | book.setPrice(book.getPrice() * 2); 58 | books.add(book); 59 | 60 | Log.e("Server", "books: " + book.toString()); 61 | } 62 | } 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/baronzhang/ipc/server/Stub.java: -------------------------------------------------------------------------------- 1 | package com.baronzhang.ipc.server; 2 | 3 | import android.os.Binder; 4 | import android.os.IBinder; 5 | import android.os.IInterface; 6 | import android.os.Parcel; 7 | import android.os.RemoteException; 8 | 9 | import com.baronzhang.ipc.Book; 10 | import com.baronzhang.ipc.proxy.Proxy; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * @author baronzhang (baron[dot]zhanglei[at]gmail[dot]com) 16 | * 05/01/2018 17 | */ 18 | public abstract class Stub extends Binder implements BookManager { 19 | 20 | private static final String DESCRIPTOR = "com.baronzhang.ipc.server.BookManager"; 21 | 22 | public Stub() { 23 | this.attachInterface(this, DESCRIPTOR); 24 | } 25 | 26 | public static BookManager asInterface(IBinder binder) { 27 | if (binder == null) 28 | return null; 29 | IInterface iin = binder.queryLocalInterface(DESCRIPTOR); 30 | if (iin != null && iin instanceof BookManager) 31 | return (BookManager) iin; 32 | return new Proxy(binder); 33 | } 34 | 35 | @Override 36 | public IBinder asBinder() { 37 | return this; 38 | } 39 | 40 | @Override 41 | protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { 42 | switch (code) { 43 | 44 | case INTERFACE_TRANSACTION: 45 | reply.writeString(DESCRIPTOR); 46 | return true; 47 | 48 | case TRANSAVTION_getBooks: 49 | data.enforceInterface(DESCRIPTOR); 50 | List result = this.getBooks(); 51 | reply.writeNoException(); 52 | reply.writeTypedList(result); 53 | return true; 54 | 55 | case TRANSAVTION_addBook: 56 | data.enforceInterface(DESCRIPTOR); 57 | Book arg0 = null; 58 | if (data.readInt() != 0) { 59 | arg0 = Book.CREATOR.createFromParcel(data); 60 | } 61 | this.addBook(arg0); 62 | reply.writeNoException(); 63 | return true; 64 | 65 | } 66 | return super.onTransact(code, data, reply, flags); 67 | } 68 | 69 | public static final int TRANSAVTION_getBooks = IBinder.FIRST_CALL_TRANSACTION; 70 | public static final int TRANSAVTION_addBook = IBinder.FIRST_CALL_TRANSACTION + 1; 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_client.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |