104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov/*
204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov * Copyright (C) 2016 The Android Open Source Project
304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov *
404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov * you may not use this file except in compliance with the License.
604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov * You may obtain a copy of the License at
704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov *
804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov *
1004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software
1104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
1204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov * See the License for the specific language governing permissions and
1404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov * limitations under the License.
1504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov */
1604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
1704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovpackage android.util;
1804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
1904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport android.content.ComponentName;
2004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport android.content.Context;
2104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport android.content.Intent;
2204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport android.content.ServiceConnection;
2304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport android.os.Build;
2404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport android.os.IBinder;
2504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport android.os.RemoteException;
2604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport android.os.SystemClock;
2704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport android.support.test.InstrumentationRegistry;
2804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
2904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport java.io.Closeable;
3004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport java.io.IOException;
3104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovimport java.util.concurrent.TimeoutException;
3204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
3304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganovfinal class RemoteIntArray implements ServiceConnection, Closeable {
3404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    private static final long BIND_REMOTE_SERVICE_TIMEOUT =
3504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            ("eng".equals(Build.TYPE)) ? 120000 : 10000;
3604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
3704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    private final Object mLock = new Object();
3804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
3904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    private final Intent mIntent = new Intent();
4004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
4104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    private android.util.IRemoteMemoryIntArray mRemoteInstance;
4204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
4374c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov    public RemoteIntArray(int size) throws IOException, TimeoutException {
4404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        mIntent.setComponent(new ComponentName(InstrumentationRegistry.getContext(),
4504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov                RemoteMemoryIntArrayService.class));
4604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        synchronized (mLock) {
4704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            if (mRemoteInstance == null) {
4804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov                bindLocked();
4904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            }
5004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            try {
5174c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov                mRemoteInstance.create(size);
5204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            } catch (RemoteException e) {
5304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov                throw new IOException(e);
5404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            }
5504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
5604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
5704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
5804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public MemoryIntArray peekInstance() {
5904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        try {
6004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            return mRemoteInstance.peekInstance();
6104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        } catch (RemoteException e) {
6204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            throw new RuntimeException(e);
6304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
6404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
6504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
6604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public boolean isWritable() {
6704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        try {
6804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            return mRemoteInstance.isWritable();
6904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        } catch (RemoteException e) {
7004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            throw new RuntimeException(e);
7104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
7204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
7304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
7404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public int get(int index) throws IOException {
7504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        try {
7604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            return mRemoteInstance.get(index);
7704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        } catch (RemoteException e) {
7804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            throw new IOException(e);
7904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
8004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
8104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
8204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public void set(int index, int value) throws IOException {
8304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        try {
8404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            mRemoteInstance.set(index, value);
8504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        } catch (RemoteException e) {
8604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            throw new IOException(e);
8704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
8804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
8904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
9004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public int size() throws IOException {
9104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        try {
9204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            return mRemoteInstance.size();
9304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        } catch (RemoteException e) {
9404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            throw new IOException(e);
9504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
9604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
9704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
9804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public void close() {
9904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        try {
10004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            mRemoteInstance.close();
10104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        } catch (RemoteException e) {
10204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            throw new RuntimeException(e);
10304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
10404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
10504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
10604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public boolean isClosed() {
10704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        try {
10804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            return mRemoteInstance.isClosed();
10904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        } catch (RemoteException e) {
11004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            throw new RuntimeException(e);
11104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
11204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
11304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
11404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    private void bindLocked() throws TimeoutException {
11504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        if (mRemoteInstance != null) {
11604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            return;
11704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
11804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
11904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        InstrumentationRegistry.getContext().bindService(mIntent, this, Context.BIND_AUTO_CREATE);
12004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
12104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        final long startMillis = SystemClock.uptimeMillis();
12204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        while (true) {
12304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            if (mRemoteInstance != null) {
12404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov                break;
12504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            }
12604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
12704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            final long remainingMillis = BIND_REMOTE_SERVICE_TIMEOUT - elapsedMillis;
12804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            if (remainingMillis <= 0) {
12904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov                throw new TimeoutException("Cannot get spooler!");
13004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            }
13104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            try {
13204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov                mLock.wait(remainingMillis);
13304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            } catch (InterruptedException ie) {
13404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov                    /* ignore */
13504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            }
13604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
13704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
13804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        mLock.notifyAll();
13904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
14004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
14104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public void destroy() {
14204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        synchronized (mLock) {
14304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            if (mRemoteInstance == null) {
14404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov                return;
14504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            }
14604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            mRemoteInstance = null;
14704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            InstrumentationRegistry.getContext().unbindService(this);
14804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
14904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
15004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
15174c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov    public void accessLastElementInRemoteProcess(MemoryIntArray array) {
15274c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov        try {
15374c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov            mRemoteInstance.accessLastElementInRemoteProcess(array);
15474c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov        } catch (RemoteException e) {
15574c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov            throw new RuntimeException(e);
15674c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov        }
15774c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov    }
15874c9983e80d8224bbe1de7c37e8f6ac4a76df11dSvetoslav Ganov
15904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    @Override
16004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public void onServiceConnected(ComponentName name, IBinder service) {
16104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        synchronized (mLock) {
16204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            mRemoteInstance = android.util.IRemoteMemoryIntArray.Stub.asInterface(service);
16304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            mLock.notifyAll();
16404df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
16504df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
16604df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov
16704df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    @Override
16804df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    public void onServiceDisconnected(ComponentName name) {
16904df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        synchronized (mLock) {
17004df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov            mRemoteInstance = null;
17104df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov        }
17204df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov    }
17304df738bcb6584dd82b731a67f4cf8d6925b061eSvetoslav Ganov}