1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.os.Build; 21 import android.os.IBinder; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.util.Slog; 25 26 import libcore.util.NativeAllocationRegistry; 27 28 /** 29 * An input channel specifies the file descriptors used to send input events to 30 * a window in another process. It is Parcelable so that it can be sent 31 * to the process that is to receive events. Only one thread should be reading 32 * from an InputChannel at a time. 33 * @hide 34 */ 35 public final class InputChannel implements Parcelable { 36 private static final String TAG = "InputChannel"; 37 38 private static final boolean DEBUG = false; 39 private static final NativeAllocationRegistry sRegistry = 40 NativeAllocationRegistry.createMalloced( 41 InputChannel.class.getClassLoader(), 42 nativeGetFinalizer()); 43 44 @UnsupportedAppUsage 45 public static final @android.annotation.NonNull Parcelable.Creator<InputChannel> CREATOR 46 = new Parcelable.Creator<InputChannel>() { 47 public InputChannel createFromParcel(Parcel source) { 48 InputChannel result = new InputChannel(); 49 result.readFromParcel(source); 50 return result; 51 } 52 53 public InputChannel[] newArray(int size) { 54 return new InputChannel[size]; 55 } 56 }; 57 58 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 59 private long mPtr; // used by native code 60 nativeOpenInputChannelPair(String name)61 private static native long[] nativeOpenInputChannelPair(String name); 62 nativeGetFinalizer()63 private static native long nativeGetFinalizer(); nativeDispose(long channel)64 private native void nativeDispose(long channel); nativeReadFromParcel(Parcel parcel)65 private native long nativeReadFromParcel(Parcel parcel); nativeWriteToParcel(Parcel parcel, long channel)66 private native void nativeWriteToParcel(Parcel parcel, long channel); nativeDup(long channel)67 private native long nativeDup(long channel); nativeGetToken(long channel)68 private native IBinder nativeGetToken(long channel); 69 nativeGetName(long channel)70 private native String nativeGetName(long channel); 71 72 /** 73 * Creates an uninitialized input channel. 74 * It can be initialized by reading from a Parcel or by transferring the state of 75 * another input channel into this one. 76 */ 77 @UnsupportedAppUsage InputChannel()78 public InputChannel() { 79 } 80 81 /** 82 * Set Native input channel object from native space. 83 * @param nativeChannel the native channel object. 84 * 85 * @hide 86 */ setNativeInputChannel(long nativeChannel)87 private void setNativeInputChannel(long nativeChannel) { 88 if (nativeChannel == 0) { 89 throw new IllegalArgumentException("Attempting to set native input channel to null."); 90 } 91 if (mPtr != 0) { 92 throw new IllegalArgumentException("Already has native input channel."); 93 } 94 if (DEBUG) { 95 Slog.d(TAG, "setNativeInputChannel : " + String.format("%x", nativeChannel)); 96 } 97 sRegistry.registerNativeAllocation(this, nativeChannel); 98 mPtr = nativeChannel; 99 } 100 101 /** 102 * Creates a new input channel pair. One channel should be provided to the input 103 * dispatcher and the other to the application's input queue. 104 * @param name The descriptive (non-unique) name of the channel pair. 105 * @return A pair of input channels. The first channel is designated as the 106 * server channel and should be used to publish input events. The second channel 107 * is designated as the client channel and should be used to consume input events. 108 */ openInputChannelPair(String name)109 public static InputChannel[] openInputChannelPair(String name) { 110 if (name == null) { 111 throw new IllegalArgumentException("name must not be null"); 112 } 113 114 if (DEBUG) { 115 Slog.d(TAG, "Opening input channel pair '" + name + "'"); 116 } 117 InputChannel channels[] = new InputChannel[2]; 118 long[] nativeChannels = nativeOpenInputChannelPair(name); 119 for (int i = 0; i< 2; i++) { 120 channels[i] = new InputChannel(); 121 channels[i].setNativeInputChannel(nativeChannels[i]); 122 } 123 return channels; 124 } 125 126 /** 127 * Gets the name of the input channel. 128 * @return The input channel name. 129 */ getName()130 public String getName() { 131 String name = nativeGetName(mPtr); 132 return name != null ? name : "uninitialized"; 133 } 134 135 /** 136 * Disposes the input channel. 137 * Explicitly releases the reference this object is holding on the input channel. 138 * When all references are released, the input channel will be closed. 139 */ dispose()140 public void dispose() { 141 nativeDispose(mPtr); 142 } 143 144 /** 145 * Release the Java objects hold over the native InputChannel. If other references 146 * still exist in native-land, then the channel may continue to exist. 147 */ release()148 public void release() { 149 } 150 151 /** 152 * Creates a copy of this instance to the outParameter. This is used to pass an input channel 153 * as an out parameter in a binder call. 154 * @param other The other input channel instance. 155 */ copyTo(InputChannel outParameter)156 public void copyTo(InputChannel outParameter) { 157 if (outParameter == null) { 158 throw new IllegalArgumentException("outParameter must not be null"); 159 } 160 if (outParameter.mPtr != 0) { 161 throw new IllegalArgumentException("Other object already has a native input channel."); 162 } 163 outParameter.setNativeInputChannel(nativeDup(mPtr)); 164 } 165 166 /** 167 * Duplicates the input channel. 168 */ dup()169 public InputChannel dup() { 170 InputChannel target = new InputChannel(); 171 target.setNativeInputChannel(nativeDup(mPtr)); 172 return target; 173 } 174 175 @Override describeContents()176 public int describeContents() { 177 return Parcelable.CONTENTS_FILE_DESCRIPTOR; 178 } 179 readFromParcel(Parcel in)180 public void readFromParcel(Parcel in) { 181 if (in == null) { 182 throw new IllegalArgumentException("in must not be null"); 183 } 184 long nativeIn = nativeReadFromParcel(in); 185 if (nativeIn != 0) { 186 setNativeInputChannel(nativeIn); 187 } 188 } 189 190 @Override writeToParcel(Parcel out, int flags)191 public void writeToParcel(Parcel out, int flags) { 192 if (out == null) { 193 throw new IllegalArgumentException("out must not be null"); 194 } 195 196 nativeWriteToParcel(out, mPtr); 197 198 if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0) { 199 dispose(); 200 } 201 } 202 203 @Override toString()204 public String toString() { 205 return getName(); 206 } 207 getToken()208 public IBinder getToken() { 209 return nativeGetToken(mPtr); 210 } 211 } 212