1 /* 2 * Copyright (C) 2022 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 com.android.car.provision; 18 19 import android.app.Service; 20 import android.content.Intent; 21 import android.os.Binder; 22 import android.os.Handler; 23 import android.os.IBinder; 24 import android.os.Looper; 25 import android.os.Parcel; 26 import android.os.RemoteException; 27 import android.util.Log; 28 29 import com.android.internal.annotations.GuardedBy; 30 31 /** 32 * Default implementing UserNoticeUI. There will not be any UI shown but only message in logcat. 33 */ 34 public final class UserNoticeUiService extends Service { 35 36 private static final String TAG = UserNoticeUiService.class.getSimpleName(); 37 38 private static final String IUSER_NOTICE_BINDER_DESCRIPTOR = "android.car.user.IUserNotice"; 39 private static final int IUSER_NOTICE_TR_ON_LOGGED = 40 android.os.IBinder.FIRST_CALL_TRANSACTION; 41 42 private static final String IUSER_NOTICE_UI_BINDER_DESCRIPTOR = 43 "android.car.user.IUserNoticeUI"; 44 private static final int IUSER_NOTICE_UI_BINDER_TR_SET_CALLBACK = 45 android.os.IBinder.FIRST_CALL_TRANSACTION; 46 47 private final Handler mMainHandler = new Handler(Looper.getMainLooper()); 48 49 private final Object mLock = new Object(); 50 51 // Do not use IUserNoticeUI class intentionally to show how it can be 52 // implemented without accessing the hidden API. 53 private final IBinder mIUserNoticeUiBinder = new Binder() { 54 @Override 55 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) 56 throws RemoteException { 57 switch (code) { 58 case IUSER_NOTICE_UI_BINDER_TR_SET_CALLBACK: 59 Log.d(TAG, "onTransact, received call to set callBack"); 60 data.enforceInterface(IUSER_NOTICE_UI_BINDER_DESCRIPTOR); 61 IBinder binder = data.readStrongBinder(); 62 onSetCallbackBinder(binder); 63 return true; 64 default: 65 return super.onTransact(code, data, reply, flags); 66 } 67 } 68 }; 69 70 @GuardedBy("mLock") 71 private IBinder mIUserNoticeService; 72 73 @Override onBind(Intent intent)74 public IBinder onBind(Intent intent) { 75 return mIUserNoticeUiBinder; 76 } 77 onSetCallbackBinder(IBinder binder)78 private void onSetCallbackBinder(IBinder binder) { 79 if (binder == null) { 80 Log.wtf(TAG, "No binder set in onSetCallbackBinder call", new RuntimeException()); 81 return; 82 } 83 mMainHandler.post(() -> { 84 synchronized (mLock) { 85 mIUserNoticeService = binder; 86 } 87 showMessage(); 88 stopService(); 89 }); 90 } 91 showMessage()92 private void showMessage() { 93 Log.i(TAG, "showing user notice for user: " + getUserId()); 94 } 95 stopService()96 private void stopService() { 97 IBinder userNotice; 98 synchronized (mLock) { 99 userNotice = mIUserNoticeService; 100 mIUserNoticeService = null; 101 } 102 if (userNotice != null) { 103 sendOnLoggedToCarService(userNotice); 104 } 105 stopSelf(); 106 } 107 sendOnLoggedToCarService(IBinder userNotice)108 private void sendOnLoggedToCarService(IBinder userNotice) { 109 Parcel data = Parcel.obtain(); 110 data.writeInterfaceToken(IUSER_NOTICE_BINDER_DESCRIPTOR); 111 try { 112 userNotice.transact(IUSER_NOTICE_TR_ON_LOGGED, data, null, 0); 113 } catch (RemoteException e) { 114 Log.w(TAG, "CarService crashed, finish now"); 115 stopSelf(); 116 } 117 } 118 } 119