1/*
2 * Copyright (C) 2016 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 */
16package com.android.car.vehiclemonitor;
17
18import android.annotation.IntDef;
19import android.os.Handler;
20import android.os.Looper;
21import android.os.Message;
22import android.os.RemoteException;
23import android.os.ServiceManager;
24import android.os.ServiceSpecificException;
25
26import java.lang.annotation.Retention;
27import java.lang.annotation.RetentionPolicy;
28import java.lang.ref.WeakReference;
29
30/**
31 * System API to access Vehicle monitor. This is only for system services and applications should
32 * not use this. All APIs will fail with security error if normal app tries this.
33 */
34public class VehicleMonitor {
35    private static final String TAG = VehicleMonitor.class.getSimpleName();
36
37    private final IVehicleMonitor mService;
38    private final VehicleMonitorListener mListener;
39    private final IVehicleMonitorListenerImpl mVehicleMonitorListener;
40    private final EventHandler mEventHandler;
41
42    private static final int VMS_CONNECT_MAX_RETRY = 10;
43    private static final long VMS_RETRY_WAIT_TIME_MS = 1000;
44
45    /**
46     * Application priorities used in vehicle monitoring.
47     */
48    @Retention(RetentionPolicy.SOURCE)
49    @IntDef({
50            ApplicationPriority.NONE,
51            ApplicationPriority.FOREGROUND
52    })
53    public @interface ApplicationPriority {
54        int NONE = 0;
55        int FOREGROUND = 1;
56    }
57
58    /**
59     * Listener for VMS events.
60     */
61    public interface VehicleMonitorListener {
62        void onAppViolation(int pid, int uid, int action, int violation);
63    }
64
65    /**
66     * Factory method to create VehicleMonitor
67     */
68    public static VehicleMonitor createVehicleMonitor(
69            VehicleMonitorListener listener, Looper looper) {
70        int retryCount = 0;
71        IVehicleMonitor service = null;
72        while (true) {
73            service = IVehicleMonitor.Stub.asInterface(
74                    ServiceManager.getService(IVehicleMonitor.class.getCanonicalName()));
75            if (service != null) {
76                break;
77            }
78            retryCount++;
79            if (retryCount > VMS_CONNECT_MAX_RETRY) {
80                break;
81            }
82            try {
83                Thread.sleep(VMS_RETRY_WAIT_TIME_MS);
84            } catch (InterruptedException e) {
85                //ignore
86            }
87        }
88        if (service == null) {
89            throw new RuntimeException("Vehicle monitor service not available:"
90                    + IVehicleMonitor.class.getCanonicalName());
91        }
92        return new VehicleMonitor(service, listener, looper);
93    }
94
95    private VehicleMonitor(
96            IVehicleMonitor service, VehicleMonitorListener listener, Looper looper) {
97        mService = service;
98        mListener = listener;
99        mEventHandler = new EventHandler(looper);
100        mVehicleMonitorListener = new IVehicleMonitorListenerImpl(this);
101        try {
102            mService.setMonitorListener(mVehicleMonitorListener);
103        } catch (RemoteException e) {
104            throw new RuntimeException("Vehicle monitor service not working ", e);
105        }
106    }
107
108    /**
109     * Set application priority.
110     * <p>
111     * This will lead into writing application priority into vehicle monitor.
112     */
113    public void setAppPriority(int pid, int uid, @ApplicationPriority int priority)
114            throws ServiceSpecificException {
115        try {
116            mService.setAppPriority(pid, uid, priority);
117        } catch (RemoteException e) {
118            throw new RuntimeException("Vehicle monitor service not working ", e);
119        }
120    }
121
122    private void handleVehicleMonitorAppViolation(AppViolation appViolation) {
123        mListener.onAppViolation(appViolation.mPid, appViolation.mUid, appViolation.mAction,
124                appViolation.mViolation);
125    }
126
127    private class EventHandler extends Handler {
128
129        private static final int MSG_APP_VIOLATION = 0;
130
131        private EventHandler(Looper looper) {
132            super(looper);
133        }
134
135        private void notifyAppViolation(int pid, int uid, int action, int violation) {
136            AppViolation appViolation = new AppViolation(pid, uid, action, violation);
137            Message msg = obtainMessage(MSG_APP_VIOLATION, appViolation);
138            sendMessage(msg);
139        }
140
141        @Override
142        public void handleMessage(Message msg) {
143            switch (msg.what) {
144                case MSG_APP_VIOLATION:
145                    AppViolation appViolation = (AppViolation) msg.obj;
146                    handleVehicleMonitorAppViolation(appViolation);
147                    break;
148            }
149        }
150    }
151
152    private static class IVehicleMonitorListenerImpl extends IVehicleMonitorListener.Stub {
153
154        private final WeakReference<VehicleMonitor> mVehicleMonitor;
155
156        private IVehicleMonitorListenerImpl(VehicleMonitor vehicleNewotk) {
157            mVehicleMonitor = new WeakReference<>(vehicleNewotk);
158        }
159
160        @Override
161        public void onAppViolation(int pid, int uid, int action, int violation) {
162            VehicleMonitor vehicleMonitor = mVehicleMonitor.get();
163            if (vehicleMonitor != null) {
164                vehicleMonitor.mEventHandler.notifyAppViolation(pid, uid, action, violation);
165            }
166        }
167    }
168
169    private static class AppViolation {
170        public final int mPid;
171        public final int mUid;
172        public final int mAction;
173        public final int mViolation;
174
175        AppViolation(int pid, int uid, int action, int violation) {
176            mPid = pid;
177            mUid = uid;
178            mAction = action;
179            mViolation = violation;
180        }
181    }
182}
183