-Authors of GNU Hello.
-
- Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc.
-
- Copying and distribution of this file, with or without modification,
- are permitted in any medium without royalty provided the copyright
- notice and this notice are preserved.
-
-The following contributions warranted legal paper exchanges with the
-Free Software Foundation. See also the ChangeLog and THANKS files.
-
-Mike Haertel
-David MacKenzie
-Jan Brittenson
-Roland McGrath
-Charles Hannum
-Bruce Korb hello.c, configure.ac.
-Karl Eichwalder all files.
-Karl Berry all files.
-The King releases.
+Jayoun Lee <airjany@samsung.com>
+Sewook Park <sewook7.park@samsung.com>
+Jaeho Lee <jaeho81.lee@samsung.com>
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
+
+PROJECT(amd C)
+AUX_SOURCE_DIRECTORY(src SOURCES)
+
+ADD_DEFINITIONS("-DSHARE_PREFIX=\"${SHARE_INSTALL_PREFIX}/aul\"")
+IF(with_wayland)
+ ADD_DEFINITIONS("-DWAYLAND")
+ENDIF(with_wayland)
+IF(with_x11)
+ ADD_DEFINITIONS("-DX11")
+ENDIF(with_x11)
+
+IF(_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP)
+ ADD_DEFINITIONS("-DTIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP")
+ENDIF(_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP)
+IF(_TIZEN_FEATURE_BLOCK_INPUT)
+ ADD_DEFINITIONS("-DTIZEN_FEATURE_BLOCK_INPUT")
+ENDIF(_TIZEN_FEATURE_BLOCK_INPUT)
+IF(_TIZEN_FEATURE_AUTO_ROTATION)
+ ADD_DEFINITIONS("-DTIZEN_FEATURE_AUTO_ROTATION")
+ENDIF(_TIZEN_FEATURE_AUTO_ROTATION)
+
+# Set required packages
+INCLUDE(FindPkgConfig)
+
+SET(AMD_PKG_CHECK_MODULES dlog rua aul glib-2.0 gio-2.0 vconf pkgmgr-info pkgmgr bundle libsystemd-daemon cynara-client cynara-creds-socket cynara-session cert-svc-vcore libtzplatform-config xkbcommon sensor security-manager ttrace app2sd capi-system-info)
+IF (with_wayland)
+ pkg_check_modules(pkgs REQUIRED ${AMD_PKG_CHECK_MODULES} wayland-client tizen-extension-client wayland-tbm-client tizen-launch-client)
+ENDIF(with_wayland)
+IF(with_x11)
+ pkg_check_modules(pkgs REQUIRED ${AMD_PKG_CHECK_MODULES} )
+ENDIF(with_x11)
+
+FOREACH(flag ${pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/inc)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpic")
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS_RELEASE "-O2")
+SET(CMAKE_SKIP_BUILD_RPATH true)
+# Linker flags
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed")
+
+ADD_EXECUTABLE(amd ${SOURCES})
+SET_TARGET_PROPERTIES(amd PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS} -fPIE")
+TARGET_LINK_LIBRARIES(amd ${pkgs_LDFLAGS} "-pie")
+INSTALL(TARGETS amd DESTINATION bin)
+
+
--- /dev/null
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AMD_APP_COM_H__
+#define __AMD_APP_COM_H__
+
+#include <stdbool.h>
+
+int _app_com_broker_init(void);
+int _app_com_broker_fini(void);
+int _app_com_client_remove(int cpid);
+int _app_com_add_endpoint(const char *endpoint, unsigned int propagate,
+ const char *assoc_priv);
+int _app_com_remove_endpoint(const char *endpoint);
+int _app_com_join(const char *endpoint, int cpid, const char *filter,
+ uid_t uid);
+int _app_com_send(const char *endpoint, int cpid, bundle *envelope, uid_t uid);
+int _app_com_leave(const char *endpoint, int cpid);
+const char *_app_com_get_privilege(const char *endpoint);
+bool _app_com_endpoint_exists(const char *endpoint);
+
+#endif /* __AMD_APP_COM_H__ */
+
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <bundle.h>
+
+typedef enum {
+ APP_GROUP_LAUNCH_MODE_SINGLE = 0,
+ APP_GROUP_LAUNCH_MODE_GROUP,
+ APP_GROUP_LAUNCH_MODE_CALLER,
+ APP_GROUP_LAUNCH_MODE_SINGLETON,
+} app_group_launch_mode;
+
+void _app_group_remove(int pid);
+int _app_group_get_window(int pid);
+int _app_group_set_window(int pid, int wid);
+void _app_group_get_leader_pids(int *cnt, int **pids);
+void _app_group_get_group_pids(int leader_pid, int *cnt, int **pids);
+bool _app_group_is_leader_pid(int pid);
+bool _app_group_is_group_app(bundle *kb, uid_t uid);
+bool _app_group_is_sub_app(int pid);
+void _app_group_reroute(int pid);
+void _app_group_clear_top(int pid, uid_t uid);
+int _app_group_get_leader_pid(int pid);
+void _app_group_set_dead_pid(int pid);
+int _app_group_get_status(int pid);
+int _app_group_set_status(int pid, int status, bool force);
+int _app_group_get_fg_flag(int pid);
+int _app_group_set_hint(int pid, bundle *kb);
+int _app_group_find_second_leader(int lpid);
+void _app_group_remove_leader_pid(int lpid);
+int _app_group_can_start_app(const char *appid, bundle *b, bool *can_attach,
+ int *lpid, app_group_launch_mode *mode, uid_t uid);
+void _app_group_start_app(int pid, bundle *b, int lpid, bool can_attach,
+ app_group_launch_mode mode);
+int _app_group_find_singleton(const char *appid, int *found_pid,
+ int *found_lpid);
+int _app_group_can_reroute(int pid);
+void _app_group_lower(int pid, int *exit);
+void _app_group_restart_app(int pid, bundle *b);
+int _app_group_find_pid_from_recycle_bin(const char *appid);
+void _app_group_get_idle_pids(int *cnt, int **pids);
+void _app_group_remove_from_recycle_bin(int pid);
+int _app_group_get_next_caller_pid(int pid);
+int _app_group_activate_below(int pid, const char *below_appid);
+int _app_group_activate_above(int pid, const char *above_appid);
+int _app_group_attach(const char *parent_appid, const char *child_appid,
+ uid_t uid);
+int _app_group_detach(const char *child_appid, uid_t uid);
+int _app_group_init(void);
+void _app_group_fini(void);
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <glib.h>
+
+#define METADATA_LARGEMEMORY "http://tizen.org/metadata/largememory"
+#define METADATA_OOMTERMINATION "http://tizen.org/metadata/oomtermination"
+
+typedef struct app_property_s *app_property_h;
+
+int _app_property_add_alias_info(app_property_h app_property,
+ const char *alias_appid, const char *appid);
+int _app_property_remove_alias_info(app_property_h app_property,
+ const char *alias_appid, const char *appid);
+const char *_app_property_get_real_appid(app_property_h app_property,
+ const char *alias_appid);
+GList *_app_property_get_allowed_app_list(app_property_h app_property,
+ const char *appid);
+app_property_h _app_property_find(uid_t uid);
+int _app_property_insert(uid_t uid, const char *appid);
+int _app_property_delete(uid_t uid, const char *appid);
+int _app_property_load(uid_t uid);
+void _app_property_unload(uid_t uid);
+int _app_property_init(void);
+void _app_property_fini(void);
+void _app_property_cache_put(app_property_h app_property, const char *checksum, const char *appid);
+const char *_app_property_cache_get(app_property_h app_property, const char *checksum);
+void _app_property_cache_invalidate(app_property_h app_property);
+bool _app_property_metadata_query_bool(app_property_h app_property, const char *appid, const char *key);
+int _app_property_metadata_foreach(app_property_h app_property, const char *appid,
+ const char *key, int (*callback)(const char *value, void *data), void *user_data);
+bool _app_property_metadata_match(app_property_h app_property, const char *appid,
+ const char *key, const char *value);
+bool _app_property_metadata_query_activation(app_property_h app_property, const char *appid, const char *key);
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <stdbool.h>
+#include <security-manager.h>
+
+#include "amd_appinfo.h"
+
+typedef enum {
+ AT_SERVICE_APP,
+ AT_UI_APP,
+ AT_WIDGET_APP,
+ AT_WATCH_APP,
+} app_type_e;
+
+typedef struct _shared_info_t {
+ char *owner_appid;
+ private_sharing_req *handle;
+} shared_info_t;
+
+typedef struct app_status_s *app_status_h;
+
+void _app_status_send_fault_dead_for_update_app(const char *pkgid);
+void _app_status_send_fault_dead_for_oom_apps(void);
+void _app_status_fault_recovery(int pid, int uid, const char *pkgid,
+ const char *appid, int type, bool is_exit_notified);
+int _app_status_set_is_exit_notified(app_status_h app_status, bool is_exit_notified);
+bool _app_status_get_is_exit_notified(app_status_h app_status);
+int _app_status_add_app_info(const struct appinfo *ai, int pid,
+ bool is_subapp, uid_t uid, int caller_pid,
+ bool bg_launch, const char *instance_id,
+ bool debug_mode);
+int _app_status_remove_all_app_info_with_uid(uid_t uid);
+int _app_status_remove(app_status_h app_status);
+int _app_status_update_status(app_status_h app_status, int status, bool force,
+ bool update_group_info);
+int _app_status_update_last_caller_pid(app_status_h app_status, int caller_pid);
+int _app_status_update_bg_launch(app_status_h app_status, bool bg_launch);
+int _app_status_get_process_cnt(const char *appid);
+bool _app_status_is_home_app(app_status_h app_status);
+int _app_status_get_pid(app_status_h app_status);
+int _app_status_get_last_caller_pid(app_status_h app_status);
+int _app_status_is_running(app_status_h app_status);
+int _app_status_get_status(app_status_h app_status);
+uid_t _app_status_get_uid(app_status_h app_status);
+const char *_app_status_get_appid(app_status_h app_status);
+const char *_app_status_get_pkgid(app_status_h app_status);
+bool _app_status_get_bg_launch(app_status_h app_status);
+const char *_app_status_get_instance_id(app_status_h app_stauts);
+int _app_status_get_app_type(app_status_h app_status);
+int _app_status_add_shared_info(app_status_h app_status, shared_info_t *info);
+int _app_status_clear_shared_info_list(app_status_h stat);
+GList *_app_status_get_shared_info_list(app_status_h stat);
+bool _app_status_socket_exists(app_status_h app_status);
+bool _app_status_is_starting(app_status_h app_status);
+int _app_status_update_is_starting(app_status_h app_status, bool is_starting);
+const char *_app_status_get_app_path(app_status_h app_status);
+app_status_h _app_status_find(int pid);
+app_status_h _app_status_find_v2(int pid);
+app_status_h _app_status_find_by_appid(const char *appid, uid_t uid);
+app_status_h _app_status_find_by_appid_v2(const char *appid, uid_t uid);
+app_status_h _app_status_find_with_org_caller(const char *appid, uid_t uid,
+ int caller_pid);
+app_status_h _app_status_find_by_instance_id(const char *appid,
+ const char *instance_id, uid_t uid);
+void _app_status_find_service_apps(app_status_h app_status, int status,
+ void (*send_event_to_svc_core)(int, uid_t), bool suspend);
+void _app_status_check_service_only(app_status_h app_status,
+ void (*send_event_to_svc_core)(int, uid_t));
+int _app_status_send_running_appinfo(int fd, int cmd, uid_t uid);
+int _app_status_foreach_running_appinfo(void (*callback)(app_status_h, void *),
+ void *data);
+int _app_status_terminate_apps(const char *appid, uid_t uid);
+int _app_status_terminate_apps_by_pkgid(const char *pkgid, uid_t uid);
+int _app_status_get_appid_bypid(int fd, int pid);
+int _app_status_get_pkgid_bypid(int fd, int pid);
+int _app_status_get_instance_id_bypid(int fd, int pid);
+int _app_status_get_org_caller_pid(app_status_h app_status);
+int _app_status_publish_status(int pid, int context_status);
+void _app_status_cleanup(app_status_h app_status);
+int _app_status_usr_init(uid_t uid);
+void _app_status_usr_fini(uid_t uid);
+int _app_status_init(void);
+int _app_status_finish(void);
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include <glib.h>
+#include <stdbool.h>
+
+#define AIT_START 0
+enum appinfo_type {
+ AIT_NAME = AIT_START,
+ AIT_EXEC,
+ AIT_PKGTYPE,
+ AIT_ONBOOT, /* start on boot: boolean */
+ AIT_RESTART, /* auto restart: boolean */
+ AIT_MULTI,
+ AIT_HWACC,
+ AIT_PERM,
+ AIT_PKGID,
+ AIT_PRELOAD,
+ AIT_STATUS,
+ AIT_POOL,
+ AIT_COMPTYPE,
+ AIT_TEP,
+ AIT_MOUNTABLE_PKG,
+ AIT_STORAGE_TYPE,
+ AIT_BG_CATEGORY,
+ AIT_LAUNCH_MODE,
+ AIT_GLOBAL,
+ AIT_EFFECTIVE_APPID,
+ AIT_TASKMANAGE,
+ AIT_VISIBILITY,
+ AIT_APPTYPE,
+ AIT_ROOT_PATH,
+ AIT_SPLASH_SCREEN,
+ AIT_SPLASH_SCREEN_DISPLAY,
+ AIT_API_VERSION,
+ AIT_ENABLEMENT,
+ AIT_COOLDOWN,
+ AIT_SYSTEM,
+ AIT_MAX
+};
+
+struct appinfo {
+ char *val[AIT_MAX];
+};
+
+struct appinfo_splash_screen {
+ GHashTable *portrait;
+ GHashTable *landscape;
+};
+
+struct appinfo_splash_image {
+ char *src;
+ char *type;
+ char *indicatordisplay;
+ char *color_depth;
+};
+
+#define APP_TYPE_SERVICE "svcapp"
+#define APP_TYPE_UI "uiapp"
+#define APP_TYPE_WIDGET "widgetapp"
+#define APP_TYPE_WATCH "watchapp"
+
+#define APP_ENABLEMENT_MASK_ACTIVE 0x1
+#define APP_ENABLEMENT_MASK_REQUEST 0x2
+
+typedef void (*appinfo_iter_callback)(void *user_data,
+ const char *filename, struct appinfo *c);
+int _appinfo_init(void);
+void _appinfo_fini(void);
+int _appinfo_insert(uid_t uid, const char *pkgid);
+struct appinfo *_appinfo_find(uid_t caller_uid, const char *appid);
+const char *_appinfo_get_value(const struct appinfo *c, enum appinfo_type type);
+const void *_appinfo_get_ptr_value(const struct appinfo *c,
+ enum appinfo_type type);
+int _appinfo_get_int_value(const struct appinfo *c, enum appinfo_type type,
+ int *val);
+int _appinfo_get_boolean(const struct appinfo *c, enum appinfo_type type,
+ bool *val);
+int _appinfo_set_value(struct appinfo *c, enum appinfo_type, const char *val);
+int _appinfo_set_ptr_value(struct appinfo *c, enum appinfo_type, void *val);
+int _appinfo_set_int_value(struct appinfo *c, enum appinfo_type type, int val);
+void _appinfo_foreach(uid_t uid, appinfo_iter_callback cb, void *user_data);
+void _appinfo_reload(void);
+int _appinfo_load(uid_t uid);
+void _appinfo_unload(uid_t uid);
+bool _appinfo_is_pkg_updating(const char *pkgid);
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "amd_appinfo.h"
+
+#define APP_SUPPORT_MODE_VIP_APPLICATION 0x00000010
+
+#define COOLDOWN_STATUS_RELEASE "Release"
+#define COOLDOWN_STATUS_RELEASE_STRING_LEN 7
+#define COOLDOWN_STATUS_LIMITACTION "LimitAction"
+#define COOLDOWN_STATUS_LIMITACTION_STRING_LEN 11
+
+/* cooldown status values */
+enum cooldown_status_val {
+ COOLDOWN_RELEASE,
+ COOLDOWN_WARNING,
+ COOLDOWN_LIMIT,
+};
+
+int _cooldown_get_status(void);
+int _cooldown_check_mode(const struct appinfo *ai);
+int _cooldown_init(void);
+void _cooldown_fini(void);
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AMD_CYNARA_H__
+#define __AMD_CYNARA_H__
+
+#include "amd_request.h"
+
+int _cynara_init(void);
+void _cynara_finish(void);
+int _cynara_check_privilege(request_h req);
+
+#endif /* __AMD_CYNARA_H__ */
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <bundle.h>
+
+#include "amd_appinfo.h"
+
+typedef char **(_extractor_mountable)(const struct appinfo *ai);
+
+char **_extractor_mountable_get_tep_paths(const struct appinfo *ai);
+char **_extractor_mountable_get_tpk_paths(const struct appinfo *ai);
+void _extractor_mount(const struct appinfo *ai, bundle *kb,
+ _extractor_mountable mountable);
+void _extractor_unmount(int pid, _extractor_mountable mountable);
+
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <sys/inotify.h>
+
+typedef bool (*inotify_watch_cb)(const char *event_name, void *data);
+
+int _inotify_add_watch(const char *path, uint32_t mask,
+ inotify_watch_cb callback, void *data);
+void _inotify_rm_watch(int wd);
+int _inotify_init(void);
+void _inotify_fini(void);
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+int _input_init(void);
+int _input_fini(void);
+int _input_lock(void);
+int _input_unlock(void);
+
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <bundle.h>
+
+#include "amd_request.h"
+#include "amd_util.h"
+#include "amd_appinfo.h"
+
+#define PROC_STATUS_LAUNCH 0
+#define PROC_STATUS_FG 3
+#define PROC_STATUS_BG 4
+#define PROC_STATUS_FOCUS 5
+#define PROC_STATUS_HIDE 7
+
+int _send_to_sigkill(int pid);
+int _resume_app(int pid, request_h req);
+int _pause_app(int pid, request_h req);
+int _term_app(int pid, request_h req);
+int _term_req_app(int pid, request_h req);
+int _term_bgapp(int pid, request_h req);
+int _term_sub_app(int pid, uid_t uid);
+int _launch_start_app(const char *appid, request_h req, bool *pending,
+ bool *bg_launch, bool new_instance);
+int _launch_start_app_local(uid_t uid, const char *appid);
+int _launch_start_app_local_with_bundle(uid_t uid, const char *appid,
+ bundle *kb);
+int _launch_start_onboot_app_local(uid_t uid, const char *appid,
+ struct appinfo *ai);
+int _launch_init(void);
+void _launch_set_focused_pid(int pid);
+int _launch_get_focused_pid(void);
+int _term_app_v2(int pid, request_h req, bool *pend);
+int _launch_start_onboot_apps(uid_t uid);
+int _terminate_app_local(uid_t uid, int pid);
+int _launch_add_fgmgr(int pid);
+void _launch_remove_fgmgr(int pid);
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AMD_LOGIN_MONITOR_H__
+#define __AMD_LOGIN_MOINTOR_H__
+
+typedef enum uid_state_e {
+ UID_STATE_UNKNOWN = 0x00,
+ UID_STATE_OPENING = 0x01,
+ UID_STATE_LINGERING = 0x02,
+ UID_STATE_ONLINE = 0x04,
+ UID_STATE_ACTIVE = 0x08,
+ UID_STATE_CLOSING = 0x10,
+ UID_STATE_OFFLINE = 0x20,
+} uid_state;
+
+void _login_monitor_set_uid_state(uid_t uid, uid_state state);
+uid_state _login_monitor_get_uid_state(uid_t uid);
+int _login_monitor_get_uids(uid_t **uids);
+int _login_monitor_init(void);
+void _login_monitor_fini(void);
+
+#endif /* __AMD_LOGIN_MONITOR_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <bundle.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+typedef struct request_s *request_h;
+
+int _request_send_result(request_h req, int res);
+int _request_send_raw(request_h req, int cmd, unsigned char *data, int len);
+int _request_get_fd(request_h req);
+int _request_get_pid(request_h req);
+int _request_get_cmd(request_h req);
+bundle *_request_get_bundle(request_h req);
+request_h _request_create_local(int cmd, uid_t uid, int pid, bundle *kb);
+void _request_free_local(request_h req);
+int _request_remove_fd(request_h req);
+int _request_reply_for_pending_request(int pid);
+int _request_flush_pending_request(int pid);
+uid_t _request_get_target_uid(request_h req);
+uid_t _request_get_uid(request_h req);
+pid_t _request_get_target_pid(request_h req);
+int _request_usr_init(uid_t uid);
+int _request_init(void);
+void _request_fini(void);
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <bundle.h>
+
+int _rua_update_screen_info(int pid, unsigned int surf);
+int _rua_add_info(int pid, bool new_instance);
+const char *_rua_get_image_path(int pid);
+int _rua_delete_info(bundle *b, uid_t uid);
+int _rua_usr_init(uid_t uid);
+void _rua_usr_fini(uid_t uid);
+int _rua_init(void);
+void _rua_fini(void);
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+int _screen_connector_send_update_request(const char *appid,
+ const char *instance_id, uid_t uid);
+int _screen_connector_add_app_screen(int pid, unsigned int surf,
+ const char *instance_id, uid_t uid);
+int _screen_connector_remove_app_screen(int pid, const char *instance_id,
+ uid_t uid);
+int _screen_connector_remove_app_screen_v2(int pid, uid_t uid);
+int _screen_connector_update_app_screen(int pid, unsigned int surf, uid_t uid);
+int _screen_connector_add_screen_viewer(int pid, int screen_type,
+ bool priv, unsigned int ref, uid_t uid);
+int _screen_connector_remove_screen_viewer(int pid, int screen_type,
+ bool priv, unsigned int ref, uid_t uid);
+int _screen_connector_remove_screen_viewer_v2(int pid, uid_t uid);
+int _screen_connector_usr_init(uid_t uid);
+void _screen_connector_usr_fini(uid_t uid);
+int _screen_connector_init(void);
+void _screen_connector_fini(void);
+const char *_screen_connector_get_appid_by_surface_id(unsigned int surf,
+ uid_t uid);
+const char *_screen_connector_get_instance_id_by_surface_id(unsigned int surf,
+ uid_t uid);
+int _screen_connector_update_screen_viewer_status(int pid, int status,
+ unsigned int surf, uid_t uid);
+unsigned int _screen_connector_get_surface_id(const char *instance_id,
+ uid_t uid);
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "amd_app_status.h"
+
+typedef struct shared_info_main_s *shared_info_h;
+
+shared_info_h _temporary_permission_create(int caller_pid, const char *appid,
+ bundle *kb, uid_t uid);
+int _temporary_permission_destroy(shared_info_h handle);
+int _temporary_permission_apply(int pid, uid_t uid, shared_info_h handle);
+int _temporary_permission_drop(int pid, uid_t uid);
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#define APP_BOOSTING_PERIOD 1500
+#define APP_BOOSTING_STOP 0
+
+#define RESOURCED_ATTRIBUTE_LARGEMEMORY 0x01
+#define RESOURCED_ATTRIBUTE_OOMTERMINATION 0X02
+#define RESOURCED_ATTRIBUTE_WEB_APP 0x04
+#define RESOURCED_ATTRIBUTE_DOWNLOAD_APP 0x08
+#define RESOURCED_ATTRIBUTE_SERVICE_APP 0x10
+
+int _signal_init(void);
+int _signal_send_watchdog(int pid, int signal_num);
+int _signal_send_proc_prelaunch(const char *appid, const char *pkgid,
+ int attribute, int category);
+int _signal_send_proc_suspend(int pid);
+int _signal_send_tep_mount(char *mnt_path[], const char *pkgid);
+int _signal_send_tep_unmount(const char *mnt_path);
+int _signal_get_proc_status(const int pid, int *status, int *focused);
+int _signal_subscribe_startup_finished(int (*callback)(uid_t uid, void *data),
+ void *user_data);
+int _signal_unsubscribe_startup_finished(void);
+int _signal_send_cpu_boost(int req);
+int _signal_send_display_lock_state(const char *state, char *flag,
+ unsigned int timeout);
+int _signal_send_display_unlock_state(const char *state, char *flag);
+int _signal_add_initializer(int (*callback)(void *data), void *user_data);
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define LAUNCHPAD_PROCESS_POOL_SOCK ".launchpad-process-pool-sock"
+
+#define PAD_CMD_LAUNCH 0
+#define PAD_CMD_VISIBILITY 10
+#define PAD_CMD_ADD_LOADER 11
+#define PAD_CMD_REMOVE_LOADER 12
+#define PAD_CMD_MAKE_DEFAULT_SLOTS 13
+#define PAD_CMD_DEMAND 14
+#define PAD_CMD_PING 15
+
+int _create_sock_activation(void);
+int _create_server_sock(void);
+int _send_cmd_to_launchpad(const char *pad_type, uid_t uid, int cmd,
+ bundle *kb);
+void _send_result_to_client(int fd, int res);
+void _send_result_to_client_v2(int fd, int res);
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <glib.h>
+#include <bundle.h>
+#include <tizen-extension-client-protocol.h>
+
+#include "amd_appinfo.h"
+
+typedef struct splash_image_s *splash_image_h;
+
+splash_image_h _splash_screen_get_image(int pid);
+splash_image_h _splash_screen_create_image(const struct appinfo *ai,
+ bundle *kb, int cmd, bool is_subapp);
+void _splash_screen_send_image(splash_image_h si);
+void _splash_screen_send_pid(splash_image_h si, int pid);
+void _splash_screen_set_effect_type(int pid, const char *appid, bool is_subapp);
+void _splash_screen_destroy_image(splash_image_h si);
+int _splash_screen_init(void);
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "amd_appinfo.h"
+
+#define SUSPEND_TYPE_EXCLUDE "exclude"
+#define SUSPEND_TYPE_INCLUDE "include"
+
+enum suspend_status_e {
+ SUSPEND_STATUS_EXCLUDE,
+ SUSPEND_STATUS_INCLUDE,
+};
+
+bool _suspend_is_allowed_background(const struct appinfo *ai);
+void _suspend_add_timer(int pid, const struct appinfo *ai);
+void _suspend_remove_timer(int pid);
+int _suspend_add_proc(int pid);
+int _suspend_remove_proc(int pid);
+int _suspend_update_status(int pid, int status);
+void _suspend_init(void);
+void _suspend_fini(void);
+
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <unistd.h>
+
+#include <dlog.h>
+#include <glib.h>
+#include <stdbool.h>
+#include <tzplatform_config.h>
+
+#define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AUL_AMD"
+
+#define _E(fmt, arg...) LOGE(fmt, ##arg)
+#define _D(fmt, arg...) LOGD(fmt, ##arg)
+#define _W(fmt, arg...) LOGW(fmt, ##arg)
+#define _I(fmt, arg...) LOGI(fmt, ##arg)
+
+#define MAX_LOCAL_BUFSZ 128
+#define MAX_PID_STR_BUFSZ 20
+#define MAX_UID_STR_BUFSZ 20
+
+#define MAX_PACKAGE_STR_SIZE 512
+#define MAX_PACKAGE_APP_PATH_SIZE 512
+
+#define REGULAR_UID_MIN 5000
+
+#define GSLIST_FOREACH_SAFE(list, l, l_next) \
+ for (l = list, \
+ l_next = g_slist_next(l); \
+ l; \
+ l = l_next, \
+ l_next = g_slist_next(l))
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+int _util_save_log(const char *tag, const char *message);
+int _util_init(void);
+void _util_fini(void);
+bool _util_check_oom(void);
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <wayland-client.h>
+
+int _wayland_add_registry_listener(
+ struct wl_registry_listener *registry_listener,
+ void *data);
+struct wl_display *_wayland_get_display(void);
+int _wayland_init(void);
+void _wayland_finish(void);
+
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AMD_WIDGET_H__
+#define __AMD_WIDGET_H__
+
+#include "amd_request.h"
+
+int _widget_add(const char *widget_id, const char *instance_id, int pid,
+ uid_t uid);
+int _widget_del(const char *widget_id, const char *instance_id);
+int _widget_list(const char *widget_id, request_h req);
+int _widget_update(const char *widget_id, request_h req);
+int _widget_cleanup(int pid, uid_t uid);
+int _widget_is_faulted(const char *widget_id, int pid,
+ uid_t uid, bool *is_faulted);
+bool _widget_exist(int pid, uid_t uid);
+char *_widget_get_id(int pid, uid_t uid);
+int _widget_send_status_to_viewer(int pid, uid_t uid, const char *widget_id,
+ int viewer_pid, aul_widget_instance_event_e status);
+int _widget_send_dead_signal(int pid, uid_t uid, const char *pkgid);
+int _widget_count(const char *widget_id, uid_t uid);
+int _widget_get_pid(const char *widget_id, const char *instance_id);
+int _widget_verify_cmd(request_h req);
+int _widget_is_dying(int pid, uid_t uid);
+int _widget_init(void);
+void _widget_fini(void);
+int _widget_add_update_info(const char *pkg_id, int pid, uid_t uid);
+int _widget_send_dead_signal_for_update_widget(const char *pkgid);
+int _widget_send_dead_signal_for_faulted(int pid, uid_t uid,
+ const char *pkgid, const char *widget_id);
+void _widget_restart_faulted(void);
+void _widget_dead_handler(int pid, int uid, const char *pkgid, int caller_pid,
+ bool normal_exit, bool can_restart);
+void _widget_verify_instance(bundle *kb, int pid, uid_t uid);
+int _widget_send_running_info(request_h req);
+
+#endif /* __AMD_WIDGET_H__ */
+
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define AUL_DBUS_PATH "/aul/dbus_handler"
+#define AUL_DBUS_SIGNAL_INTERFACE "org.tizen.aul.signal"
+#define AUL_DBUS_APPDEAD_SIGNAL "app_dead"
+#define AUL_DBUS_APPLAUNCH_SIGNAL "app_launch"
+#define AUL_DBUS_HOMELAUNCH_SIGNAL "home_launch"
+
+#define AUL_APP_STATUS_DBUS_PATH "/Org/Tizen/Aul/AppStatus"
+#define AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE "org.tizen.aul.AppStatus"
+#define STATUS_FOREGROUND "fg"
+#define STATUS_BACKGROUND "bg"
+
+#define AUL_APP_STATUS_DBUS_LAUNCH_REQUEST "AppLaunch"
+#define AUL_APP_STATUS_DBUS_RESUME_REQUEST "AppResume"
+#define AUL_APP_STATUS_DBUS_TERMINATE_REQUEST "AppTerminate"
+#define AUL_APP_STATUS_DBUS_STATUS_CHANGE "AppStatusChange"
+#define AUL_APP_STATUS_DBUS_GROUP "AppGroup"
+#define AUL_APP_STATUS_DBUS_TERMINATED "AppTerminated"
+
+#define SYSTEM_PATH_CORE "/Org/Tizen/System/DeviceD/Core"
+#define SYSTEM_INTERFACE_CORE "org.tizen.system.deviced.core"
+
+#define SYSTEM_SIGNAL_BOOTING_DONE "BootingDone"
+
+#define SYSTEM_PATH_SYSNOTI "/Org/Tizen/System/DeviceD/SysNoti"
+#define SYSTEM_INTERFACE_SYSNOTI "org.tizen.system.deviced.SysNoti"
+
+#define SYSTEM_SIGNAL_COOLDOWN_CHANGED "CoolDownChanged"
+
+#define RESOURCED_PATH_CORE "/Org/Tizen/ResourceD/Process"
+#define RESOURCED_INTERFACE_CORE "org.tizen.resourced.process"
+
+#define RESOURCED_SIGNAL_PROCESS_STATUS "ProcStatus"
+
+#define ROTATION_BUS_NAME "org.tizen.system.coord"
+#define ROTATION_OBJECT_PATH "/Org/Tizen/System/Coord/Rotation"
+#define ROTATION_INTERFACE_NAME "org.tizen.system.coord.rotation"
+#define ROTATION_METHOD_NAME "Degree"
+
+#define RESOURCED_PROC_OBJECT "/Org/Tizen/ResourceD/Process"
+#define RESOURCED_PROC_INTERFACE "org.tizen.resourced.process"
+#define RESOURCED_PROC_METHOD "ProcExclude"
+
+#define APPFW_SUSPEND_HINT_PATH "/Org/Tizen/Appfw/SuspendHint"
+#define APPFW_SUSPEND_HINT_INTERFACE "org.tizen.appfw.SuspendHint"
+#define APPFW_SUSPEND_HINT_SIGNAL "SuspendHint"
+
+#define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
+#define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
+#define RESOURCED_FREEZER_SIGNAL "FreezerState"
+
+#define RESOURCED_ALLOWED_BG_ATTRIBUTE 0x100
+#define RESOURCED_BACKGROUND_MANAGEMENT_ATTRIBUTE 0x200
+#define RESOURCED_API_VER_2_4_ATTRIBUTE 0x400
+
+#define RESOURCED_PROC_PRELAUNCH_SIGNAL "ProcPrelaunch"
+#define RESOURCED_PROC_WATCHDOG_SIGNAL "ProcWatchdog"
+#define RESOURCED_PROC_GROUP_SIGNAL "ProcGroup"
+
+#define PROC_TYPE_EXCLUDE "exclude"
+#define PROC_TYPE_INCLUDE "include"
+#define PROC_TYPE_WAKEUP "wakeup"
+
+#define TEP_BUS_NAME "org.tizen.system.deviced"
+#define TEP_OBJECT_PATH "/Org/Tizen/System/DeviceD/Tzip"
+#define TEP_INTERFACE_NAME "org.tizen.system.deviced.Tzip"
+#define TEP_MOUNT_METHOD "Mount"
+#define TEP_UNMOUNT_METHOD "Unmount"
+#define TEP_IS_MOUNTED_METHOD "IsMounted"
+
+#define WM_PROC_NAME "org.enlightenment.wm"
+#define WM_PROC_PATH "/org/enlightenment/wm"
+#define WM_PROC_INTERFACE "org.enlightenment.wm.proc"
+#define WM_PROC_METHOD "GetProcStatus"
+
+#define SD_BUS_NAME "org.freedesktop.systemd1"
+#define SD_OBJECT_PATH "/org/freedesktop/systemd1"
+
+#define SD_MANAGER_INTERFACE "org.freedesktop.systemd1.Manager"
+#define SD_STARTUP_FINISHED_SIGNAL "StartupFinished"
+#define SD_USER_SESSION_STARTUP_FINISHED_SIGNAL "UserSessionStartupFinished"
+#define SD_SUBSCRIBE_METHOD "Subscribe"
+
+#define SD_UNIT_OBJECT_PATH "/org/freedesktop/systemd1/unit/default_2etarget"
+#define SD_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
+#define SD_GET_METHOD "Get"
+
+#define SYSTEM_BUS_NAME "org.tizen.system.deviced"
+#define SYSTEM_OBJECT_PATH "/Org/Tizen/System/DeviceD/PmQos"
+#define SYSTEM_INTERFACE_NAME "org.tizen.system.deviced.PmQos"
+#define SYSTEM_METHOD_NAME "AppLaunch"
+
+#define SYSTEM_PATH_DISPLAY "/Org/Tizen/System/DeviceD/Display"
+#define SYSTEM_INTERFACE_DISPLAY "org.tizen.system.deviced.display"
+#define SYSTEM_LOCK_STATE "lockstate"
+#define SYSTEM_UNLOCK_STATE "unlockstate"
+#define SYSTEM_LCD_OFF "lcdoff"
+#define SYSTEM_STAY_CUR_STATE "staycurstate"
+#define SYSTEM_SLEEP_MARGIN "sleepmargin"
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/** AUL SVC internal private key */
+#define AUL_SVC_K_OPERATION "__APP_SVC_OP_TYPE__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_URI "__APP_SVC_URI__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_MIME "__APP_SVC_MIME_TYPE__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_DATA "__APP_SVC_DATA__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_PKG_NAME "__APP_SVC_PKG_NAME__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_CATEGORY "__APP_SVC_CATEGORY__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_RES_VAL "__APP_SVC_K_RES_VAL__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_WIN_ID "__APP_SVC_K_WIN_ID__"
+/** AUL SVC internal private key */
+#define AUL_SVC_K_LAUNCH_MODE "__APP_SVC_LAUNCH_MODE__"
+
+
--- /dev/null
+d /run/aul 1755 root root
+t /run/aul - - - - security.SMACK64="System::Run"
+t /run/aul - - - - security.SMACK64TRANSMUTE="TRUE"
+d /run/aul/apps 1777 root root
+t /run/aul/apps - - - - security.SMACK64="*"
+t /run/aul/apps - - - - security.SMACK64TRANSMUTE="TRUE"
+d /run/aul/daemons 1777 root root
+t /run/aul/daemons - - - - security.SMACK64="User::Home"
+t /run/aul/daemons - - - - security.SMACK64TRANSMUTE="TRUE"
+d /run/aul/dbspace 1777 root root
+t /run/aul/dbspace - - - - security.SMACK64="User::Home"
+t /run/aul/dbspace - - - - security.SMACK64TRANSMUTE="TRUE"
+d /run/aul/log 1777 root root
+t /run/aul/log - - - - security.SMACK64="User::Home"
+t /run/aul/log - - - - security.SMACK64TRANSMUTE="TRUE"
--- /dev/null
+#
+# Systemd script to Launch AMD
+#
+
+[Unit]
+Description=Start Application Management Daemon
+DefaultDependencies=false
+Requires=dbus.socket tizen-system-env.service
+After=dbus.socket tizen-system-env.service
+
+[Service]
+User=app_fw
+Group=app_fw
+SmackProcessLabel=System
+Type=notify
+EnvironmentFile=/run/tizen-system-env
+EnvironmentFile=/run/xdg-root-env
+ExecStart=/usr/bin/amd
+OOMScoreAdjust=-100
+Restart=on-failure
+RestartSec=3
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+[Socket]
+ListenStream=/run/aul/daemons/.amd-sock
+SocketMode=0777
+DirectoryMode=0777
+
+[Install]
+WantedBy=sockets.target
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
+
--- /dev/null
+%bcond_with x
+%bcond_with wayland
+
+Name: amd
+Summary: Application Management Daemon
+Version: 0.2.1
+Release: 1
+Group: Application Framework/Service
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+Source100: ac.conf
+Source101: ac.service
+Source102: ac.socket
+Source1001: %{name}.manifest
+
+Requires(post): /sbin/ldconfig
+Requires(post): /usr/bin/systemctl
+Requires(postun): /sbin/ldconfig
+Requires(postun): /usr/bin/systemctl
+Requires(preun): /usr/bin/systemctl
+Requires: tizen-platform-config
+
+BuildRequires: cmake
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(bundle)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(security-manager)
+BuildRequires: pkgconfig(rua)
+BuildRequires: pkgconfig(aul)
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(pkgmgr-info)
+BuildRequires: pkgconfig(pkgmgr)
+BuildRequires: pkgconfig(libtzplatform-config)
+BuildRequires: pkgconfig(libsystemd-daemon)
+BuildRequires: pkgconfig(cynara-client)
+BuildRequires: pkgconfig(cynara-creds-socket)
+BuildRequires: pkgconfig(cynara-session)
+BuildRequires: pkgconfig(cert-svc-vcore)
+BuildRequires: pkgconfig(xkbcommon)
+BuildRequires: pkgconfig(sensor)
+BuildRequires: pkgconfig(ttrace)
+BuildRequires: pkgconfig(app2sd)
+BuildRequires: pkgconfig(capi-system-info)
+%if %{with wayland}
+BuildRequires: pkgconfig(wayland-client)
+BuildRequires: pkgconfig(tizen-extension-client)
+BuildRequires: pkgconfig(tizen-launch-client)
+BuildRequires: pkgconfig(wayland-tbm-client)
+%endif
+
+%if "%{?profile}" == "tv"
+%define tizen_feature_terminate_unmanageable_app 0
+%define tizen_feature_block_input 0
+%define tizen_feature_auto_rotation 0
+%else
+%if "%{?profile}" == "ivi"
+%define tizen_feature_terminate_unmanageable_app 1
+%define tizen_feature_block_input 0
+%define tizen_feature_auto_rotation 0
+%else
+%define tizen_feature_terminate_unmanageable_app 1
+%define tizen_feature_block_input 1
+%define tizen_feature_auto_rotation 1
+%endif
+%endif
+
+%description
+Application management daemon
+
+%prep
+%setup -q
+sed -i 's|TZ_SYS_DB|%{TZ_SYS_DB}|g' %{SOURCE1001}
+cp %{SOURCE1001} .
+
+%build
+%if 0%{?simulator}
+CFLAGS="%{optflags} -D__emul__"; export CFLAGS
+%endif
+
+%if 0%{?tizen_feature_terminate_unmanageable_app}
+_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP=ON
+%endif
+%if 0%{?tizen_feature_block_input}
+_TIZEN_FEATURE_BLOCK_INPUT=ON
+%endif
+%if 0%{?tizen_feature_auto_rotation}
+_TIZEN_FEATURE_AUTO_ROTATION=ON
+%endif
+
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+%cmake -DFULLVER=%{version} -DMAJORVER=${MAJORVER} \
+%if %{with wayland}
+ -Dwith_wayland=TRUE \
+%endif
+%if %{with x}
+ -Dwith_x11=TRUE \
+%endif
+ -D_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP:BOOL=${_TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP} \
+ -D_TIZEN_FEATURE_BLOCK_INPUT:BOOL=${_TIZEN_FEATURE_BLOCK_INPUT} \
+ -D_TIZEN_FEATURE_AUTO_ROTATION:BOOL=${_TIZEN_FEATURE_AUTO_ROTATION} \
+ .
+
+%__make %{?_smp_mflags}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+mkdir -p %{buildroot}%{_tmpfilesdir}
+mkdir -p %{buildroot}%{_unitdir}/multi-user.target.wants
+mkdir -p %{buildroot}%{_unitdir}/sockets.target.wants
+install -m 0644 %SOURCE100 %{buildroot}%{_tmpfilesdir}/ac.conf
+install -m 0644 %SOURCE101 %{buildroot}%{_unitdir}/ac.service
+install -m 0644 %SOURCE102 %{buildroot}%{_unitdir}/ac.socket
+ln -sf ../ac.service %{buildroot}%{_unitdir}/multi-user.target.wants/ac.service
+ln -sf ../ac.socket %{buildroot}%{_unitdir}/sockets.target.wants/ac.socket
+
+%preun
+if [ $1 == 0 ]; then
+ systemctl stop ac.service
+ systemctl disable ac
+fi
+
+%post
+/sbin/ldconfig
+
+systemctl daemon-reload
+if [ $1 == 1 ]; then
+ systemctl restart ac.service
+fi
+
+%postun
+/sbin/ldconfig
+systemctl daemon-reload
+
+%files
+%license LICENSE
+%manifest %{name}.manifest
+%{_tmpfilesdir}/ac.conf
+%{_unitdir}/ac.service
+%{_unitdir}/multi-user.target.wants/ac.service
+%{_unitdir}/ac.socket
+%{_unitdir}/sockets.target.wants/ac.socket
+%caps(cap_kill,cap_dac_override=ep) %{_bindir}/amd
+
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <glib.h>
+#include <bundle.h>
+#include <aul.h>
+#include <aul_cmd.h>
+#include <aul_app_com.h>
+#include <aul_sock.h>
+
+#include "amd_util.h"
+#include "amd_app_com.h"
+
+struct endpoint_info {
+ char *endpoint;
+ unsigned int propagate;
+ char *privilege;
+ GList *clients;
+};
+
+struct client_info {
+ int pid;
+ uid_t uid;
+ char *filter;
+ struct endpoint_info *endpoint;
+};
+
+static GHashTable *cpid_tbl;
+static GHashTable *endpoint_tbl;
+
+static void __remove_client(struct endpoint_info *info, int cpid);
+
+static void __free_endpoint(struct endpoint_info *info)
+{
+ if (!info)
+ return;
+
+ if (info->endpoint)
+ g_free(info->endpoint);
+
+ if (info->privilege)
+ g_free(info->privilege);
+
+ if (info->clients)
+ g_list_free(info->clients);
+
+ g_free(info);
+}
+
+int _app_com_broker_init(void)
+{
+ if (!endpoint_tbl) {
+ endpoint_tbl = g_hash_table_new(g_str_hash, g_str_equal);
+ if (endpoint_tbl == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+ }
+
+ if (!cpid_tbl) {
+ cpid_tbl = g_hash_table_new(g_direct_hash, g_direct_equal);
+ if (cpid_tbl == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void __remove_cpid(gpointer key, gpointer value, gpointer user_data)
+{
+ int pid = GPOINTER_TO_INT(key);
+ struct endpoint_info *info;
+ GList *client_list = (GList *)value;
+
+ while (client_list) {
+ info = (struct endpoint_info *)client_list->data;
+ __remove_client(info, pid);
+ client_list = client_list->next;
+ }
+ g_list_free((GList *)value);
+}
+
+int _app_com_broker_fini(void)
+{
+ if (cpid_tbl) {
+ g_hash_table_foreach(cpid_tbl, __remove_cpid, NULL);
+ g_hash_table_destroy(cpid_tbl);
+ cpid_tbl = NULL;
+ }
+
+ if (endpoint_tbl) {
+ g_hash_table_destroy(endpoint_tbl);
+ endpoint_tbl = NULL;
+ }
+
+ return 0;
+}
+
+int _app_com_add_endpoint(const char *endpoint, unsigned int propagate,
+ const char *assoc_priv)
+{
+ struct endpoint_info *info;
+
+ info = g_hash_table_lookup(endpoint_tbl, endpoint);
+ if (info) {
+ _E("endpoint already exists.");
+ return AUL_APP_COM_R_ERROR_ENDPOINT_ALREADY_EXISTS;
+ }
+
+ _D("endpoint=%s propagate=%d assoc_priv=%s",
+ endpoint, propagate, assoc_priv);
+
+ info = (struct endpoint_info *)g_malloc0(sizeof(struct endpoint_info));
+ if (info == NULL) {
+ _E("out of memory");
+ return AUL_APP_COM_R_ERROR_OUT_OF_MEMORY;
+ }
+
+ info->endpoint = g_strdup(endpoint);
+ info->propagate = propagate;
+ info->clients = NULL;
+
+ if (assoc_priv)
+ info->privilege = g_strdup(assoc_priv);
+ else
+ info->privilege = NULL;
+
+ g_hash_table_insert(endpoint_tbl, info->endpoint, info);
+
+ return AUL_APP_COM_R_ERROR_OK;
+}
+
+int _app_com_remove_endpoint(const char *endpoint)
+{
+ struct endpoint_info *info;
+
+ info = g_hash_table_lookup(endpoint_tbl, endpoint);
+ if (!info) {
+ _D("endpoint not exists");
+ return AUL_APP_COM_R_ERROR_UNKNOWN_ENDPOINT;
+ }
+
+ if (info->clients != NULL) {
+ _D("client active");
+ return AUL_APP_COM_R_ERROR_CLIENT_REMAINING;
+ }
+
+ g_hash_table_remove(endpoint_tbl, endpoint);
+ __free_endpoint(info);
+
+ return AUL_APP_COM_R_ERROR_OK;
+}
+
+static struct client_info *__add_client(struct endpoint_info *info,
+ const char *filter, int pid, uid_t uid)
+{
+ GList *client_list;
+ struct client_info *c;
+
+ c = (struct client_info *)g_malloc0(sizeof(struct client_info));
+ if (c == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ c->endpoint = info;
+ c->pid = pid;
+ c->uid = uid;
+ if (filter)
+ c->filter = g_strdup(filter);
+ else
+ c->filter = NULL;
+
+ info->clients = g_list_append(info->clients, c);
+ client_list = g_hash_table_lookup(cpid_tbl, GINT_TO_POINTER(pid));
+ if (client_list == NULL) {
+ client_list = g_list_append(client_list, info);
+ g_hash_table_insert(cpid_tbl, GINT_TO_POINTER(pid),
+ client_list);
+ } else {
+ client_list = g_list_append(client_list, info);
+ }
+
+ return c;
+}
+
+int _app_com_join(const char *endpoint, int cpid, const char *filter,
+ uid_t uid)
+{
+ struct endpoint_info *info;
+
+ info = g_hash_table_lookup(endpoint_tbl, endpoint);
+ if (!info) {
+ _E("endpoint not exists: %s", endpoint);
+ return AUL_APP_COM_R_ERROR_UNKNOWN_ENDPOINT;
+ }
+
+ _D("endpoint=%s cpid=%d filter=%s uid=%d", endpoint, cpid, filter, uid);
+
+ if (__add_client(info, filter, cpid, uid) == NULL)
+ return AUL_APP_COM_R_ERROR_OUT_OF_MEMORY;
+
+ return AUL_APP_COM_R_ERROR_OK;
+}
+
+const char *_app_com_get_privilege(const char *endpoint)
+{
+ struct endpoint_info *info;
+
+ info = g_hash_table_lookup(endpoint_tbl, endpoint);
+ if (!info) {
+ _E("endpoint not exists: %s", endpoint);
+ return NULL;
+ }
+
+ return info->privilege;
+}
+
+static int __check_filter(const char *filter, int cpid, int rpid, bundle *b)
+{
+ /* TODO */
+ return 0;
+}
+
+int _app_com_send(const char *endpoint, int cpid, bundle *envelope, uid_t uid)
+{
+ struct endpoint_info *info;
+ GList *client_head;
+ struct client_info *client;
+ int ret;
+ int result = AUL_APP_COM_R_OK;
+
+ info = g_hash_table_lookup(endpoint_tbl, endpoint);
+ if (!info) {
+ _E("endpoint not exists: %s", endpoint);
+ return AUL_APP_COM_R_ERROR_UNKNOWN_ENDPOINT;
+ }
+
+ /* TODO delete internal keys */
+
+ _D("endpoint=%s cpid=%d", endpoint, cpid);
+
+ bundle_add_str(envelope, AUL_K_COM_ENDPOINT, endpoint);
+ bundle_add_byte(envelope, AUL_K_COM_RESULT, &result, sizeof(result));
+
+ client_head = info->clients;
+ while (client_head) {
+ client = (struct client_info *)client_head->data;
+ client_head = client_head->next;
+ if (client == NULL)
+ continue;
+ if (client->pid == cpid)
+ continue;
+ if (client->uid >= REGULAR_UID_MIN && client->uid != uid)
+ continue;
+
+ if (client->filter) {
+ ret = __check_filter(client->filter, cpid, client->pid,
+ envelope);
+ if (ret < 0)
+ continue;
+ }
+
+ ret = aul_sock_send_bundle(client->pid, client->uid,
+ APP_COM_MESSAGE, envelope, AUL_SOCK_NOREPLY);
+ if (ret < 0) {
+ _E("failed to send message pid(%d), uid(%d), ret(%d)",
+ client->pid, client->uid, ret);
+ }
+ }
+
+ return AUL_APP_COM_R_ERROR_OK;
+}
+
+static void __remove_client(struct endpoint_info *info, int cpid)
+{
+ GList *client_head;
+ struct client_info *client;
+
+ if (info == NULL)
+ return;
+
+ client_head = info->clients;
+ while (client_head) {
+ client = (struct client_info *)client_head->data;
+ client_head = client_head->next;
+ if (client && client->pid == cpid) {
+ info->clients = g_list_remove(info->clients, client);
+ if (client->filter)
+ g_free(client->filter);
+
+ g_free(client);
+ }
+ }
+
+ if (info->clients == NULL) {
+ g_hash_table_remove(endpoint_tbl, info->endpoint);
+ _D("endpoint removed: %s", info->endpoint);
+ __free_endpoint(info);
+ }
+}
+
+int _app_com_leave(const char *endpoint, int cpid)
+{
+ struct endpoint_info *info;
+ GList *endpoint_head;
+
+ info = g_hash_table_lookup(endpoint_tbl, endpoint);
+ if (!info) {
+ _E("endpoint not exists: %s", endpoint);
+ return AUL_APP_COM_R_ERROR_UNKNOWN_ENDPOINT;
+ }
+
+ endpoint_head = g_hash_table_lookup(cpid_tbl, GINT_TO_POINTER(cpid));
+ if (endpoint_head) {
+ endpoint_head = g_list_remove(endpoint_head, info);
+ if (endpoint_head == NULL) {
+ g_hash_table_remove(cpid_tbl, GINT_TO_POINTER(cpid));
+ } else {
+ g_hash_table_replace(cpid_tbl, GINT_TO_POINTER(cpid),
+ endpoint_head);
+ }
+ }
+ __remove_client(info, cpid);
+
+ return AUL_APP_COM_R_ERROR_OK;
+}
+
+int _app_com_client_remove(int cpid)
+{
+ GList *client_list;
+ struct endpoint_info *info;
+ GList *client_head;
+
+ client_list = g_hash_table_lookup(cpid_tbl, GINT_TO_POINTER(cpid));
+ if (client_list == NULL)
+ return AUL_APP_COM_R_OK;
+
+ client_head = g_list_first(client_list);
+ while (client_head) {
+ info = (struct endpoint_info *)client_head->data;
+ client_head = g_list_next(client_head);
+ if (info) {
+ client_list = g_list_remove(client_list, info);
+ __remove_client(info, cpid);
+ }
+ }
+
+ g_hash_table_remove(cpid_tbl, GINT_TO_POINTER(cpid));
+
+ return AUL_APP_COM_R_ERROR_OK;
+}
+
+bool _app_com_endpoint_exists(const char *endpoint)
+{
+ return g_hash_table_contains(endpoint_tbl, endpoint);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <glib.h>
+#include <aul.h>
+#include <aul_svc.h>
+#include <bundle_internal.h>
+#include <aul_sock.h>
+#include <wayland-client.h>
+#include <wayland-tbm-client.h>
+#include <tizen-extension-client-protocol.h>
+
+#include "amd_util.h"
+#include "amd_app_group.h"
+#include "amd_launch.h"
+#include "amd_request.h"
+#include "amd_app_status.h"
+#include "app_signal.h"
+#include "amd_appinfo.h"
+#include "amd_share.h"
+#include "amd_suspend.h"
+#include "amd_wayland.h"
+
+#define APP_SVC_K_LAUNCH_MODE "__APP_SVC_LAUNCH_MODE__"
+
+typedef struct _app_group_context_t {
+ int pid;
+ int wid;
+ int status;
+ int fg;
+ int group_sig;
+ int can_be_leader;
+ int reroute;
+ int caller_pid;
+ int can_shift;
+ int recycle;
+ app_group_launch_mode launch_mode;
+} app_group_context_t;
+
+static struct wl_display *display;
+static struct tizen_policy *tz_policy;
+static int tz_policy_initialized;
+static GHashTable *app_group_hash;
+static int dead_pid = -1;
+static int focused_leader_pid = -1;
+static GList *recycle_bin;
+extern char *home_appid;
+
+static void __wl_listener_cb(void *data, struct wl_registry *reg,
+ uint32_t id, const char *interface, uint32_t ver)
+{
+ if (!strcmp(interface, "tizen_policy")) {
+ if (!tz_policy) {
+ tz_policy = wl_registry_bind(reg, id,
+ &tizen_policy_interface, 1);
+ }
+ }
+}
+
+static void __wl_listener_remove_cb(void *data, struct wl_registry *reg,
+ uint32_t id)
+{
+ if (tz_policy) {
+ tizen_policy_destroy(tz_policy);
+ tz_policy = NULL;
+ }
+}
+
+static struct wl_registry_listener registry_listener = {
+ __wl_listener_cb,
+ __wl_listener_remove_cb
+};
+
+static int __wl_init(void)
+{
+ if (!display) {
+ display = _wayland_get_display();
+ if (!display) {
+ _E("Failed to get display");
+ return -1;
+ }
+ }
+
+ if (!tz_policy)
+ return -1;
+
+ tz_policy_initialized = 1;
+
+ return 0;
+}
+
+static void __lower_window(int wid)
+{
+ if (!tz_policy_initialized) {
+ if (__wl_init() < 0) {
+ _E("__wl_init() failed");
+ return;
+ }
+ }
+
+ tizen_policy_lower_by_res_id(tz_policy, wid);
+ wl_display_roundtrip(display);
+}
+
+static void __attach_window(int parent_wid, int child_wid)
+{
+ if (!tz_policy_initialized) {
+ if (__wl_init() < 0) {
+ _E("__wl_init() failed");
+ return;
+ }
+ }
+
+ tizen_policy_set_transient_for(tz_policy, child_wid, parent_wid);
+ wl_display_roundtrip(display);
+}
+
+static void __detach_window(int child_wid)
+{
+ if (!tz_policy_initialized) {
+ if (__wl_init() < 0) {
+ _E("__wl_init() failed");
+ return;
+ }
+ }
+
+ tizen_policy_unset_transient_for(tz_policy, child_wid);
+ wl_display_roundtrip(display);
+}
+
+static void __activate_below(int wid, int below_wid)
+{
+ if (!tz_policy_initialized) {
+ if (__wl_init() < 0) {
+ _E("__wl_init() failed");
+ return;
+ }
+ }
+
+ tizen_policy_activate_below_by_res_id(tz_policy, below_wid, wid);
+ wl_display_roundtrip(display);
+}
+
+static void __activate_above(int wid, int above_wid)
+{
+ if (!tz_policy_initialized) {
+ if (__wl_init() < 0) {
+ _E("__wl_init() failed");
+ return;
+ }
+ }
+
+ tizen_policy_activate_above_by_res_id(tz_policy, above_wid, wid);
+ wl_display_roundtrip(display);
+}
+
+static gint __comp_pid(gconstpointer a, gconstpointer b)
+{
+ app_group_context_t *ac1 = (app_group_context_t *)a;
+
+ return ac1->pid - GPOINTER_TO_INT(b);
+}
+
+static void __list_destroy_cb(gpointer data)
+{
+ free(data);
+}
+
+static gboolean __hash_table_cb(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ int pid = GPOINTER_TO_INT(user_data);
+ GList *list = (GList *)value;
+ GList *itr = g_list_first(list);
+ app_group_context_t *ac;
+
+ while (itr != NULL) {
+ ac = (app_group_context_t *)itr->data;
+ if (ac && ac->pid == pid) {
+ free(ac);
+ list = g_list_delete_link(list, itr);
+ if (g_list_length(list) == 0) {
+ g_list_free_full(list, __list_destroy_cb);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ itr = g_list_next(itr);
+ }
+
+ return FALSE;
+}
+
+static GList *__find_removable_apps(int from)
+{
+ int cnt;
+ int *pids = NULL;
+ GList *list = NULL;
+ bool found = false;
+ int i;
+ int j;
+ int *gpids = NULL;
+ int gcnt;
+
+ _app_group_get_leader_pids(&cnt, &pids);
+
+ for (i = 0; i < cnt; i++) {
+ _app_group_get_group_pids(pids[i], &gcnt, &gpids);
+ for (j = 0; j < gcnt; j++) {
+ if (gpids[j] == from) {
+ found = true;
+ continue;
+ }
+
+ if (found) {
+ list = g_list_append(list,
+ GINT_TO_POINTER(gpids[j]));
+ }
+ }
+
+ if (gpids != NULL)
+ free(gpids);
+
+ if (found)
+ break;
+ }
+
+ if (pids != NULL)
+ free(pids);
+
+ return list;
+}
+
+static void __prepare_to_suspend_services(int pid, uid_t uid)
+{
+ int ret;
+ int dummy;
+
+ _D("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+ ret = aul_sock_send_raw(pid, uid, APP_SUSPEND, (unsigned char *)&dummy,
+ sizeof(int), AUL_SOCK_NOREPLY);
+ if (ret < 0)
+ _E("error on suspend service for pid: %d", pid);
+}
+
+static void __prepare_to_wake_services(int pid, uid_t uid)
+{
+ int ret;
+ int dummy;
+
+ _D("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+ ret = aul_sock_send_raw(pid, uid, APP_WAKE, (unsigned char *)&dummy,
+ sizeof(int), AUL_SOCK_NOREPLY);
+ if (ret < 0)
+ _E("error on wake service for pid: %d", pid);
+}
+
+static void __set_flag(GList *list, int cpid, int flag, bool force)
+{
+ app_group_context_t *ac;
+ app_status_h app_status;
+ const struct appinfo *ai;
+ const char *appid;
+ const char *pkgid;
+ int bg_category;
+ uid_t uid;
+
+ while (list) {
+ ac = (app_group_context_t *)list->data;
+ if (ac && (ac->fg != flag || force == true)) {
+ app_status = _app_status_find(ac->pid);
+ appid = _app_status_get_appid(app_status);
+ uid = _app_status_get_uid(app_status);
+ ai = _appinfo_find(uid, appid);
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ bg_category = (intptr_t)_appinfo_get_value(ai,
+ AIT_BG_CATEGORY);
+ if (flag) {
+ _D("Send FG signal %s", appid);
+ aul_send_app_status_change_signal(ac->pid,
+ appid, pkgid, STATUS_FOREGROUND,
+ APP_TYPE_UI);
+ if (!bg_category) {
+ _app_status_find_service_apps(
+ app_status,
+ STATUS_VISIBLE,
+ __prepare_to_wake_services,
+ false);
+ }
+ } else {
+ _D("send BG signal %s", appid);
+ aul_send_app_status_change_signal(ac->pid,
+ appid, pkgid, STATUS_BACKGROUND,
+ APP_TYPE_UI);
+ if (!bg_category) {
+ _app_status_find_service_apps(
+ app_status,
+ STATUS_BG,
+ __prepare_to_suspend_services,
+ true);
+ if (force && cpid == ac->pid) {
+ __prepare_to_suspend_services(
+ ac->pid, uid);
+ _suspend_add_timer(ac->pid, ai);
+ }
+ }
+ }
+ ac->fg = flag;
+ }
+ list = g_list_next(list);
+ }
+}
+
+static void __set_fg_flag(int cpid, int flag, bool force)
+{
+ int lpid = _app_group_get_leader_pid(cpid);
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == lpid) {
+ __set_flag(i, cpid, flag, force);
+ break;
+ }
+ }
+}
+
+static bool __is_visible(int cpid)
+{
+ int lpid = _app_group_get_leader_pid(cpid);
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == lpid) {
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->status == STATUS_VISIBLE)
+ return true;
+
+ i = g_list_next(i);
+ }
+ break;
+ }
+ }
+
+ return false;
+}
+
+static bool __can_attach_window(bundle *b, const char *appid,
+ app_group_launch_mode *launch_mode, uid_t uid)
+{
+ char *str = NULL;
+ const char *mode = NULL;
+ const struct appinfo *ai = NULL;
+
+ ai = _appinfo_find(uid, appid);
+ mode = _appinfo_get_value(ai, AIT_LAUNCH_MODE);
+
+ if (mode == NULL)
+ *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLE;
+ else if (strcmp(mode, "caller") == 0)
+ *launch_mode = APP_GROUP_LAUNCH_MODE_CALLER;
+ else if (strcmp(mode, "single") == 0)
+ *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLE;
+ else if (strcmp(mode, "group") == 0)
+ *launch_mode = APP_GROUP_LAUNCH_MODE_GROUP;
+ else if (strcmp(mode, "singleton") == 0)
+ *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLETON;
+
+ switch (*launch_mode) {
+ case APP_GROUP_LAUNCH_MODE_CALLER:
+ case APP_GROUP_LAUNCH_MODE_SINGLETON:
+ _D("launch mode from db is caller or singleton");
+
+ bundle_get_str(b, APP_SVC_K_LAUNCH_MODE, &str);
+ if (str != NULL && strncmp(str, "group", 5) == 0)
+ return true;
+ break;
+ case APP_GROUP_LAUNCH_MODE_GROUP:
+ return true;
+ case APP_GROUP_LAUNCH_MODE_SINGLE:
+ return false;
+ }
+
+ return false;
+}
+
+static bool __can_be_leader(bundle *b)
+{
+ char *str = NULL;
+
+ bundle_get_str(b, AUL_SVC_K_CAN_BE_LEADER, &str);
+ if (str != NULL && strcmp(str, "true") == 0)
+ return true;
+
+ return false;
+}
+
+static int __get_previous_pid(int pid)
+{
+ int previous_pid = -1;
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac == NULL) {
+ i = g_list_next(i);
+ continue;
+ }
+
+ if (ac && ac->pid == pid)
+ return previous_pid;
+
+ previous_pid = ac->pid;
+ i = g_list_next(i);
+ }
+ }
+
+ return -1;
+}
+
+static int __get_caller_pid(bundle *kb)
+{
+ const char *pid_str;
+ int pid;
+
+ pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
+ if (pid_str)
+ goto end;
+
+ pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
+ if (pid_str == NULL)
+ return -1;
+
+end:
+ pid = atoi(pid_str);
+ if (pid <= 1)
+ return -1;
+
+ return pid;
+}
+
+static app_group_context_t *__detach_context_from_recycle_bin(int pid)
+{
+ GList *iter = recycle_bin;
+ app_group_context_t *ac;
+
+ while (iter) {
+ ac = (app_group_context_t *)iter->data;
+ if (ac && ac->pid == pid) {
+ recycle_bin = g_list_delete_link(recycle_bin, iter);
+ return ac;
+ }
+
+ iter = g_list_next(iter);
+ }
+
+ return NULL;
+
+}
+
+static void __group_add(int leader_pid, int pid, int wid,
+ app_group_launch_mode mode, int caller_pid, int can_shift,
+ int recycle)
+{
+ app_group_context_t *ac = NULL;
+ GList *list;
+ GList *tmp_list;
+
+ ac = __detach_context_from_recycle_bin(pid);
+ if (ac == NULL) {
+ ac = malloc(sizeof(app_group_context_t));
+ if (ac == NULL) {
+ _E("out of memory");
+ return;
+ }
+ ac->pid = pid;
+ ac->wid = wid;
+ ac->fg = 0;
+ ac->can_be_leader = 0;
+ ac->reroute = 0;
+ ac->launch_mode = mode;
+ ac->caller_pid = caller_pid;
+ ac->can_shift = can_shift;
+ ac->recycle = recycle;
+ }
+
+ if (leader_pid == pid || ac->recycle)
+ ac->group_sig = 1;
+ else
+ ac->group_sig = 0;
+
+ dead_pid = -1;
+
+ list = (GList *)g_hash_table_lookup(app_group_hash,
+ GINT_TO_POINTER(leader_pid));
+ if (list != NULL) {
+ tmp_list = g_list_find_custom(list, GINT_TO_POINTER(pid),
+ __comp_pid);
+ if (tmp_list != NULL) {
+ _E("pid exist");
+ free(ac);
+ return;
+ }
+ }
+
+ list = g_list_append(list, ac);
+ g_hash_table_insert(app_group_hash, GINT_TO_POINTER(leader_pid), list);
+
+ if (ac->wid != 0)
+ _app_group_set_window(pid, ac->wid);
+}
+
+static void __group_remove(int pid)
+{
+ int ppid = __get_previous_pid(pid);
+
+ g_hash_table_foreach_remove(app_group_hash, __hash_table_cb,
+ GINT_TO_POINTER(pid));
+
+ if (ppid != -1)
+ _app_group_set_status(ppid, -1, false);
+}
+
+static app_group_context_t *__get_context(int pid)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == pid)
+ return ac;
+
+ i = g_list_next(i);
+ }
+ }
+
+ return NULL;
+}
+
+static int __can_recycle(int pid)
+{
+ app_group_context_t *context = __get_context(pid);
+
+ if (context)
+ return context->recycle;
+
+ return 0;
+}
+
+static int __can_reroute(int pid)
+{
+ app_group_context_t *context = __get_context(pid);
+
+ if (context)
+ return context->reroute;
+
+ return 0;
+}
+
+static app_group_context_t *__context_dup(const app_group_context_t *context)
+{
+ app_group_context_t *dup;
+
+ if (!context) {
+ _E("context is NULL.");
+ return NULL;
+ }
+
+ dup = malloc(sizeof(app_group_context_t));
+ if (!dup) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ memcpy(dup, context, sizeof(app_group_context_t));
+ return dup;
+}
+
+static void __do_recycle(app_group_context_t *context)
+{
+ const char *appid;
+ const char *pkgid;
+ const struct appinfo *ai;
+ app_status_h app_status;
+ uid_t uid;
+
+ app_status = _app_status_find(context->pid);
+ uid = _app_status_get_uid(app_status);
+
+ if (context->fg) {
+ appid = _app_status_get_appid(app_status);
+ ai = _appinfo_find(uid, appid);
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+
+ _D("send_signal BG %s", appid);
+ aul_send_app_status_change_signal(context->pid, appid, pkgid,
+ STATUS_BACKGROUND, APP_TYPE_UI);
+ _app_status_find_service_apps(app_status, STATUS_BG,
+ __prepare_to_suspend_services, true);
+ context->fg = 0;
+ }
+ recycle_bin = g_list_append(recycle_bin, context);
+ _temporary_permission_drop(context->pid, uid);
+}
+
+void _app_group_remove(int pid)
+{
+ app_group_context_t *context;
+
+ __group_remove(pid);
+ context = __detach_context_from_recycle_bin(pid);
+ if (context)
+ free(context);
+}
+
+void _app_group_remove_from_recycle_bin(int pid)
+{
+ app_group_context_t *context = __detach_context_from_recycle_bin(pid);
+
+ if (context)
+ free(context);
+}
+
+int _app_group_get_window(int pid)
+{
+ app_group_context_t *context = __get_context(pid);
+
+ if (context)
+ return context->wid;
+
+ return -1;
+}
+
+int _app_group_set_window(int pid, int wid)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ int previous_wid;
+ int caller_wid;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ previous_wid = 0;
+ while (i != NULL) {
+ ac = (app_group_context_t *) i->data;
+ if (ac == NULL) {
+ i = g_list_next(i);
+ continue;
+ }
+
+ if (ac && ac->pid == pid) {
+ ac->wid = wid;
+ if (previous_wid != 0)
+ __attach_window(previous_wid, wid);
+
+ if (ac->can_shift && ac->caller_pid > 0) {
+ caller_wid = _app_group_get_window(
+ ac->caller_pid);
+ if (caller_wid != 0) {
+ __attach_window(caller_wid,
+ wid);
+ }
+ }
+
+ i = g_list_next(i);
+ if (i) {
+ ac = (app_group_context_t *)i->data;
+ if (ac->wid != 0)
+ __attach_window(wid, ac->wid);
+ }
+
+ return 0;
+ }
+ previous_wid = ac->wid;
+ i = g_list_next(i);
+ }
+ }
+
+ return -1;
+}
+
+void _app_group_clear_top(int pid, uid_t uid)
+{
+ int p;
+ int wid;
+ GList *list;
+ GList *itr;
+
+ list = __find_removable_apps(pid);
+ if (list != NULL) {
+ itr = g_list_last(list);
+ while (itr != NULL) {
+ p = GPOINTER_TO_INT(itr->data);
+ if (p > 0) {
+ wid = _app_group_get_window(p);
+ __detach_window(wid);
+ aul_send_app_terminate_request_signal(p,
+ NULL, NULL, NULL);
+ _term_sub_app(p, uid);
+ _app_group_remove(p);
+ }
+ itr = g_list_previous(itr);
+ }
+ g_list_free(list);
+ }
+}
+
+bool _app_group_is_group_app(bundle *kb, uid_t uid)
+{
+ char *str = NULL;
+ const char *mode;
+ char *appid = NULL;
+ const struct appinfo *ai;
+
+ if (kb == NULL)
+ return false;
+
+ bundle_get_str(kb, AUL_K_APPID, &appid);
+ if (appid == NULL)
+ return false;
+
+ ai = _appinfo_find(uid, appid);
+ mode = _appinfo_get_value(ai, AIT_LAUNCH_MODE);
+
+ if (mode != NULL && (strcmp(mode, "caller") == 0 ||
+ strcmp(mode, "singleton") == 0)) {
+ bundle_get_str(kb, APP_SVC_K_LAUNCH_MODE, &str);
+ if (str != NULL && strcmp(str, "group") == 0)
+ return true;
+ } else if (mode != NULL && strcmp(mode, "group") == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+void _app_group_get_leader_pids(int *cnt, int **pids)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ int size = g_hash_table_size(app_group_hash);
+ int *leader_pids;
+ int i;
+
+ if (size > 0) {
+ leader_pids = (int *)malloc(sizeof(int) * size);
+ if (leader_pids == NULL) {
+ _E("out of memory");
+ *cnt = 0;
+ *pids = NULL;
+ return;
+ }
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ i = 0;
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ leader_pids[i] = GPOINTER_TO_INT(key);
+ i++;
+ }
+
+ *cnt = size;
+ *pids = leader_pids;
+ } else {
+ *cnt = 0;
+ *pids = NULL;
+ }
+}
+
+bool _app_group_is_leader_pid(int pid)
+{
+ int cnt;
+ int *pids = NULL;
+ int i;
+
+ _app_group_get_leader_pids(&cnt, &pids);
+ for (i = 0; i < cnt; i++) {
+ if (pid == pids[i]) {
+ free(pids);
+ return true;
+ }
+ }
+
+ if (pids != NULL)
+ free(pids);
+
+ return false;
+}
+
+void _app_group_get_group_pids(int leader_pid, int *cnt, int **pids)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ int size;
+ int *pid_array;
+ int j;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ if (GPOINTER_TO_INT(key) == leader_pid) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ size = g_list_length(list);
+
+ if (size > 0) {
+ j = 0;
+ pid_array = (int *)malloc(sizeof(int) * size);
+ if (pid_array == NULL) {
+ _E("out of memory");
+ *cnt = 0;
+ *pids = NULL;
+ return;
+ }
+
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ pid_array[j] = ac->pid;
+ i = g_list_next(i);
+ j++;
+ }
+
+ *cnt = size;
+ *pids = pid_array;
+ } else {
+ *cnt = 0;
+ *pids = NULL;
+ }
+ return;
+ }
+ }
+
+ *cnt = 0;
+ *pids = NULL;
+}
+
+bool _app_group_is_sub_app(int pid)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *found;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ if (list != NULL) {
+ found = g_list_find_custom(list, GINT_TO_POINTER(pid),
+ __comp_pid);
+ if (found) {
+ if (g_list_first(list) == found)
+ return false;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void _app_group_reroute(int pid)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *found;
+ GList *before;
+ GList *after;
+ app_group_context_t *ac1;
+ app_group_context_t *ac2;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ if (list != NULL) {
+ found = g_list_find_custom(list, GINT_TO_POINTER(pid),
+ __comp_pid);
+ if (found) {
+ before = g_list_previous(found);
+ after = g_list_next(found);
+ if (before == NULL || after == NULL)
+ return;
+
+ _D("reroute");
+ ac1 = (app_group_context_t *)before->data;
+ ac2 = (app_group_context_t *)after->data;
+
+ __attach_window(ac1->wid, ac2->wid);
+ break;
+ }
+ }
+ }
+}
+
+int _app_group_get_leader_pid(int pid)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *found;
+ int lpid = -1;
+ int again = 0;
+
+repeat:
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ if (list != NULL) {
+ found = g_list_find_custom(list, GINT_TO_POINTER(pid),
+ __comp_pid);
+ if (found) {
+ lpid = GPOINTER_TO_INT(key);
+ break;
+ }
+ }
+ }
+
+ if (lpid == -1 && dead_pid == pid)
+ lpid = focused_leader_pid;
+
+ if (lpid == -1 && again == 0) {
+ pid = getpgid(pid);
+ again = 1;
+ goto repeat;
+ }
+
+ return lpid;
+}
+
+void _app_group_set_dead_pid(int pid)
+{
+ focused_leader_pid = _app_group_get_leader_pid(pid);
+ dead_pid = pid;
+ if (dead_pid == focused_leader_pid) {
+ focused_leader_pid = -1;
+ dead_pid = -1;
+ }
+}
+
+int _app_group_get_status(int pid)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == pid)
+ return ac->status;
+
+ i = g_list_next(i);
+ }
+ }
+ return -1;
+}
+
+static void __set_status(app_group_context_t *ac, app_group_context_t *last_ac,
+ int lpid, int pid, int status, bool force)
+{
+ const char *pkgid;
+ app_status_h app_status;
+
+ if (status > 0)
+ ac->status = status;
+
+ if (last_ac->wid != 0 || status == STATUS_VISIBLE || force == TRUE) {
+ if (__is_visible(pid)) {
+ __set_fg_flag(pid, 1, force);
+ if (!ac->group_sig && lpid != pid) {
+ app_status = _app_status_find(pid);
+ pkgid = _app_status_get_pkgid(app_status);
+ _D("send group signal %d", pid);
+ aul_send_app_group_signal(lpid, pid, pkgid);
+ ac->group_sig = 1;
+ }
+ } else {
+ __set_fg_flag(pid, 0, force);
+ }
+ }
+}
+
+int _app_group_set_status(int pid, int status, bool force)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ app_group_context_t *ac;
+ GList *last;
+ app_group_context_t *last_ac;
+ int lpid;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ last = g_list_last(list);
+ last_ac = (app_group_context_t *)last->data;
+ lpid = GPOINTER_TO_INT(key);
+ i = g_list_first(list);
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == pid) {
+ __set_status(ac, last_ac, lpid, pid, status,
+ force);
+ return 0;
+ }
+ i = g_list_next(i);
+ }
+ }
+ return -1;
+}
+
+int _app_group_get_fg_flag(int pid)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == pid)
+ return ac->fg;
+
+ i = g_list_next(i);
+ }
+ }
+
+ return 0;
+}
+
+int _app_group_set_hint(int pid, bundle *kb)
+{
+ char *str_leader = NULL;
+ char *str_reroute = NULL;
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ app_group_context_t *ac;
+
+ if (kb == NULL)
+ return -1;
+
+ bundle_get_str(kb, AUL_SVC_K_CAN_BE_LEADER, &str_leader);
+ bundle_get_str(kb, AUL_SVC_K_REROUTE, &str_reroute);
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == pid) {
+ if (str_leader && !strcmp(str_leader, "true"))
+ ac->can_be_leader = 1;
+ if (str_reroute && !strcmp(str_reroute, "true"))
+ ac->reroute = 1;
+ return 0;
+ }
+ i = g_list_next(i);
+ }
+ }
+
+ return -1;
+}
+
+int _app_group_find_second_leader(int lpid)
+{
+ app_group_context_t *ac;
+ GList *list;
+
+ list = (GList *)g_hash_table_lookup(app_group_hash,
+ GINT_TO_POINTER(lpid));
+ if (list != NULL) {
+ list = g_list_next(list);
+ if (list != NULL) {
+ ac = (app_group_context_t *)list->data;
+ if (ac && ac->can_be_leader) {
+ _W("found the second leader, lpid: %d, pid: %d",
+ lpid, ac->pid);
+ return ac->pid;
+ }
+ }
+ }
+
+ return -1;
+}
+
+void _app_group_remove_leader_pid(int lpid)
+{
+ app_group_context_t *ac;
+ GList *next;
+ GList *list;
+
+ list = (GList *)g_hash_table_lookup(app_group_hash,
+ GINT_TO_POINTER(lpid));
+ if (list != NULL) {
+ next = g_list_next(list);
+ if (next != NULL) {
+ ac = (app_group_context_t *)list->data;
+ if (ac)
+ free(ac);
+ list = g_list_delete_link(list, list);
+ ac = (app_group_context_t *)next->data;
+ g_hash_table_insert(app_group_hash,
+ GINT_TO_POINTER(ac->pid), next);
+ g_hash_table_remove(app_group_hash,
+ GINT_TO_POINTER(lpid));
+ }
+ }
+}
+
+int _app_group_can_start_app(const char *appid, bundle *b, bool *can_attach,
+ int *lpid, app_group_launch_mode *mode, uid_t uid)
+{
+ const char *val;
+ int caller_pid;
+ int caller_wid;
+
+ *can_attach = false;
+ if (__can_attach_window(b, appid, mode, uid)) {
+ *can_attach = true;
+ val = bundle_get_val(b, AUL_K_ORG_CALLER_PID);
+ if (val == NULL)
+ val = bundle_get_val(b, AUL_K_CALLER_PID);
+
+ if (val == NULL) {
+ _E("no caller pid");
+ return -1;
+ }
+
+ caller_pid = atoi(val);
+ *lpid = _app_group_get_leader_pid(caller_pid);
+ if (*lpid != -1) {
+ caller_wid = _app_group_get_window(caller_pid);
+ if (caller_wid == 0) {
+ _D("caller window wasn't ready");
+ if (__can_be_leader(b))
+ *can_attach = false;
+ else
+ *can_attach = true;
+ }
+ } else {
+ _E("no lpid");
+ if (__can_be_leader(b))
+ *can_attach = false;
+ else
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void _app_group_start_app(int pid, bundle *b, int lpid, bool can_attach,
+ app_group_launch_mode mode)
+{
+ int caller_pid = __get_caller_pid(b);
+ int can_shift = 0;
+ int recycle = 0;
+ const char *str;
+
+ _D("app_group_start_app");
+
+ str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW);
+ if (str != NULL && strcmp(str, "true") == 0)
+ can_shift = 1;
+
+ str = bundle_get_val(b, AUL_SVC_K_RECYCLE);
+ if (str != NULL && strcmp(str, "true") == 0)
+ recycle = 1;
+
+ if (can_attach)
+ __group_add(lpid, pid, 0, mode, caller_pid, 0, recycle);
+ else
+ __group_add(pid, pid, 0, mode, caller_pid, can_shift, 0);
+ _app_group_set_hint(pid, b);
+}
+
+int _app_group_find_singleton(const char *appid, int *found_pid,
+ int *found_lpid)
+{
+ GHashTableIter iter;
+ gpointer key = NULL;
+ gpointer value = NULL;
+ app_status_h app_status;
+ const char *target;
+ GList *list;
+ app_group_context_t *ac;
+ int singleton = APP_GROUP_LAUNCH_MODE_SINGLETON;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ while (list != NULL) {
+ ac = (app_group_context_t *)list->data;
+ if (ac && ac->launch_mode == singleton) {
+ app_status = _app_status_find(ac->pid);
+ target = _app_status_get_appid(app_status);
+ if (appid && target && !strcmp(appid, target)) {
+ *found_pid = ac->pid;
+ *found_lpid = GPOINTER_TO_INT(key);
+ return 0;
+ }
+ }
+ list = g_list_next(list);
+ }
+ }
+
+ return -1;
+}
+
+int _app_group_can_reroute(int pid)
+{
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == pid)
+ return ac->reroute;
+
+ i = g_list_next(i);
+ }
+ }
+
+ return 0;
+}
+
+void _app_group_lower(int pid, int *exit)
+{
+ app_group_context_t *ac;
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ GList *list;
+ GList *i;
+
+ if (_app_group_is_sub_app(pid)) {
+ if (__can_recycle(pid) && __can_reroute(pid)) {
+ ac = __get_context(pid);
+ if (ac) {
+ _app_group_reroute(pid);
+
+ if (ac->wid != 0)
+ __detach_window(ac->wid);
+
+ ac = __context_dup(ac);
+ __group_remove(pid);
+ if (ac)
+ __do_recycle(ac);
+ }
+ *exit = 0;
+ } else
+ *exit = 1;
+ return;
+ }
+
+ *exit = 0;
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+
+ if (ac && ac->pid == pid) {
+ if (ac->can_shift) {
+ __detach_window(ac->wid);
+ ac->can_shift = 0;
+ __lower_window(ac->wid);
+ }
+ return;
+ }
+ i = g_list_next(i);
+ }
+ }
+}
+
+static void __restart_app(app_group_context_t *ac, int pid, bundle *b)
+{
+ const char *pid_str;
+ int cwid;
+
+ ac->caller_pid = __get_caller_pid(b);
+
+ if (ac->can_shift) {
+ if (ac->wid != 0)
+ __detach_window(ac->wid);
+ ac->can_shift = 0;
+ }
+
+ pid_str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW);
+ if (pid_str && !strcmp(pid_str, "true")) {
+ ac->can_shift = 1;
+ if (ac->wid != 0) {
+ if (ac->caller_pid > 0) {
+ cwid = _app_group_get_window(ac->caller_pid);
+ if (cwid != 0)
+ __attach_window(cwid, ac->wid);
+ else
+ _E("invalid caller wid");
+ } else {
+ _E("invalid caller pid");
+ }
+ }
+ }
+}
+
+void _app_group_restart_app(int pid, bundle *b)
+{
+ GList *list;
+ GList *i;
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ app_group_context_t *ac;
+
+ if (b == NULL)
+ return;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == pid) {
+ __restart_app(ac, pid, b);
+ return;
+ }
+ i = g_list_next(i);
+ }
+ }
+}
+
+int _app_group_find_pid_from_recycle_bin(const char *appid)
+{
+ app_group_context_t *ac;
+ app_status_h app_status;
+ const char *appid_from_bin;
+ GList *iter = recycle_bin;
+
+ while (iter) {
+ ac = (app_group_context_t *)iter->data;
+ app_status = _app_status_find(ac->pid);
+ appid_from_bin = _app_status_get_appid(app_status);
+ if (appid && appid_from_bin && !strcmp(appid, appid_from_bin))
+ return ac->pid;
+
+ iter = g_list_next(iter);
+ }
+
+ return -1;
+}
+
+void _app_group_get_idle_pids(int *cnt, int **pids)
+{
+ GList *iter = recycle_bin;
+ int idle_cnt = g_list_length(iter);
+ int *idle_pids;
+ int i = 0;
+ app_group_context_t *ac;
+
+ if (idle_cnt <= 0) {
+ *cnt = 0;
+ *pids = NULL;
+ return;
+ }
+
+ idle_pids = (int *)malloc(sizeof(int) * idle_cnt);
+ if (idle_pids == NULL) {
+ _E("Out-of-memory");
+ *cnt = 0;
+ *pids = NULL;
+ return;
+ }
+
+ while (iter) {
+ ac = (app_group_context_t *)iter->data;
+ idle_pids[i] = ac->pid;
+ iter = g_list_next(iter);
+ i++;
+ }
+
+ *cnt = idle_cnt;
+ *pids = idle_pids;
+}
+
+int _app_group_get_next_caller_pid(int pid)
+{
+ GList *list;
+ GList *i;
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ app_group_context_t *ac;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ list = (GList *)value;
+ i = g_list_first(list);
+ while (i != NULL) {
+ ac = (app_group_context_t *)i->data;
+ if (ac && ac->pid == pid) {
+ i = g_list_next(i);
+ if (i == NULL)
+ return -1;
+
+ ac = (app_group_context_t *)i->data;
+ return ac->caller_pid;
+ }
+ i = g_list_next(i);
+ }
+ }
+
+ return -1;
+}
+
+int _app_group_activate_below(int pid, const char *below_appid)
+{
+ app_group_context_t *context = __get_context(pid);
+ int wid;
+ int tpid;
+ GList *list;
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ app_status_h app_status;
+ const char *appid;
+
+ if (!context) {
+ _E("Invalid pid");
+ return -1;
+ }
+
+ if (context->wid == 0) {
+ _E("Caller wid was 0");
+ return -1;
+ }
+
+ if (!below_appid) {
+ _E("below_appid was null");
+ return -1;
+ }
+
+ wid = context->wid;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ tpid = GPOINTER_TO_INT(key);
+ app_status = _app_status_find(tpid);
+ appid = _app_status_get_appid(app_status);
+ if (appid && strcmp(appid, below_appid) == 0) {
+ list = (GList *)value;
+ context = (app_group_context_t *)list->data;
+ __activate_below(wid, context->wid);
+ return 0;
+ }
+ }
+
+ _E("Failed to find available appid to move");
+ return -1;
+}
+
+int _app_group_activate_above(int pid, const char *above_appid)
+{
+ app_group_context_t *context = __get_context(pid);
+ int wid;
+ int tpid;
+ GList *list;
+ GHashTableIter iter;
+ gpointer key;
+ gpointer value;
+ app_status_h app_status;
+ const char *appid;
+
+ if (!context) {
+ _E("Invalid pid");
+ return -1;
+ }
+
+ if (context->wid == 0) {
+ _E("Caller wid was 0");
+ return -1;
+ }
+
+ if (!above_appid) {
+ _E("below_appid was null");
+ return -1;
+ }
+
+ wid = context->wid;
+
+ g_hash_table_iter_init(&iter, app_group_hash);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ tpid = GPOINTER_TO_INT(key);
+ app_status = _app_status_find(tpid);
+ appid = _app_status_get_appid(app_status);
+ if (appid && strcmp(appid, above_appid) == 0) {
+ list = (GList *)value;
+ context = (app_group_context_t *)list->data;
+ __activate_above(wid, context->wid);
+ return 0;
+ }
+ }
+
+ _E("Failed to find available appid to move");
+ return -1;
+}
+
+int _app_group_attach(const char *parent_appid, const char *child_appid,
+ uid_t uid)
+{
+ app_status_h status;
+ int ppid;
+ int cpid;
+ int pwid;
+ int cwid;
+
+ status = _app_status_find_by_appid(parent_appid, uid);
+ if (!status) {
+ _E("parent app is not running %s", parent_appid);
+ return -1;
+ }
+
+ ppid = _app_status_get_pid(status);
+ status = _app_status_find_by_appid(child_appid, uid);
+ if (!status) {
+ _E("child app is not running %s", child_appid);
+ return -1;
+ }
+
+ pwid = _app_group_get_window(ppid);
+ if (pwid == 0) {
+ _E("window wasn't ready - ppid(%d)", ppid);
+ return -1;
+ }
+
+ cpid = _app_status_get_pid(status);
+ cwid = _app_group_get_window(cpid);
+ if (cwid == 0) {
+ _E("window wasn't ready - cpid(%d)", cpid);
+ return -1;
+ }
+
+ __attach_window(pwid, cwid);
+
+ return 0;
+}
+
+int _app_group_detach(const char *child_appid, uid_t uid)
+{
+ app_status_h status;
+ int cpid;
+ int cwid;
+
+ status = _app_status_find_by_appid(child_appid, uid);
+ if (!status) {
+ _E("child app is not running %s", child_appid);
+ return -1;
+ }
+
+ cpid = _app_status_get_pid(status);
+ cwid = _app_group_get_window(cpid);
+ if (cwid == 0) {
+ _E("window wasn't ready : %d", cwid);
+ return -1;
+ }
+
+ __detach_window(cwid);
+
+ return 0;
+}
+
+int _app_group_init(void)
+{
+ _D("app group init");
+ _wayland_add_registry_listener(®istry_listener, NULL);
+ app_group_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, NULL);
+ if (app_group_hash == NULL) {
+ _E("Failed to create app group hash");
+ return -1;
+ }
+
+ return 0;
+}
+
+void _app_group_fini(void)
+{
+ _D("app group fini");
+ /* TODO: Destroy app group info */
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+#include <ctype.h>
+#include <gio/gio.h>
+#include <aul_svc.h>
+#include <pkgmgr-info.h>
+
+#include "amd_util.h"
+#include "amd_app_property.h"
+
+struct metadata_filter {
+ const char *key;
+ const char *value; /* Could be NULL */
+};
+
+struct metadata_entity {
+ char *appid;
+ char *key;
+ char *value;
+};
+
+struct app_property_s {
+ uid_t uid;
+ GHashTable *alias_info_table;
+ GHashTable *allowed_info_table;
+ GHashTable *appid_cache_table;
+ GList *metadata_list;
+};
+
+static GHashTable *user_prop_table;
+
+static int __foreach_allowed_info(const char *appid, const char *allowed_appid,
+ void *data);
+
+static int __add_alias_info(const char *alias_appid,
+ const char *appid, void *user_data)
+{
+ GHashTable *alias_info_table = (GHashTable *)user_data;
+ char *key;
+ char *value;
+ char *id;
+
+ if (alias_appid == NULL || appid == NULL || alias_info_table == NULL) {
+ _W("Invalid parameter");
+ return -1;
+ }
+
+ key = strdup(alias_appid);
+ if (key == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ value = strdup(appid);
+ if (value == NULL) {
+ _E("out of memory");
+ free(key);
+ return -1;
+ }
+
+ id = g_hash_table_lookup(alias_info_table, key);
+ if (id) {
+ _D("Replace alias info - alias_appid(%s), appid(%d)",
+ key, value);
+ g_hash_table_replace(alias_info_table, key, value);
+ } else {
+ g_hash_table_insert(alias_info_table, key, value);
+ }
+
+ return 0;
+}
+
+int _app_property_add_alias_info(app_property_h app_property,
+ const char *alias_appid, const char *appid)
+{
+ int ret;
+
+ if (app_property == NULL || appid == NULL) {
+ _W("Invalid parameter");
+ return -1;
+ }
+
+ if (alias_appid && appid) {
+ ret = __add_alias_info(alias_appid, appid,
+ app_property->alias_info_table);
+ if (ret < 0) {
+ _W("Failed to add alias info");
+ return -1;
+ }
+ } else if (appid) {
+ ret = aul_svc_foreach_alias_info_by_appid_for_uid(
+ __add_alias_info, appid,
+ app_property->uid,
+ app_property->alias_info_table);
+ if (ret < 0) {
+ _W("Failed to retrive alias info - appid(%s)", appid);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static gboolean __remove_alias_info(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ if (value == NULL || user_data == NULL) {
+ _W("Invalid parameter");
+ return FALSE;
+ }
+
+ if (strcmp(value, user_data) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+int _app_property_remove_alias_info(app_property_h app_property,
+ const char *alias_appid, const char *appid)
+{
+ const char *id;
+
+ if (app_property == NULL || (alias_appid == NULL && appid == NULL)) {
+ _W("Invalid parameter");
+ return -1;
+ }
+
+ if (alias_appid) {
+ id = g_hash_table_lookup(app_property->alias_info_table,
+ alias_appid);
+ if (id) {
+ g_hash_table_remove(app_property->alias_info_table,
+ alias_appid);
+ }
+ } else {
+ g_hash_table_foreach_remove(app_property->alias_info_table,
+ __remove_alias_info, (gpointer)appid);
+ }
+
+ return 0;
+}
+
+const char *_app_property_get_real_appid(app_property_h app_property,
+ const char *alias_appid)
+{
+ if (app_property == NULL || alias_appid == NULL) {
+ _W("Invalid parameter");
+ return NULL;
+ }
+
+ return g_hash_table_lookup(app_property->alias_info_table, alias_appid);
+}
+
+GList *_app_property_get_allowed_app_list(app_property_h app_property,
+ const char *appid)
+{
+ if (app_property == NULL || appid == NULL) {
+ _W("Invalid parameter");
+ return NULL;
+ }
+
+ return g_hash_table_lookup(app_property->allowed_info_table, appid);
+}
+
+app_property_h _app_property_find(uid_t uid)
+{
+ if (user_prop_table == NULL)
+ return NULL;
+
+ return g_hash_table_lookup(user_prop_table, GUINT_TO_POINTER(uid));
+}
+
+int _app_property_insert(uid_t uid, const char *appid)
+{
+ int ret;
+ app_property_h app_property;
+
+ if (appid == NULL) {
+ _W("Invalid parameter");
+ return -1;
+ }
+
+ app_property = _app_property_find(uid);
+ if (app_property == NULL)
+ return -1;
+
+ ret = aul_svc_foreach_alias_info_by_appid_for_uid(__add_alias_info,
+ appid, app_property->uid,
+ app_property->alias_info_table);
+ if (ret < 0) {
+ _E("Failed to retrive alias info uid(%d) - ret(%d)",
+ app_property->uid, ret);
+ return -1;
+ }
+
+ ret = aul_svc_foreach_allowed_info_by_appid_for_uid(
+ __foreach_allowed_info, appid,
+ app_property->uid, app_property->allowed_info_table);
+ if (ret < 0) {
+ _E("Failed to retrive allowed info uid(%d) - ret (%d)",
+ app_property->uid, ret);
+ return -1;
+ }
+
+ _D("uid(%d), appid(%s)", uid, appid);
+
+ return 0;
+}
+
+int _app_property_delete(uid_t uid, const char *appid)
+{
+ app_property_h app_property;
+
+ if (appid == NULL) {
+ _W("Invalid parameter");
+ return -1;
+ }
+
+ app_property = _app_property_find(uid);
+ if (app_property == NULL)
+ return -1;
+
+ g_hash_table_foreach_remove(app_property->alias_info_table,
+ __remove_alias_info, (gpointer)appid);
+
+ g_hash_table_remove(app_property->allowed_info_table, appid);
+ _D("uid(%d), appid(%d)", uid, appid);
+
+ return 0;
+}
+
+static void __foreach_alias_info(const char *alias_appid, const char *appid,
+ void *data)
+{
+ GHashTable *alias_info_table = (GHashTable *)data;
+ char *key;
+ char *value;
+
+ if (alias_appid == NULL || appid == NULL || alias_info_table == NULL) {
+ _W("Invalid parameter");
+ return;
+ }
+
+ key = strdup(alias_appid);
+ if (key == NULL) {
+ _E("out of memory");
+ return;
+ }
+
+ value = strdup(appid);
+ if (value == NULL) {
+ _E("out of memory");
+ free(key);
+ return;
+ }
+
+ g_hash_table_insert(alias_info_table, key, value);
+}
+
+static int __foreach_allowed_info(const char *appid, const char *allowed_appid,
+ void *data)
+{
+ GHashTable *allowed_info_table = (GHashTable *)data;
+ char *key;
+ char *value;
+ GList *list;
+
+ if (appid == NULL || allowed_appid == NULL ||
+ allowed_info_table == NULL) {
+ _W("Invalid parameter");
+ return -1;
+ }
+
+ value = strdup(allowed_appid);
+ if (value == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ list = g_hash_table_lookup(allowed_info_table, appid);
+ if (list) {
+ list = g_list_append(list, value);
+ } else {
+ key = strdup(appid);
+ if (key == NULL) {
+ _E("out of memory");
+ free(value);
+ return -1;
+ }
+
+ list = g_list_append(list, value);
+ g_hash_table_insert(allowed_info_table, key, list);
+ }
+
+ return 0;
+}
+
+static void __destroy_allowed_info_list(gpointer data)
+{
+ GList *list = (GList *)data;
+
+ if (list == NULL)
+ return;
+
+ g_list_free_full(list, free);
+}
+
+static struct app_property_s *__create_app_property(uid_t uid)
+{
+ struct app_property_s *prop;
+
+ prop = calloc(1, sizeof(struct app_property_s));
+ if (prop == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ prop->uid = uid;
+ prop->alias_info_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ free, free);
+ if (prop->alias_info_table == NULL) {
+ _E("Failed to create alias info table");
+ free(prop);
+ return NULL;
+ }
+
+ prop->allowed_info_table = g_hash_table_new_full(g_str_hash,
+ g_str_equal, free, __destroy_allowed_info_list);
+ if (prop->allowed_info_table == NULL) {
+ _E("Failed to create allowed info table");
+ g_hash_table_destroy(prop->alias_info_table);
+ free(prop);
+ return NULL;
+ }
+
+ prop->appid_cache_table = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
+ if (prop->appid_cache_table == NULL) {
+ _E("Failed to create appid cache table");
+ g_hash_table_destroy(prop->allowed_info_table);
+ g_hash_table_destroy(prop->alias_info_table);
+ free(prop);
+ return NULL;
+ }
+
+ prop->metadata_list = NULL;
+
+ return prop;
+}
+
+static void __free_metadata_entity(gpointer data)
+{
+ struct metadata_entity *entity = data;
+
+ if (!entity)
+ return;
+
+ free(entity->appid);
+ free(entity->key);
+ free(entity->value);
+ free(entity);
+}
+
+static void __destroy_app_property(gpointer data)
+{
+ struct app_property_s *prop = (struct app_property_s *)data;
+
+ if (prop == NULL)
+ return;
+
+ if (prop->allowed_info_table)
+ g_hash_table_destroy(prop->allowed_info_table);
+ if (prop->alias_info_table)
+ g_hash_table_destroy(prop->alias_info_table);
+ if (prop->appid_cache_table)
+ g_hash_table_destroy(prop->appid_cache_table);
+ if (prop->metadata_list)
+ g_list_free_full(prop->metadata_list, __free_metadata_entity);
+
+ free(prop);
+}
+
+static gint __comp_metadata_list(gconstpointer a, gconstpointer b)
+{
+ const struct metadata_entity *entity1 = a;
+ const struct metadata_entity *entity2 = b;
+
+ if (!a || !b)
+ return -1;
+
+ if (!strcmp(entity1->appid, entity2->appid) &&
+ !strcmp(entity1->key, entity2->key) &&
+ !strcmp(entity1->value, entity2->value))
+ return 0;
+
+ return -1;
+}
+
+static void __add_metadata_info(const char *appid, const char *key,
+ const char *val, struct app_property_s *prop)
+{
+ struct metadata_entity *entity;
+
+ if (appid == NULL || key == NULL) {
+ _W("Invalid parameter");
+ return;
+ }
+
+ entity = calloc(1, sizeof(struct metadata_entity));
+ if (entity == NULL) {
+ _E("out of memory");
+ return;
+ }
+
+ entity->appid = strdup(appid);
+ if (!entity->appid) {
+ _E("out of memory");
+ goto err;
+ }
+
+ entity->key = strdup(key);
+ if (!entity->key) {
+ _E("out of memory");
+ goto err;
+ }
+
+ if (val) {
+ entity->value = strdup(val);
+ if (!entity->value) {
+ _E("out of memory");
+ goto err;
+ }
+ }
+
+ if (g_list_find_custom(prop->metadata_list, entity, __comp_metadata_list))
+ goto err;
+
+ prop->metadata_list = g_list_append(prop->metadata_list, entity);
+ return;
+
+err:
+ free(entity->appid);
+ free(entity->key);
+ free(entity->value);
+ free(entity);
+}
+
+static struct metadata_filter __metadata_table[] = {
+ { METADATA_LARGEMEMORY, NULL },
+ { METADATA_OOMTERMINATION, NULL },
+};
+
+static int __app_list_cb(pkgmgrinfo_appinfo_h handle, void *user_data)
+{
+ char *appid = NULL;
+ struct app_property_s *prop = user_data;
+ char *val;
+ int ret;
+ int i;
+ const int n = ARRAY_SIZE(__metadata_table);
+
+ pkgmgrinfo_appinfo_get_appid(handle, &appid);
+
+ if (!appid)
+ return -1;
+
+ for (i = 0; i < n; i++) {
+ val = NULL;
+ ret = pkgmgrinfo_appinfo_get_metadata_value(handle,
+ __metadata_table[i].key, &val);
+ if (ret == PMINFO_R_OK) {
+ __add_metadata_info(appid,
+ __metadata_table[i].key,
+ val, prop);
+ }
+ }
+
+ return 0;
+}
+
+static int __load_metadata(struct app_property_s *prop)
+{
+ int ret;
+ pkgmgrinfo_appinfo_metadata_filter_h handle;
+ int i;
+ const int n = ARRAY_SIZE(__metadata_table);
+
+ ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
+ if (ret != PMINFO_R_OK)
+ return -1;
+
+ for (i = 0; i < n; i++) {
+ ret = pkgmgrinfo_appinfo_metadata_filter_add(handle,
+ __metadata_table[i].key,
+ __metadata_table[i].value);
+ if (ret != PMINFO_R_OK) {
+ pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+ return -1;
+ }
+ }
+
+ ret = pkgmgrinfo_appinfo_usr_metadata_filter_foreach(handle,
+ __app_list_cb, prop, prop->uid);
+ if (ret != PMINFO_R_OK) {
+ pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+ return -1;
+ }
+
+ ret = pkgmgrinfo_appinfo_usr_metadata_filter_foreach(handle,
+ __app_list_cb, prop, GLOBAL_USER);
+ if (ret != PMINFO_R_OK) {
+ pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+ return -1;
+ }
+
+ pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+
+ return 0;
+}
+
+static int __load_app_property(struct app_property_s *prop)
+{
+ int ret;
+
+ if (prop == NULL) {
+ _W("Invalid parameter");
+ return -1;
+ }
+
+ ret = aul_svc_foreach_alias_info_for_uid(__foreach_alias_info,
+ prop->uid, prop->alias_info_table);
+ if (ret < 0) {
+ _E("Failed to retrive alias info uid(%d) - ret(%d)",
+ prop->uid, ret);
+ return -1;
+ }
+
+ ret = aul_svc_foreach_allowed_info_for_uid(__foreach_allowed_info,
+ prop->uid, prop->allowed_info_table);
+ if (ret < 0) {
+ _E("Failed to retrive allowed info uid(%d) - ret(%d)",
+ prop->uid, ret);
+ return -1;
+ }
+
+ ret = __load_metadata(prop);
+ if (ret < 0) {
+ _E("Failed to retrive metadata info uid(%d) - ret(%d)",
+ prop->uid, ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+int _app_property_load(uid_t uid)
+{
+ int ret;
+ struct app_property_s *prop;
+
+ prop = __create_app_property(uid);
+ if (prop == NULL)
+ return -1;
+
+ ret = __load_app_property(prop);
+ if (ret < 0) {
+ _E("Failed to load properties - ret(%d)", ret);
+ __destroy_app_property(prop);
+ return -1;
+ }
+
+ g_hash_table_insert(user_prop_table, GUINT_TO_POINTER(uid), prop);
+
+ return 0;
+}
+
+void _app_property_unload(uid_t uid)
+{
+ g_hash_table_remove(user_prop_table, GUINT_TO_POINTER(uid));
+}
+
+int _app_property_init(void)
+{
+ _D("app property init");
+
+ user_prop_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, __destroy_app_property);
+ if (user_prop_table == NULL) {
+ _E("Failed to create user prop table");
+ return -1;
+ }
+
+ return 0;
+}
+
+void _app_property_fini(void)
+{
+ _D("app property fini");
+
+ if (user_prop_table)
+ g_hash_table_destroy(user_prop_table);
+}
+
+void _app_property_cache_put(app_property_h app_property, const char *checksum, const char *appid)
+{
+ if (!app_property || !checksum || !appid)
+ return;
+
+ g_hash_table_replace(app_property->appid_cache_table, strdup(checksum), strdup(appid));
+}
+
+const char *_app_property_cache_get(app_property_h app_property, const char *checksum)
+{
+ const char *appid;
+
+ if (!app_property || !checksum)
+ return NULL;
+
+ appid = g_hash_table_lookup(app_property->appid_cache_table, checksum);
+
+ return appid;
+}
+
+void _app_property_cache_invalidate(app_property_h app_property)
+{
+ if (app_property)
+ g_hash_table_remove_all(app_property->appid_cache_table);
+}
+
+bool _app_property_metadata_query_bool(app_property_h app_property,
+ const char *appid, const char *key)
+{
+ return _app_property_metadata_match(app_property, appid, key, "true");
+}
+
+int _app_property_metadata_foreach(app_property_h app_property,
+ const char *appid, const char *key,
+ int (*callback)(const char *value, void *data),
+ void *user_data)
+{
+ struct metadata_entity *ret;
+ GList *i;
+
+ if (!app_property || !appid || !key)
+ return -1;
+
+ i = app_property->metadata_list;
+ while (i) {
+ ret = i->data;
+
+ if (!strcmp(ret->appid, appid) &&
+ strcmp(ret->key, key)) {
+ if (callback(ret->value, user_data) < 0)
+ break;
+ }
+
+ i = g_list_next(i);
+ }
+
+ return 0;
+}
+
+bool _app_property_metadata_match(app_property_h app_property,
+ const char *appid, const char *key, const char *value)
+{
+ struct metadata_entity entity;
+ GList *i;
+
+ if (!app_property || !appid || !key || !value)
+ return false;
+
+ entity.appid = (char *)appid;
+ entity.key = (char *)key;
+ entity.value = (char *)value;
+ i = g_list_find_custom(app_property->metadata_list,
+ &entity, __comp_metadata_list);
+ if (!i)
+ return false;
+
+ return true;
+}
+
+static gint __comp_key(gconstpointer a, gconstpointer b)
+{
+ const struct metadata_entity *entity1 = a;
+ const struct metadata_entity *entity2 = b;
+
+ if (!a || !b)
+ return -1;
+
+ if (!strcmp(entity1->appid, entity2->appid) &&
+ !strcmp(entity1->key, entity2->key)) {
+ if (entity1->value && !strcmp(entity1->value, "false"))
+ return -1;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+bool _app_property_metadata_query_activation(app_property_h app_property,
+ const char *appid, const char *key)
+{
+ struct metadata_entity entity;
+ GList *i;
+
+ if (!app_property || !appid || !key)
+ return false;
+
+ entity.appid = (char *)appid;
+ entity.key = (char *)key;
+ entity.value = NULL;
+ i = g_list_find_custom(app_property->metadata_list,
+ &entity, __comp_key);
+
+ if (!i)
+ return false;
+
+ return true;
+}
+
+
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <glib.h>
+#include <aul.h>
+#include <string.h>
+#include <linux/limits.h>
+#include <vconf.h>
+#include <time.h>
+#include <aul_sock.h>
+#include <aul_proc.h>
+#include <ctype.h>
+#include <gio/gio.h>
+#include <bundle_internal.h>
+
+#include "amd_app_status.h"
+#include "amd_appinfo.h"
+#include "amd_request.h"
+#include "amd_launch.h"
+#include "amd_util.h"
+#include "amd_app_group.h"
+#include "amd_input.h"
+#include "amd_suspend.h"
+#include "amd_socket.h"
+#include "amd_share.h"
+#include "amd_extractor.h"
+#include "amd_app_com.h"
+#include "amd_widget.h"
+#include "amd_screen_connector.h"
+#include "amd_cooldown.h"
+#include "amd_inotify.h"
+
+struct pkg_status_s {
+ char *pkgid;
+ int status;
+ GSList *ui_list;
+ GSList *svc_list;
+};
+
+struct app_status_s {
+ char *appid;
+ char *app_path;
+ char *pkgid;
+ char *instance_id;
+ int app_type;
+ int pid;
+ uid_t uid;
+ int status;
+ bool is_subapp;
+ int leader_pid;
+ int timestamp;
+ int fg_count;
+ bool managed;
+ int org_caller_pid;
+ int last_caller_pid;
+ struct pkg_status_s *pkg_status;
+ GList *shared_info_list;
+ bool bg_launch;
+ bool socket_exists;
+ bool starting;
+ bool is_exit_notified;
+ bool debug_mode;
+ guint timer;
+};
+
+struct fault_app_s {
+ int pid;
+ int uid;
+ char *appid;
+ char *pkgid;
+ int type;
+};
+
+static GHashTable *oom_app_table;
+static GHashTable *pkg_update_app_table;
+static GSList *app_status_list;
+static GHashTable *pkg_status_table;
+static int limit_bg_uiapps;
+static char *home_appid;
+static GHashTable *__wd_table;
+
+int _app_status_set_is_exit_notified(app_status_h app_status, bool is_exit_notified)
+{
+ if (app_status == NULL)
+ return -1;
+
+ app_status->is_exit_notified = is_exit_notified;
+
+ return 0;
+}
+
+bool _app_status_get_is_exit_notified(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return false;
+
+ return app_status->is_exit_notified;
+}
+
+static void __send_fault_dead_signal(int pid, int uid, const char *appid,
+ int type, bool is_exit_notified)
+{
+ char *endpoint = NULL;
+ char sender_pid_str[MAX_PID_STR_BUFSZ];
+ bundle *kb;
+
+ if (type == AT_WATCH_APP)
+ endpoint = "watch.dead";
+
+ if (endpoint == NULL)
+ return;
+
+ kb = bundle_create();
+ if (!kb) {
+ _E("cannot create bundle out of memory");
+ return;
+ }
+
+ _D("send pid %d uid %d appid %s type %d is_exit_notified %d",
+ pid, uid, appid, type, is_exit_notified);
+
+ snprintf(sender_pid_str, MAX_PID_STR_BUFSZ, "%d", pid);
+ bundle_add(kb, AUL_K_APPID, appid);
+ bundle_add(kb, AUL_K_PID, sender_pid_str);
+ bundle_add(kb, AUL_K_IS_FAULT, (is_exit_notified == true) ? "false" : "true");
+
+ _app_com_send(endpoint, getpgid(pid), kb, uid);
+}
+
+void _app_status_fault_recovery(int pid, int uid, const char *pkgid,
+ const char *appid, int type, bool is_exit_notified)
+{
+ struct fault_app_s *app_info;
+
+ if (_util_check_oom()) {
+ app_info =
+ g_hash_table_lookup(
+ oom_app_table,
+ appid);
+ if (app_info == NULL) {
+ app_info = (struct fault_app_s *)
+ calloc(1, sizeof(struct fault_app_s));
+ app_info->appid = strdup(appid);
+ app_info->pkgid = strdup(pkgid);
+ app_info->pid = pid;
+ app_info->uid = uid;
+ app_info->type = type;
+ g_hash_table_insert(
+ oom_app_table,
+ app_info->appid,
+ app_info);
+ }
+ } else if (_appinfo_is_pkg_updating(pkgid)) {
+ app_info =
+ g_hash_table_lookup(
+ pkg_update_app_table,
+ appid);
+ if (app_info == NULL) {
+ app_info = (struct fault_app_s *)
+ calloc(1, sizeof(struct fault_app_s));
+ app_info->appid = strdup(appid);
+ app_info->pkgid = strdup(pkgid);
+ app_info->pid = pid;
+ app_info->uid = uid;
+ app_info->type = type;
+ g_hash_table_insert(
+ pkg_update_app_table,
+ app_info->pkgid,
+ app_info);
+ }
+ } else {
+ __send_fault_dead_signal(pid, uid, appid, type, is_exit_notified);
+ }
+}
+
+static void __destroy_fault_app_info(gpointer data)
+{
+ struct fault_app_s *info =
+ (struct fault_app_s *)data;
+
+ if (info == NULL)
+ return;
+ if (info->appid)
+ free(info->appid);
+ if (info->pkgid)
+ free(info->pkgid);
+
+ free(info);
+}
+
+void _app_status_send_fault_dead_for_oom_apps(void)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ struct fault_app_s *info;
+
+ g_hash_table_iter_init(&iter, oom_app_table);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ info = (struct fault_app_s *)value;
+ __send_fault_dead_signal(info->pid, info->uid, info->appid,
+ info->type, false);
+ }
+ g_hash_table_remove_all(oom_app_table);
+
+}
+
+void _app_status_send_fault_dead_for_update_app(const char *pkgid)
+{
+ struct fault_app_s *info;
+
+ info = g_hash_table_lookup(pkg_update_app_table, pkgid);
+ if (info != NULL) {
+ __send_fault_dead_signal(info->pid, info->uid, info->appid,
+ info->type, false);
+ g_hash_table_remove(pkg_update_app_table, pkgid);
+ }
+}
+
+static int __get_managed_uiapp_cnt(void)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+ int cnt = 0;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->managed &&
+ app_status->app_type == AT_UI_APP)
+ cnt++;
+ }
+
+ return cnt;
+}
+
+static void __cleanup_bg_uiapps(int n)
+{
+ GSList *iter;
+ GSList *iter_next;
+ struct app_status_s *app_status;
+ int i = 0;
+ int ret;
+
+ GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+ if (i == n)
+ break;
+
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->status != STATUS_VISIBLE) {
+ ret = _terminate_app_local(app_status->uid,
+ app_status->pid);
+ if (ret < 0) {
+ _E("Failed to terminate app(%d)",
+ app_status->pid);
+ continue;
+ }
+ i++;
+ }
+ }
+}
+
+static gint __compare_app_status_for_sorting(gconstpointer p1, gconstpointer p2)
+{
+ struct app_status_s *app_status1 = (struct app_status_s *)p1;
+ struct app_status_s *app_status2 = (struct app_status_s *)p2;
+ int app_group_cnt1;
+ int app_group_cnt2;
+ int *app_group_pids1;
+ int *app_group_pids2;
+
+ if (app_status1->app_type != AT_UI_APP ||
+ app_status2->app_type != AT_UI_APP)
+ return 0;
+
+ if (app_status1->timestamp > app_status2->timestamp)
+ return 1;
+ else if (app_status1->timestamp < app_status2->timestamp)
+ return -1;
+
+ _app_group_get_group_pids(app_status1->leader_pid, &app_group_cnt1,
+ &app_group_pids1);
+ _app_group_get_group_pids(app_status2->leader_pid, &app_group_cnt2,
+ &app_group_pids2);
+ free(app_group_pids1);
+ free(app_group_pids2);
+
+ if (app_group_cnt1 < app_group_cnt2)
+ return 1;
+ else if (app_group_cnt1 > app_group_cnt2)
+ return -1;
+
+ if (app_status1->fg_count > app_status2->fg_count)
+ return 1;
+ else if (app_status1->fg_count < app_status2->fg_count)
+ return -1;
+
+ return 0;
+}
+
+static void __check_running_uiapp_list(void)
+{
+ int len;
+ int n;
+
+ len = __get_managed_uiapp_cnt();
+ if (len <= 0)
+ return;
+
+ n = len - limit_bg_uiapps;
+ if (n <= 0)
+ return;
+
+ app_status_list = g_slist_sort(app_status_list,
+ (GCompareFunc)__compare_app_status_for_sorting);
+ __cleanup_bg_uiapps(n);
+}
+
+static void __vconf_cb(keynode_t *key, void *data)
+{
+ const char *name;
+
+ name = vconf_keynode_get_name(key);
+ if (name && strcmp(name, VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS) == 0) {
+ limit_bg_uiapps = vconf_keynode_get_int(key);
+ if (limit_bg_uiapps > 0)
+ __check_running_uiapp_list();
+ }
+}
+
+static void __update_leader_app_status(int leader_pid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+
+ if (leader_pid <= 0)
+ return;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->pid == leader_pid) {
+ app_status->timestamp = time(NULL) / 10;
+ app_status->fg_count++;
+ break;
+ }
+ }
+}
+
+static void __remove_all_shared_info(struct app_status_s *app_status)
+{
+ GList *list;
+ shared_info_t *shared_info;
+
+ if (!app_status || !app_status->shared_info_list)
+ return;
+
+ list = app_status->shared_info_list;
+ while (list) {
+ shared_info = (shared_info_t *)list->data;
+ if (shared_info) {
+ if (shared_info->owner_appid)
+ free(shared_info->owner_appid);
+ free(shared_info);
+ }
+ list = g_list_next(list);
+ }
+
+ g_list_free(app_status->shared_info_list);
+ app_status->shared_info_list = NULL;
+}
+
+static void __add_pkg_status(struct app_status_s *app_status)
+{
+ struct pkg_status_s *pkg_status;
+
+ if (app_status == NULL) {
+ _E("Invalid parameter");
+ return;
+ }
+
+ if (app_status->app_type != AT_SERVICE_APP &&
+ app_status->app_type != AT_UI_APP)
+ return;
+
+ if (pkg_status_table == NULL) {
+ pkg_status_table = g_hash_table_new(g_str_hash, g_str_equal);
+ if (pkg_status_table == NULL) {
+ _E("out of memory");
+ return;
+ }
+ }
+
+ pkg_status = g_hash_table_lookup(pkg_status_table, app_status->pkgid);
+ if (pkg_status == NULL) {
+ pkg_status = (struct pkg_status_s *)calloc(1,
+ sizeof(struct pkg_status_s));
+ if (pkg_status == NULL) {
+ _E("out of memory");
+ return;
+ }
+
+ pkg_status->pkgid = strdup(app_status->pkgid);
+ if (pkg_status->pkgid == NULL) {
+ _E("out of memory");
+ free(pkg_status);
+ return;
+ }
+
+ g_hash_table_insert(pkg_status_table, pkg_status->pkgid,
+ pkg_status);
+ }
+
+ pkg_status->status = app_status->status;
+ app_status->pkg_status = pkg_status;
+
+ if (app_status->app_type == AT_SERVICE_APP) {
+ pkg_status->svc_list = g_slist_append(pkg_status->svc_list,
+ app_status);
+ } else {
+ pkg_status->ui_list = g_slist_append(pkg_status->ui_list,
+ app_status);
+ }
+}
+
+static int __get_ui_app_status_pkg_status(struct pkg_status_s *pkg_status)
+{
+ struct app_status_s *app_status;
+ GSList *iter;
+
+ for (iter = pkg_status->ui_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status->status != STATUS_BG)
+ return app_status->status;
+ }
+
+ return STATUS_BG;
+}
+
+static int __update_pkg_status(struct app_status_s *app_status)
+{
+ struct pkg_status_s *pkg_status;
+ int ret;
+
+ if (app_status == NULL)
+ return -1;
+
+ if (pkg_status_table == NULL)
+ return -1;
+
+ pkg_status = (struct pkg_status_s *)g_hash_table_lookup(
+ pkg_status_table, app_status->pkgid);
+ if (pkg_status == NULL) {
+ _E("pkgid(%s) is not on list", app_status->pkgid);
+ return -1;
+ }
+
+ if (pkg_status->ui_list) {
+ ret = __get_ui_app_status_pkg_status(pkg_status);
+ if (ret > -1)
+ pkg_status->status = ret;
+ } else {
+ pkg_status->status = STATUS_SERVICE;
+ }
+
+ return 0;
+}
+
+static void __remove_pkg_status(struct app_status_s *app_status)
+{
+ struct pkg_status_s *pkg_status;
+
+ if (app_status == NULL) {
+ _E("Invalid parameter");
+ return;
+ }
+
+ pkg_status = g_hash_table_lookup(pkg_status_table, app_status->pkgid);
+ if (pkg_status == NULL)
+ return;
+
+ if (app_status->app_type == AT_SERVICE_APP) {
+ pkg_status->svc_list = g_slist_remove(pkg_status->svc_list,
+ app_status);
+ _D("STATUS_SERVICE: appid(%s)", app_status->appid);
+ } else {
+ pkg_status->ui_list = g_slist_remove(pkg_status->ui_list,
+ app_status);
+ _D("~STATUS_SERVICE: appid(%s)", app_status->appid);
+ }
+
+ if (!pkg_status->svc_list && !pkg_status->ui_list) {
+ g_hash_table_remove(pkg_status_table, pkg_status->pkgid);
+ if (pkg_status->pkgid)
+ free(pkg_status->pkgid);
+ free(pkg_status);
+ }
+}
+
+static void __destroy_app_status(struct app_status_s *app_status)
+{
+ if (app_status == NULL)
+ return;
+
+ if (app_status->app_type == AT_WIDGET_APP)
+ _widget_cleanup(app_status->pid, app_status->uid);
+
+ __remove_all_shared_info(app_status);
+
+ if (app_status->instance_id)
+ free(app_status->instance_id);
+ if (app_status->pkgid)
+ free(app_status->pkgid);
+ if (app_status->app_path)
+ free(app_status->app_path);
+ if (app_status->appid)
+ free(app_status->appid);
+ if (app_status->timer)
+ g_source_remove(app_status->timer);
+
+ free(app_status);
+}
+
+static int __get_app_type(const char *comp_type)
+{
+ if (comp_type == NULL)
+ return -1;
+
+ if (strcmp(comp_type, APP_TYPE_SERVICE) == 0)
+ return AT_SERVICE_APP;
+ else if (strcmp(comp_type, APP_TYPE_UI) == 0)
+ return AT_UI_APP;
+ else if (strcmp(comp_type, APP_TYPE_WIDGET) == 0)
+ return AT_WIDGET_APP;
+ else if (strcmp(comp_type, APP_TYPE_WATCH) == 0)
+ return AT_WATCH_APP;
+
+ return -1;
+}
+
+static int __app_status_set_app_info(struct app_status_s *app_status,
+ const struct appinfo *ai, int pid,
+ bool is_subapp, uid_t uid, int caller_pid,
+ bool bg_launch, const char *instance_id)
+{
+ const char *appid;
+ const char *app_path;
+ const char *pkgid;
+ const char *comp_type;
+ const char *taskmanage;
+ char buf[MAX_PACKAGE_STR_SIZE];
+
+ appid = _appinfo_get_value(ai, AIT_NAME);
+ if (appid == NULL)
+ return -1;
+
+ app_status->appid = strdup(appid);
+ if (app_status->appid == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ app_path = _appinfo_get_value(ai, AIT_EXEC);
+ if (app_path == NULL)
+ return -1;
+
+ app_status->app_path = strdup(app_path);
+ if (app_status->app_path == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ if (pkgid == NULL)
+ return -1;
+
+ app_status->pkgid = strdup(pkgid);
+ if (app_status->pkgid == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (comp_type == NULL)
+ return -1;
+
+ app_status->app_type = __get_app_type(comp_type);
+ if (app_status->app_type == -1) {
+ _E("Unknown component type: %s", comp_type);
+ return -1;
+ }
+
+ if (app_status->app_type == AT_SERVICE_APP)
+ app_status->status = STATUS_SERVICE;
+ else
+ app_status->status = STATUS_LAUNCHING;
+
+ if (instance_id) {
+ app_status->instance_id = strdup(instance_id);
+ if (app_status->instance_id == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+ } else {
+ snprintf(buf, sizeof(buf), "%s:%d", appid, pid);
+ app_status->instance_id = strdup(buf);
+ if (app_status->instance_id == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+ }
+
+ app_status->pid = pid;
+ app_status->uid = uid;
+ app_status->is_subapp = is_subapp;
+ if (app_status->app_type == AT_UI_APP)
+ app_status->leader_pid = _app_group_get_leader_pid(pid);
+
+ app_status->timestamp = time(NULL) / 10;
+ app_status->org_caller_pid = caller_pid;
+ app_status->last_caller_pid = caller_pid;
+
+ taskmanage = _appinfo_get_value(ai, AIT_TASKMANAGE);
+ if (taskmanage && strcmp(taskmanage, "true") == 0 &&
+ app_status->leader_pid > 0 &&
+ app_status->is_subapp == false)
+ app_status->managed = true;
+
+ app_status->bg_launch = bg_launch;
+ app_status->socket_exists = false;
+ app_status->starting = false;
+ app_status->is_exit_notified = false;
+
+ return 0;
+}
+
+int _app_status_add_app_info(const struct appinfo *ai, int pid,
+ bool is_subapp, uid_t uid, int caller_pid,
+ bool bg_launch, const char *instance_id,
+ bool debug_mode)
+{
+ GSList *iter;
+ GSList *iter_next;
+ struct app_status_s *app_status;
+ int r;
+
+ if (ai == NULL)
+ return -1;
+
+ GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->pid == pid) {
+ if (app_status->uid == uid)
+ return 0;
+
+ app_status_list = g_slist_remove(app_status_list,
+ app_status);
+ __remove_pkg_status(app_status);
+ __destroy_app_status(app_status);
+ break;
+ }
+ }
+
+ app_status = (struct app_status_s *)calloc(1,
+ sizeof(struct app_status_s));
+ if (app_status == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ r = __app_status_set_app_info(app_status, ai, pid, is_subapp, uid,
+ caller_pid, bg_launch, instance_id);
+ if (r < 0) {
+ __destroy_app_status(app_status);
+ return -1;
+ }
+
+ app_status_list = g_slist_append(app_status_list, app_status);
+ __add_pkg_status(app_status);
+
+ return 0;
+}
+
+int _app_status_remove_all_app_info_with_uid(uid_t uid)
+{
+ GSList *iter;
+ GSList *iter_next;
+ struct app_status_s *app_status;
+
+ GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->uid == uid) {
+ app_status_list = g_slist_remove(app_status_list,
+ app_status);
+ __destroy_app_status(app_status);
+ }
+ }
+
+ return 0;
+}
+
+int _app_status_remove(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return -1;
+
+ app_status_list = g_slist_remove(app_status_list, app_status);
+ __remove_pkg_status(app_status);
+ __destroy_app_status(app_status);
+
+ return 0;
+}
+
+static gboolean __terminate_timer_cb(gpointer data)
+{
+ int pid = GPOINTER_TO_INT(data);
+ app_status_h app_status;
+ int r;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return G_SOURCE_REMOVE;
+
+ _D("pid(%d)", pid);
+ r = kill(pid, SIGKILL);
+ if (r < 0)
+ _W("Failed to send SIGKILL, pid(%d), errno(%d)", pid, errno);
+
+ app_status->timer = 0;
+ return G_SOURCE_REMOVE;
+}
+
+int _app_status_update_status(app_status_h app_status, int status, bool force,
+ bool update_group_info)
+{
+ if (app_status == NULL || status < 0)
+ return -1;
+
+ _D("pid: %d, status: %d", app_status->pid, status);
+#ifdef TIZEN_FEATURE_BLOCK_INPUT
+ _input_unlock();
+#endif /* TIZEN_FEATURE_BLOCK_INPUT */
+
+ if (app_status->status == STATUS_DYING) {
+ _E("%s is STATUS_DYING", app_status->appid);
+ return -1;
+ }
+
+ app_status->status = status;
+ if (app_status->status == STATUS_VISIBLE) {
+ app_status->timestamp = time(NULL) / 10;
+ app_status->fg_count++;
+ if (!app_status->managed)
+ __update_leader_app_status(app_status->leader_pid);
+ if (app_status->fg_count == 1 && limit_bg_uiapps > 0)
+ __check_running_uiapp_list();
+ } else if (app_status->status == STATUS_DYING) {
+ _screen_connector_remove_app_screen_v2(app_status->pid,
+ app_status->uid);
+ if (!app_status->debug_mode) {
+ app_status->timer = g_timeout_add_seconds(5,
+ __terminate_timer_cb,
+ GINT_TO_POINTER(app_status->pid));
+ }
+ aul_send_app_terminate_request_signal(app_status->pid,
+ NULL, NULL, NULL);
+ }
+
+ __update_pkg_status(app_status);
+ _D("pid: %d, appid: %s, pkgid: %s, status: %d",
+ app_status->pid, app_status->appid, app_status->pkgid,
+ app_status->status);
+
+ if (update_group_info && status != STATUS_DYING)
+ _app_group_set_status(app_status->pid, app_status->status, force);
+
+ return 0;
+}
+
+int _app_status_update_last_caller_pid(app_status_h app_status, int caller_pid)
+{
+ if (app_status == NULL)
+ return -1;
+
+ app_status->last_caller_pid = caller_pid;
+
+ return 0;
+}
+
+int _app_status_update_bg_launch(app_status_h app_status, bool bg_launch)
+{
+ if (app_status == NULL)
+ return -1;
+
+ if (!app_status->bg_launch)
+ return 0;
+
+ app_status->bg_launch = bg_launch;
+
+ return 0;
+}
+
+int _app_status_get_process_cnt(const char *appid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+ int cnt = 0;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->appid &&
+ strcmp(app_status->appid, appid) == 0)
+ cnt++;
+ }
+
+ return cnt;
+}
+
+bool _app_status_is_home_app(app_status_h app_status)
+{
+ const char *appid = _app_status_get_appid(app_status);
+
+ if (!appid)
+ return false;
+ if (!home_appid)
+ return false;
+
+ if (strcmp(home_appid, appid) == 0)
+ return true;
+
+ return false;
+}
+
+int _app_status_get_pid(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return -1;
+
+ return app_status->pid;
+}
+
+int _app_status_get_org_caller_pid(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return -1;
+
+ return app_status->org_caller_pid;
+}
+
+int _app_status_get_last_caller_pid(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return -1;
+
+ return app_status->last_caller_pid;
+}
+
+int _app_status_is_running(app_status_h app_status)
+{
+ if (app_status == NULL ||
+ (app_status->app_type == AT_UI_APP && app_status->is_subapp))
+ return -1;
+
+ return app_status->pid;
+}
+
+int _app_status_get_status(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return -1;
+
+ return app_status->status;
+}
+
+uid_t _app_status_get_uid(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return (uid_t)-1;
+
+ return app_status->uid;
+}
+
+const char *_app_status_get_appid(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return NULL;
+
+ return app_status->appid;
+}
+
+const char *_app_status_get_pkgid(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return NULL;
+
+ return app_status->pkgid;
+}
+
+bool _app_status_get_bg_launch(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return false;
+
+ return app_status->bg_launch;
+}
+
+const char *_app_status_get_instance_id(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return NULL;
+
+ return app_status->instance_id;
+}
+
+int _app_status_get_app_type(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return -1;
+
+ return app_status->app_type;
+}
+
+int _app_status_add_shared_info(app_status_h app_status, shared_info_t *info)
+{
+ if (app_status == NULL || info == NULL)
+ return -1;
+
+ app_status->shared_info_list = g_list_append(
+ app_status->shared_info_list, info);
+
+ return 0;
+}
+
+int _app_status_clear_shared_info_list(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return -1;
+
+ __remove_all_shared_info(app_status);
+
+ return 0;
+}
+
+GList *_app_status_get_shared_info_list(app_status_h app_status)
+{
+ return app_status->shared_info_list;
+}
+
+bool _app_status_socket_exists(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return false;
+
+ return app_status->socket_exists;
+}
+
+bool _app_status_is_starting(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return false;
+
+ return app_status->starting;
+}
+
+int _app_status_update_is_starting(app_status_h app_status, bool is_starting)
+{
+ if (app_status == NULL)
+ return -1;
+
+ app_status->starting = is_starting;
+
+ return 0;
+}
+
+const char *_app_status_get_app_path(app_status_h app_status)
+{
+ if (app_status == NULL)
+ return NULL;
+
+ return app_status->app_path;
+}
+
+app_status_h _app_status_find(int pid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->pid == pid)
+ return app_status;
+ }
+
+ return NULL;
+}
+
+static int __read_ppid_from_proc(const char *path, int *ppid)
+{
+ FILE *fp;
+ int ret;
+ int result = -1;
+ char *buf = NULL;
+ int val;
+
+ if (path == NULL)
+ return -1;
+
+ fp = fopen(path, "r");
+ if (fp == NULL)
+ return -1;
+
+ ret = fscanf(fp, "%ms %d\n", &buf, &val);
+ while (ret != EOF) {
+ if (ret == 2) {
+ if (buf && strcmp(buf, "PPid:") == 0) {
+ *ppid = val;
+ result = 0;
+ _D("ppid : %d", *ppid);
+ break;
+ }
+ }
+
+ free(buf);
+ buf = NULL;
+ ret = fscanf(fp, "%ms %d\n", &buf, &val);
+ }
+
+ fclose(fp);
+ free(buf);
+
+ return result;
+}
+
+int __proc_get_ppid_by_pid(int pid)
+{
+ char path[PATH_MAX] = { 0, };
+ int ret = 0;
+ int ppid;
+
+ snprintf(path, sizeof(path), "/proc/%d/status", pid);
+ ret = __read_ppid_from_proc(path, &ppid);
+ if (ret < 0)
+ return -1;
+
+ return ppid;
+}
+
+app_status_h _app_status_find_v2(int pid)
+{
+ int ppid;
+ int pgid;
+ struct app_status_s *app_status = NULL;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ pgid = getpgid(pid);
+ if (pgid > 0)
+ app_status = _app_status_find(pgid);
+ }
+
+ if (app_status == NULL) {
+ ppid = __proc_get_ppid_by_pid(pid);
+ app_status = _app_status_find(ppid);
+ }
+
+ return app_status;
+}
+
+app_status_h _app_status_find_by_appid(const char *appid, uid_t uid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->appid &&
+ strcmp(app_status->appid, appid) == 0 &&
+ app_status->uid == uid &&
+ app_status->is_subapp == false)
+ return app_status;
+ }
+
+ return NULL;
+}
+
+app_status_h _app_status_find_by_appid_v2(const char *appid, uid_t uid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->appid &&
+ strcmp(app_status->appid, appid) == 0 &&
+ app_status->uid == uid)
+ return app_status;
+ }
+
+ return NULL;
+}
+
+app_status_h _app_status_find_with_org_caller(const char *appid, uid_t uid,
+ int caller_pid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->appid &&
+ strcmp(app_status->appid, appid) == 0 &&
+ app_status->uid == uid &&
+ app_status->org_caller_pid == caller_pid)
+ return app_status;
+ }
+
+ return NULL;
+}
+
+app_status_h _app_status_find_by_instance_id(const char *appid,
+ const char *instance_id, uid_t uid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->instance_id &&
+ app_status->uid == uid &&
+ !strcmp(app_status->instance_id, instance_id) &&
+ !strcmp(app_status->appid, appid))
+ return app_status;
+ }
+
+ return NULL;
+}
+
+void _app_status_find_service_apps(app_status_h app_status, int status,
+ void (*send_event_to_svc_core)(int, uid_t), bool suspend)
+{
+ GSList *iter;
+ GSList *svc_list = NULL;
+ const struct appinfo *ai;
+ struct app_status_s *svc_status;
+ int bg_allowed;
+ uid_t uid;
+
+ if (app_status == NULL) {
+ _E("Invalid parameter");
+ return;
+ }
+
+ uid = _app_status_get_uid(app_status);
+ if (app_status->pkg_status && app_status->pkg_status->status == status)
+ svc_list = app_status->pkg_status->svc_list;
+
+ for (iter = svc_list; iter; iter = g_slist_next(iter)) {
+ svc_status = (struct app_status_s *)iter->data;
+ if (svc_status && svc_status->uid == uid) {
+ ai = _appinfo_find(uid, svc_status->appid);
+ bg_allowed = (intptr_t)_appinfo_get_value(ai,
+ AIT_BG_CATEGORY);
+ if (!bg_allowed) {
+ send_event_to_svc_core(svc_status->pid, uid);
+ if (suspend)
+ _suspend_add_timer(svc_status->pid, ai);
+ else
+ _suspend_remove_timer(svc_status->pid);
+ }
+ }
+ }
+}
+
+void _app_status_check_service_only(app_status_h app_status,
+ void (*send_event_to_svc_core)(int, uid_t))
+{
+ GSList *iter;
+ GSList *ui_list = NULL;
+ struct app_status_s *ui_status;
+ int ui_cnt = 0;
+ int bg_allowed;
+ const char *appid;
+ const struct appinfo *ai;
+ uid_t uid;
+
+ if (app_status == NULL) {
+ _E("Invalid parameter");
+ return;
+ }
+
+ uid = _app_status_get_uid(app_status);
+ if (app_status->pkg_status && app_status->pkg_status->ui_list)
+ ui_list = app_status->pkg_status->ui_list;
+
+ for (iter = ui_list; iter; iter = g_slist_next(iter)) {
+ ui_status = (struct app_status_s *)iter->data;
+ if (_app_status_get_status(ui_status) != STATUS_DYING)
+ ui_cnt++;
+ }
+
+ if (ui_cnt == 0) {
+ appid = _app_status_get_appid(app_status);
+ ai = _appinfo_find(uid, appid);
+ bg_allowed = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY);
+ if (!bg_allowed) {
+ send_event_to_svc_core(app_status->pid, uid);
+ _suspend_add_timer(app_status->pid, ai);
+ }
+ }
+}
+
+static bundle *__create_appinfo_bundle(app_status_h app_status)
+{
+ bundle *b;
+ char tmp_str[MAX_PID_STR_BUFSZ];
+
+ b = bundle_create();
+ if (b == NULL)
+ return NULL;
+
+ snprintf(tmp_str, sizeof(tmp_str), "%d", app_status->pid);
+ bundle_add(b, AUL_K_PID, tmp_str);
+ bundle_add(b, AUL_K_APPID, app_status->appid);
+ bundle_add(b, AUL_K_EXEC, app_status->app_path);
+ bundle_add(b, AUL_K_PKGID, app_status->pkgid);
+ snprintf(tmp_str, sizeof(tmp_str), "%d", app_status->status);
+ bundle_add(b, AUL_K_STATUS, tmp_str);
+ snprintf(tmp_str, sizeof(tmp_str), "%d", app_status->is_subapp);
+ bundle_add(b, AUL_K_IS_SUBAPP, tmp_str);
+ if (app_status->instance_id)
+ bundle_add(b, AUL_K_INSTANCE_ID, app_status->instance_id);
+
+ return b;
+}
+
+static int __send_running_appinfo(app_status_h app_status, int fd)
+{
+ int ret;
+ bundle *b;
+ bundle_raw *raw = NULL;
+ int len = 0;
+
+ b = __create_appinfo_bundle(app_status);
+ if (b == NULL) {
+ _E("out of memory");
+ aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR,
+ NULL, 0, AUL_SOCK_NOREPLY);
+ return -1;
+ }
+
+ ret = bundle_encode(b, &raw, &len);
+ bundle_free(b);
+ if (ret != BUNDLE_ERROR_NONE) {
+ _E("Failed to encode bundle");
+ aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR, NULL,
+ 0, AUL_SOCK_NOREPLY);
+ return -1;
+ }
+
+ ret = aul_sock_send_raw_with_fd(fd, APP_GET_INFO_OK,
+ (unsigned char *)raw, len,
+ AUL_SOCK_ASYNC | AUL_SOCK_BUNDLE);
+ if (ret < 0) {
+ _E("Failed to send raw data: %s", raw);
+ free(raw);
+ return ret;
+ }
+ free(raw);
+
+ return 0;
+}
+
+int _app_status_send_running_appinfo(int fd, int cmd, uid_t uid)
+{
+ GSList *list = NULL;
+ GSList *iter;
+ struct app_status_s *app_status;
+ int ret;
+ int count;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status->uid != uid ||
+ app_status->status == STATUS_DYING)
+ continue;
+ if (cmd != APP_ALL_RUNNING_INFO &&
+ cmd != APP_RUNNING_INSTANCE_INFO &&
+ (app_status->app_type == AT_UI_APP &&
+ app_status->is_subapp))
+ continue;
+ if (cmd == APP_RUNNING_INSTANCE_INFO &&
+ app_status->instance_id == NULL)
+ continue;
+
+ list = g_slist_append(list, app_status);
+ }
+
+ count = g_slist_length(list);
+ if (count == 0) {
+ _E("Applications are not running");
+ _send_result_to_client(fd, -1);
+ return -1;
+ }
+ _send_result_to_client_v2(fd, count);
+
+ for (iter = list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status == NULL)
+ continue;
+
+ ret = __send_running_appinfo(app_status, fd);
+ if (ret < 0) {
+ g_slist_free(list);
+ return -1;
+ }
+ }
+ close(fd);
+ g_slist_free(list);
+
+ return 0;
+}
+
+int _app_status_foreach_running_appinfo(void (*callback)(app_status_h, void *),
+ void *data)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+
+ if (callback == NULL)
+ return -1;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status->status == STATUS_DYING ||
+ app_status->is_subapp)
+ continue;
+ callback(app_status, data);
+ }
+
+ return 0;
+}
+
+int _app_status_terminate_apps(const char *appid, uid_t uid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+ int ret;
+
+ if (appid == NULL)
+ return -1;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status->uid == uid &&
+ strcmp(app_status->appid, appid) == 0 &&
+ app_status->status != STATUS_DYING) {
+ ret = _terminate_app_local(app_status->uid,
+ app_status->pid);
+ if (ret < 0) {
+ _E("Failed to terminate app(%d)",
+ app_status->pid);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int _app_status_terminate_apps_by_pkgid(const char *pkgid, uid_t uid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+ int ret;
+
+ if (pkgid == NULL)
+ return -1;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status->uid == uid &&
+ strcmp(app_status->pkgid, pkgid) == 0 &&
+ app_status->status != STATUS_DYING) {
+ ret = _terminate_app_local(app_status->uid,
+ app_status->pid);
+ if (ret < 0) {
+ _E("Failed to terminate app(%d)",
+ app_status->pid);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int _app_status_get_appid_bypid(int fd, int pid)
+{
+ int cmd = APP_GET_INFO_ERROR;
+ int len = 0;
+ int pgid;
+ int ppid;
+ int ret;
+ char appid[MAX_PACKAGE_STR_SIZE] = {0,};
+ app_status_h app_status;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ pgid = getpgid(pid);
+ if (pgid > 0) {
+ app_status = _app_status_find(pgid);
+ if (app_status == NULL) {
+ ppid = __proc_get_ppid_by_pid(pid);
+ app_status = _app_status_find(ppid);
+ }
+ }
+ }
+
+ if (app_status) {
+ snprintf(appid, sizeof(appid), "%s",
+ _app_status_get_appid(app_status));
+ SECURE_LOGD("appid for %d is %s", pid, appid);
+ len = strlen(appid);
+ cmd = APP_GET_INFO_OK;
+ }
+
+ ret = aul_sock_send_raw_with_fd(fd, cmd, (unsigned char *)appid,
+ len, AUL_SOCK_NOREPLY);
+
+ return ret;
+}
+
+int _app_status_get_pkgid_bypid(int fd, int pid)
+{
+ int cmd = APP_GET_INFO_ERROR;
+ int len = 0;
+ int pgid;
+ int ppid;
+ int ret;
+ char pkgid[MAX_PACKAGE_STR_SIZE] = {0,};
+ app_status_h app_status;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ pgid = getpgid(pid);
+ if (pgid > 0) {
+ app_status = _app_status_find(pgid);
+ if (app_status == NULL) {
+ ppid = __proc_get_ppid_by_pid(pid);
+ app_status = _app_status_find(ppid);
+ }
+ }
+ }
+
+ if (app_status) {
+ snprintf(pkgid, sizeof(pkgid), "%s",
+ _app_status_get_pkgid(app_status));
+ SECURE_LOGD("pkgid for %d is %s", pid, pkgid);
+ len = strlen(pkgid);
+ cmd = APP_GET_INFO_OK;
+ }
+
+ ret = aul_sock_send_raw_with_fd(fd, cmd, (unsigned char *)pkgid,
+ len, AUL_SOCK_NOREPLY);
+
+ return ret;
+}
+
+int _app_status_get_instance_id_bypid(int fd, int pid)
+{
+ int cmd = APP_GET_INFO_ERROR;
+ int len = 0;
+ int ret;
+ const char *instance_id;
+ char buf[MAX_PACKAGE_STR_SIZE] = {0,};
+ app_status_h app_status;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ app_status = _app_status_find(getpgid(pid));
+ if (app_status == NULL) {
+ app_status = _app_status_find(
+ __proc_get_ppid_by_pid(pid));
+ }
+ }
+
+ instance_id = _app_status_get_instance_id(app_status);
+ if (instance_id) {
+ snprintf(buf, sizeof(buf), "%s", instance_id);
+ SECURE_LOGD("pid(%d), instance-id(%s)", pid, instance_id);
+ len = strlen(buf);
+ cmd = APP_GET_INFO_OK;
+ }
+
+ ret = aul_sock_send_raw_with_fd(fd, cmd, (unsigned char *)buf, len,
+ AUL_SOCK_NOREPLY);
+
+ return ret;
+}
+
+static void __home_appid_vconf_cb(keynode_t *key, void *data)
+{
+ char *tmpstr;
+
+ tmpstr = vconf_keynode_get_str(key);
+ if (tmpstr == NULL)
+ return;
+
+ if (home_appid)
+ free(home_appid);
+ home_appid = strdup(tmpstr);
+}
+
+int _app_status_publish_status(int pid, int context_status)
+{
+ bundle *b;
+ char endpoint_system[MAX_LOCAL_BUFSZ];
+ char endpoint_user[MAX_LOCAL_BUFSZ];
+ bool endpoint_system_exists;
+ bool endpoint_user_exists;
+ char buf[MAX_PID_STR_BUFSZ];
+ app_status_h app_status;
+ const char *appid;
+ uid_t uid;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return -1;
+
+ appid = _app_status_get_appid(app_status);
+ uid = _app_status_get_uid(app_status);
+ snprintf(endpoint_user, sizeof(endpoint_user),
+ "app_status_event:%s:%d", appid, uid);
+ snprintf(endpoint_system, sizeof(endpoint_system),
+ "app_status_event:%s", appid);
+ endpoint_system_exists = _app_com_endpoint_exists(endpoint_system);
+ endpoint_user_exists = _app_com_endpoint_exists(endpoint_user);
+ if (!endpoint_system_exists && !endpoint_user_exists)
+ return -1;
+
+ b = __create_appinfo_bundle(app_status);
+ if (b == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ snprintf(buf, sizeof(buf), "%d", context_status);
+ bundle_add(b, "__CONTEXT_STATUS__", buf);
+ if (endpoint_system_exists)
+ _app_com_send(endpoint_system, pid, b, uid);
+ if (endpoint_user_exists)
+ _app_com_send(endpoint_user, pid, b, uid);
+ bundle_free(b);
+
+ return 0;
+}
+
+static void __terminate_widget_apps_by_org_caller(int caller_pid, uid_t uid)
+{
+ GSList *iter;
+ struct app_status_s *app_status;
+ int ret;
+
+ for (iter = app_status_list; iter; iter = g_slist_next(iter)) {
+ app_status = (struct app_status_s *)iter->data;
+ if ((app_status->app_type == AT_WIDGET_APP ||
+ app_status->app_type == AT_WATCH_APP) &&
+ app_status->uid == uid &&
+ app_status->org_caller_pid == caller_pid &&
+ app_status->status != STATUS_DYING) {
+ ret = _terminate_app_local(app_status->uid,
+ app_status->pid);
+ if (ret < 0) {
+ _E("Failed to terminate app(%d)",
+ app_status->pid);
+ }
+ }
+ }
+}
+
+void _app_status_cleanup(app_status_h app_status)
+{
+ int pid;
+ int caller_pid;
+ const char *instance_id;
+ uid_t uid;
+
+ if (app_status == NULL)
+ return;
+
+ pid = _app_status_get_pid(app_status);
+ uid = _app_status_get_uid(app_status);
+ _D("pid: %d, uid: %d", pid, uid);
+
+ instance_id = _app_status_get_instance_id(app_status);
+ if (instance_id == NULL)
+ instance_id = _app_status_get_appid(app_status);
+ _screen_connector_remove_app_screen_v2(pid, uid);
+ _screen_connector_remove_screen_viewer_v2(pid, uid);
+
+ __terminate_widget_apps_by_org_caller(pid, uid);
+ _extractor_unmount(pid, _extractor_mountable_get_tep_paths);
+ _extractor_unmount(pid, _extractor_mountable_get_tpk_paths);
+ _app_com_client_remove(pid);
+ if (_app_group_is_leader_pid(pid)) {
+ _W("app_group_leader_app, pid: %d", pid);
+ if (_app_group_find_second_leader(pid) == -1) {
+ _app_group_clear_top(pid, uid);
+ _app_group_set_dead_pid(pid);
+ _app_group_remove(pid);
+ } else {
+ _app_group_remove_leader_pid(pid);
+ }
+ } else if (_app_group_is_sub_app(pid)) {
+ _W("app_group_sub_app, pid: %d", pid);
+ caller_pid = _app_group_get_next_caller_pid(pid);
+ if (_app_group_can_reroute(pid)
+ || (caller_pid > 0 && caller_pid != pid)) {
+ _W("app_group reroute");
+ _app_group_reroute(pid);
+ } else {
+ _W("app_group clear top");
+ _app_group_clear_top(pid, uid);
+ }
+ _app_group_set_dead_pid(pid);
+ _app_group_remove(pid);
+ }
+
+ _launch_remove_fgmgr(pid);
+ _suspend_remove_proc(pid);
+ _app_group_remove_from_recycle_bin(pid);
+ _temporary_permission_drop(pid, uid);
+ _app_status_remove(app_status);
+ aul_send_app_terminated_signal(pid);
+}
+
+static bool __socket_monitor_cb(const char *event_name, void *data)
+{
+ app_status_h app_status;
+ int pid = -1;
+
+ if (event_name == NULL)
+ return true;
+
+ if (isdigit(*event_name))
+ pid = atoi(event_name);
+
+ if (pid > 1) {
+ _D("pid(%d)", pid);
+ _request_reply_for_pending_request(pid);
+ app_status = _app_status_find(pid);
+ if (app_status) {
+ app_status->socket_exists = true;
+ app_status->starting = true;
+ }
+ }
+
+ return true;
+}
+
+static bool __dir_monitor_cb(const char *event_name, void *data)
+{
+ char *path = (char *)data;
+ char *str = basename(path);
+ uid_t uid;
+ int wd;
+
+ if (event_name == NULL || str == NULL)
+ return true;
+
+ if (strcmp(event_name, str) == 0) {
+ wd = _inotify_add_watch(path, IN_CREATE, __socket_monitor_cb,
+ NULL);
+ uid = strtol(event_name, NULL, 10);
+ g_hash_table_insert(__wd_table, GUINT_TO_POINTER(uid),
+ GINT_TO_POINTER(wd));
+ free(path);
+ return false;
+ }
+
+ return true;
+}
+
+int _app_status_usr_init(uid_t uid)
+{
+ int wd;
+ char buf[PATH_MAX];
+ char *path;
+
+ wd = GPOINTER_TO_INT(g_hash_table_lookup(__wd_table,
+ GUINT_TO_POINTER(uid)));
+ if (wd > 0) {
+ _D("Already exists");
+ return 0;
+ }
+
+ snprintf(buf, sizeof(buf), "/run/aul/apps/%d", uid);
+ if (access(buf, F_OK) == 0) {
+ wd = _inotify_add_watch(buf, IN_CREATE, __socket_monitor_cb,
+ NULL);
+ if (wd < 0) {
+ _E("Failed to add a watch - uid(%d)", uid);
+ return -1;
+ }
+
+ g_hash_table_insert(__wd_table, GUINT_TO_POINTER(uid),
+ GINT_TO_POINTER(wd));
+ } else {
+ path = strdup(buf);
+ if (path == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ _inotify_add_watch("/run/aul/apps", IN_CREATE,
+ __dir_monitor_cb, path);
+ }
+
+ return 0;
+}
+
+void _app_status_usr_fini(uid_t uid)
+{
+ int wd;
+ GSList *iter;
+ GSList *iter_next;
+ app_status_h app_status;
+
+ wd = GPOINTER_TO_INT(g_hash_table_lookup(__wd_table,
+ GUINT_TO_POINTER(uid)));
+ if (wd > 0)
+ g_hash_table_remove(__wd_table, GUINT_TO_POINTER(uid));
+ else
+ _D("Watch fd doesn't exist - uid(%d)", uid);
+
+ GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+ app_status = (struct app_status_s *)iter->data;
+ if (app_status && app_status->uid == uid)
+ _app_status_cleanup(app_status);
+ }
+}
+
+static void __remove_inotify_watch(gpointer data)
+{
+ int wd = GPOINTER_TO_INT(data);
+
+ if (wd <= 0)
+ return;
+
+ _inotify_rm_watch(wd);
+}
+
+int _app_status_init(void)
+{
+ int ret;
+
+ __wd_table = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL, __remove_inotify_watch);
+ if (__wd_table == NULL) {
+ _E("Failed to create wd hash table");
+ return -1;
+ }
+
+ ret = vconf_get_int(VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS,
+ &limit_bg_uiapps);
+ if (ret != VCONF_OK)
+ _E("Failed to get %s", VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS);
+
+ ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS,
+ __vconf_cb, NULL);
+ if (ret != 0) {
+ _E("Failed to register callback for %s",
+ VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS);
+ }
+
+ home_appid = vconf_get_str(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME);
+ ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME,
+ __home_appid_vconf_cb, NULL);
+ if (ret != 0) {
+ _E("Failed to register callback for %s",
+ VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME);
+ }
+
+ oom_app_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, __destroy_fault_app_info);
+ pkg_update_app_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, __destroy_fault_app_info);
+
+ _cooldown_init();
+ return 0;
+}
+
+int _app_status_finish(void)
+{
+ int ret;
+ GSList *iter;
+ GSList *iter_next;
+ app_status_h app_status;
+
+ GSLIST_FOREACH_SAFE(app_status_list, iter, iter_next) {
+ app_status = (app_status_h)iter->data;
+ _app_status_cleanup(app_status);
+ }
+
+ ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS,
+ __vconf_cb);
+ if (ret != 0)
+ _E("Failed to remove a callback");
+
+ ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_SELECTED_PACKAGE_NAME,
+ __home_appid_vconf_cb);
+ if (ret != 0)
+ _E("Failed to remove a callback");
+
+ free(home_appid);
+
+ if (__wd_table)
+ g_hash_table_destroy(__wd_table);
+
+ _cooldown_fini();
+
+ g_hash_table_destroy(oom_app_table);
+ g_hash_table_destroy(pkg_update_app_table);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <dirent.h>
+#include <package-manager.h>
+#include <pkgmgr-info.h>
+#include <vconf.h>
+#include <aul.h>
+
+#include "amd_util.h"
+#include "amd_appinfo.h"
+#include "amd_launch.h"
+#include "amd_app_status.h"
+#include "amd_signal.h"
+#include "amd_app_property.h"
+#include "amd_login_monitor.h"
+#include "amd_widget.h"
+
+static pkgmgr_client *pc;
+static GHashTable *user_tbl;
+static GHashTable *pkg_pending;
+struct user_appinfo {
+ uid_t uid;
+ GHashTable *tbl; /* key is appid, value is struct appinfo */
+};
+
+struct app_event_info {
+ int req_id;
+ int type;
+ uid_t uid;
+};
+
+struct pkg_event_info {
+ uid_t target_uid;
+ const char *pkgid;
+};
+
+static GList *app_event_list;
+
+typedef int (*appinfo_handler_add_cb)(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data);
+typedef void (*appinfo_handler_remove_cb)(void *data);
+
+typedef struct _appinfo_vft {
+ appinfo_handler_add_cb constructor;
+ appinfo_handler_remove_cb destructor;
+} appinfo_vft;
+
+enum _background_category {
+ _BACKGROUND_CATEGORY_MEDIA = 0x01,
+ _BACKGROUND_CATEGORY_DOWNLOAD = 0x02,
+ _BACKGROUND_CATEGORY_BACKGROUND_NETWORK = 0x04,
+ _BACKGROUND_CATEGORY_LOCATION = 0x08,
+ _BACKGROUND_CATEGORY_SENSOR = 0x10,
+ _BACKGROUND_CATEGORY_IOT_COMMUNICATION = 0x20,
+ _BACKGROUND_CATEGORY_SYSTEM = 0x40
+};
+
+static int gles = 1;
+
+static void __free_appinfo_splash_image(gpointer data)
+{
+ struct appinfo_splash_image *splash_image = data;
+
+ if (splash_image == NULL)
+ return;
+
+ if (splash_image->color_depth)
+ free(splash_image->color_depth);
+ if (splash_image->indicatordisplay)
+ free(splash_image->indicatordisplay);
+ if (splash_image->type)
+ free(splash_image->type);
+ if (splash_image->src)
+ free(splash_image->src);
+ free(splash_image);
+}
+
+static void __free_user_appinfo(gpointer data)
+{
+ struct user_appinfo *info = (struct user_appinfo *)data;
+
+ g_hash_table_destroy(info->tbl);
+ free(info);
+}
+
+static int __read_background_category(const char *category_name,
+ void *user_data)
+{
+ struct appinfo *c = user_data;
+ int category = (intptr_t)(c->val[AIT_BG_CATEGORY]);
+
+ if (!category_name)
+ return 0;
+
+ if (strcmp(category_name, "disable") == 0) {
+ c->val[AIT_BG_CATEGORY] = 0x00;
+ return -1;
+ }
+
+ if (strcmp(category_name, "media") == 0) {
+ c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+ _BACKGROUND_CATEGORY_MEDIA));
+ } else if (strcmp(category_name, "download") == 0) {
+ c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+ _BACKGROUND_CATEGORY_DOWNLOAD));
+ } else if (strcmp(category_name, "background-network") == 0) {
+ c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+ _BACKGROUND_CATEGORY_BACKGROUND_NETWORK));
+ } else if (strcmp(category_name, "location") == 0) {
+ c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+ _BACKGROUND_CATEGORY_LOCATION));
+ } else if (strcmp(category_name, "sensor") == 0) {
+ c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+ _BACKGROUND_CATEGORY_SENSOR));
+ } else if (strcmp(category_name, "iot-communication") == 0) {
+ c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+ _BACKGROUND_CATEGORY_IOT_COMMUNICATION));
+ } else if (strcmp(category_name, "system") == 0) {
+ c->val[AIT_BG_CATEGORY] = (char *)((intptr_t)(category |
+ _BACKGROUND_CATEGORY_SYSTEM));
+ }
+
+ return 0;
+}
+
+static void __appinfo_remove_splash_screen(void *data)
+{
+ struct appinfo_splash_screen *splash_screen =
+ (struct appinfo_splash_screen *)data;
+
+ if (splash_screen == NULL)
+ return;
+
+ if (splash_screen->portrait)
+ g_hash_table_destroy(splash_screen->portrait);
+ if (splash_screen->landscape)
+ g_hash_table_destroy(splash_screen->landscape);
+ free(splash_screen);
+}
+
+static int __appinfo_add_exec(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *exec = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_exec(handle, &exec);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get exec");
+ return -1;
+ }
+
+ info->val[AIT_EXEC] = strdup(exec);
+
+ return 0;
+}
+
+static int __appinfo_add_pkgtype(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *pkgtype = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_pkgtype(handle, &pkgtype);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get pkgtype");
+ return -1;
+ }
+
+ info->val[AIT_PKGTYPE] = strdup(pkgtype);
+
+ return 0;
+}
+
+static int __appinfo_add_onboot(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ bool onboot = false;
+
+ ret = pkgmgrinfo_appinfo_is_onboot(handle, &onboot);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get onboot");
+ return -1;
+ }
+
+ info->val[AIT_ONBOOT] = strdup(onboot ? "true" : "false");
+
+ return 0;
+}
+
+static int __appinfo_add_restart(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ bool restart = false;
+
+ ret = pkgmgrinfo_appinfo_is_autorestart(handle, &restart);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get restart");
+ return -1;
+ }
+
+ info->val[AIT_RESTART] = GINT_TO_POINTER(restart ? 1 : 0);
+
+ return 0;
+}
+
+static int __appinfo_add_multi(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ bool multiple = false;
+
+ ret = pkgmgrinfo_appinfo_is_multiple(handle, &multiple);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get multiple");
+ return -1;
+ }
+
+ info->val[AIT_MULTI] = strdup(multiple ? "true" : "false");
+
+ return 0;
+}
+
+static int __appinfo_add_hwacc(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ pkgmgrinfo_app_hwacceleration hwacc;
+
+ ret = pkgmgrinfo_appinfo_get_hwacceleration(handle, &hwacc);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get hwacc");
+ return -1;
+ }
+
+ info->val[AIT_HWACC] = strdup(
+ (gles == 0 ||
+ hwacc == PMINFO_HWACCELERATION_OFF) ?
+ "NOT_USE" :
+ (hwacc == PMINFO_HWACCELERATION_ON) ?
+ "USE" :
+ "SYS");
+
+ return 0;
+}
+
+static int __appinfo_add_perm(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ pkgmgrinfo_permission_type permission;
+
+ ret = pkgmgrinfo_appinfo_get_permission_type(handle, &permission);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get permission type");
+ return -1;
+ }
+
+ info->val[AIT_PERM] = strdup(
+ (permission == PMINFO_PERMISSION_SIGNATURE) ?
+ "signature" :
+ (permission == PMINFO_PERMISSION_PRIVILEGE) ?
+ "privilege" :
+ "normal");
+
+ return 0;
+}
+
+static int __appinfo_add_pkgid(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *pkgid = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgid);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get pkgid");
+ return -1;
+ }
+
+ info->val[AIT_PKGID] = strdup(pkgid);
+
+ return 0;
+}
+
+static int __appinfo_add_preload(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ bool preload = false;
+
+ ret = pkgmgrinfo_appinfo_is_preload(handle, &preload);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get preload");
+ return -1;
+ }
+
+ info->val[AIT_PRELOAD] = strdup(preload ? "true" : "false");
+
+ return 0;
+}
+
+static int __appinfo_add_status(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ info->val[AIT_STATUS] = strdup("installed");
+
+ return 0;
+}
+
+static int __appinfo_add_pool(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ bool process_pool = false;
+
+ ret = pkgmgrinfo_appinfo_is_process_pool(handle, &process_pool);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get process_pool");
+ return -1;
+ }
+
+ info->val[AIT_POOL] = strdup(process_pool ? "true" : "false");
+
+ return 0;
+}
+
+static int __appinfo_add_comptype(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *component_type = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_component_type(handle, &component_type);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get component type");
+ return -1;
+ }
+
+ info->val[AIT_COMPTYPE] = strdup(component_type);
+
+ return 0;
+}
+
+static int __appinfo_add_tep(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *tep_name = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_tep_name(handle, &tep_name);
+ if (ret != PMINFO_R_OK) {
+ info->val[AIT_TEP] = NULL;
+ } else {
+ if (tep_name && strlen(tep_name) > 0)
+ info->val[AIT_TEP] = strdup(tep_name);
+ else
+ info->val[AIT_TEP] = NULL;
+ }
+
+ return 0;
+}
+
+static int __appinfo_add_mountable_pkg(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *tpk_name = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_zip_mount_file(handle, &tpk_name);
+ if (ret != PMINFO_R_OK) {
+ info->val[AIT_MOUNTABLE_PKG] = NULL;
+ } else {
+ if (tpk_name && strlen(tpk_name) > 0)
+ info->val[AIT_MOUNTABLE_PKG] = strdup(tpk_name);
+ else
+ info->val[AIT_MOUNTABLE_PKG] = NULL;
+ }
+
+ return 0;
+}
+
+static int __appinfo_add_storage_type(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ pkgmgrinfo_installed_storage installed_storage;
+
+ ret = pkgmgrinfo_appinfo_get_installed_storage_location(handle,
+ &installed_storage);
+ if (ret == PMINFO_R_OK) {
+ if (installed_storage == PMINFO_INTERNAL_STORAGE)
+ info->val[AIT_STORAGE_TYPE] = strdup("internal");
+ else if (installed_storage == PMINFO_EXTERNAL_STORAGE)
+ info->val[AIT_STORAGE_TYPE] = strdup("external");
+ } else {
+ info->val[AIT_STORAGE_TYPE] = strdup("internal");
+ }
+
+ return 0;
+}
+
+static int __appinfo_add_bg_category(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+
+ ret = pkgmgrinfo_appinfo_foreach_background_category(handle,
+ __read_background_category, info);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get background category");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __appinfo_add_launch_mode(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *mode = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_launch_mode(handle, &mode);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get launch_mode");
+ return -1;
+ }
+
+ info->val[AIT_LAUNCH_MODE] = strdup(mode ? mode : "single");
+
+ return 0;
+}
+
+static int __appinfo_add_global(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ bool is_global = false;
+
+ ret = pkgmgrinfo_appinfo_is_global(handle, &is_global);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get is_global info");
+ return -1;
+ }
+
+ info->val[AIT_GLOBAL] = strdup(is_global ? "true" : "false");
+
+ return 0;
+}
+
+static int __appinfo_add_effective_appid(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *effective_appid = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_effective_appid(handle, &effective_appid);
+ if (ret != PMINFO_R_OK) {
+ info->val[AIT_EFFECTIVE_APPID] = NULL;
+ } else {
+ if (effective_appid && strlen(effective_appid) > 0) {
+ info->val[AIT_EFFECTIVE_APPID] =
+ strdup(effective_appid);
+ }
+ }
+
+ return 0;
+}
+
+static int __appinfo_add_taskmanage(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ bool taskmanage = false;
+
+ pkgmgrinfo_appinfo_is_taskmanage(handle, &taskmanage);
+
+ info->val[AIT_TASKMANAGE] = strdup(taskmanage ? "true" : "false");
+
+ return 0;
+}
+
+static int __appinfo_add_apptype(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *apptype = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_apptype(handle, &apptype);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get apptype");
+ return -1;
+ }
+
+ info->val[AIT_APPTYPE] = strdup(apptype);
+
+ return 0;
+}
+
+static int __appinfo_add_root_path(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *path = NULL;
+
+ ret = pkgmgrinfo_appinfo_get_root_path(handle, &path);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get root path");
+ return -1;
+ }
+
+ info->val[AIT_ROOT_PATH] = path ? strdup(path) : NULL;
+
+ return 0;
+}
+
+static int __add_splash_screen_list_cb(const char *src, const char *type,
+ const char *orientation, const char *indicatordisplay,
+ const char *operation, const char *color_depth, void *user_data)
+{
+ struct appinfo *info = (struct appinfo *)user_data;
+ struct appinfo_splash_screen *splash_screen;
+ struct appinfo_splash_image *splash_image;
+ char *key;
+
+ splash_image = (struct appinfo_splash_image *)calloc(1,
+ sizeof(struct appinfo_splash_image));
+ if (splash_image == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ splash_image->src = strdup(src);
+ splash_image->type = strdup(type);
+ splash_image->indicatordisplay = strdup(indicatordisplay);
+ splash_image->color_depth = strdup(color_depth);
+ key = strdup(operation);
+
+ splash_screen =
+ (struct appinfo_splash_screen *)info->val[AIT_SPLASH_SCREEN];
+ if (splash_screen == NULL) {
+ splash_screen = (struct appinfo_splash_screen *)calloc(1,
+ sizeof(struct appinfo_splash_screen));
+ if (splash_screen == NULL) {
+ _E("out of memory");
+ __free_appinfo_splash_image(splash_image);
+ free(key);
+ return -1;
+ }
+ info->val[AIT_SPLASH_SCREEN] = (char *)splash_screen;
+ }
+
+ if (strcasecmp(orientation, "portrait") == 0) {
+ if (splash_screen->portrait == NULL) {
+ splash_screen->portrait = g_hash_table_new_full(
+ g_str_hash, g_str_equal, g_free,
+ __free_appinfo_splash_image);
+ }
+ g_hash_table_insert(splash_screen->portrait, key, splash_image);
+ } else if (strcasecmp(orientation, "landscape") == 0) {
+ if (splash_screen->landscape == NULL) {
+ splash_screen->landscape = g_hash_table_new_full(
+ g_str_hash, g_str_equal, g_free,
+ __free_appinfo_splash_image);
+ }
+ g_hash_table_insert(splash_screen->landscape, key,
+ splash_image);
+ } else {
+ __free_appinfo_splash_image(splash_image);
+ free(key);
+ }
+
+ return 0;
+}
+
+static int __appinfo_add_splash_screens(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+
+ ret = pkgmgrinfo_appinfo_foreach_splash_screen(handle,
+ __add_splash_screen_list_cb, info);
+ if (ret < 0) {
+ _E("Failed to get splash screen");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __appinfo_add_splash_screen_display(
+ const pkgmgrinfo_appinfo_h handle, struct appinfo *info,
+ void *data)
+{
+ bool splash_screen_display = true;
+ int ret;
+
+ ret = pkgmgrinfo_appinfo_get_splash_screen_display(handle,
+ &splash_screen_display);
+ if (ret < 0)
+ _D("Failed to get splash screen display");
+
+ info->val[AIT_SPLASH_SCREEN_DISPLAY] =
+ GINT_TO_POINTER(splash_screen_display ? 1 : 0);
+
+ return 0;
+}
+
+static int __appinfo_add_api_version(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ char *api_version;
+
+ ret = pkgmgrinfo_appinfo_get_api_version(handle, &api_version);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get api version");
+ return -1;
+ }
+
+ info->val[AIT_API_VERSION] = strdup(api_version);
+
+ return 0;
+}
+
+static int __appinfo_add_enablement(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ bool disabled = false;
+
+ ret = pkgmgrinfo_appinfo_is_disabled(handle, &disabled);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get enablement");
+ return -1;
+ }
+
+ info->val[AIT_ENABLEMENT] = GINT_TO_POINTER(disabled ? 0 : 1);
+
+ return 0;
+}
+
+static int __appinfo_add_cooldown_mode(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ int support_mode = 0;
+
+ ret = pkgmgrinfo_appinfo_get_support_mode(handle, &support_mode);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get support mode value");
+ return -1;
+ }
+
+ if (support_mode & APP_SUPPORT_MODE_COOL_DOWN_VAL)
+ info->val[AIT_COOLDOWN] = strdup("true");
+ else
+ info->val[AIT_COOLDOWN] = strdup("false");
+
+ return 0;
+}
+
+static int __appinfo_add_system(const pkgmgrinfo_appinfo_h handle,
+ struct appinfo *info, void *data)
+{
+ int ret;
+ bool system = false;
+
+ ret = pkgmgrinfo_appinfo_is_system(handle, &system);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get support mode value");
+ return -1;
+ }
+
+ if (system)
+ info->val[AIT_SYSTEM] = strdup("true");
+ else
+ info->val[AIT_SYSTEM] = strdup("false");
+ if (info->val[AIT_SYSTEM] == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ return 0;
+}
+
+static appinfo_vft appinfo_table[AIT_MAX] = {
+ [AIT_NAME] = {
+ .constructor = NULL,
+ .destructor = NULL
+ },
+ [AIT_EXEC] = {
+ .constructor = __appinfo_add_exec,
+ .destructor = free
+ },
+ [AIT_PKGTYPE] = {
+ .constructor = __appinfo_add_pkgtype,
+ .destructor = free
+ },
+ [AIT_ONBOOT] = {
+ .constructor = __appinfo_add_onboot,
+ .destructor = free
+ },
+ [AIT_RESTART] = {
+ .constructor = __appinfo_add_restart,
+ .destructor = NULL
+ },
+ [AIT_MULTI] = {
+ .constructor = __appinfo_add_multi,
+ .destructor = free
+ },
+ [AIT_HWACC] = {
+ .constructor = __appinfo_add_hwacc,
+ .destructor = free
+ },
+ [AIT_PERM] = {
+ .constructor = __appinfo_add_perm,
+ .destructor = free
+ },
+ [AIT_PKGID] = {
+ .constructor = __appinfo_add_pkgid,
+ .destructor = free
+ },
+ [AIT_PRELOAD] = {
+ .constructor = __appinfo_add_preload,
+ .destructor = free
+ },
+ [AIT_STATUS] = {
+ .constructor = __appinfo_add_status,
+ .destructor = free
+ },
+ [AIT_POOL] = {
+ .constructor = __appinfo_add_pool,
+ .destructor = free
+ },
+ [AIT_COMPTYPE] = {
+ .constructor = __appinfo_add_comptype,
+ .destructor = free
+ },
+ [AIT_TEP] = {
+ .constructor = __appinfo_add_tep,
+ .destructor = free
+ },
+ [AIT_MOUNTABLE_PKG] = {
+ .constructor = __appinfo_add_mountable_pkg,
+ .destructor = free
+ },
+ [AIT_STORAGE_TYPE] = {
+ .constructor = __appinfo_add_storage_type,
+ .destructor = free
+ },
+ [AIT_BG_CATEGORY] = {
+ .constructor = __appinfo_add_bg_category,
+ .destructor = NULL
+ },
+ [AIT_LAUNCH_MODE] = {
+ .constructor = __appinfo_add_launch_mode,
+ .destructor = free
+ },
+ [AIT_GLOBAL] = {
+ .constructor = __appinfo_add_global,
+ .destructor = free
+ },
+ [AIT_EFFECTIVE_APPID] = {
+ .constructor = __appinfo_add_effective_appid,
+ .destructor = free
+ },
+ [AIT_TASKMANAGE] = {
+ .constructor = __appinfo_add_taskmanage,
+ .destructor = free
+ },
+ [AIT_VISIBILITY] = {
+ .constructor = NULL,
+ .destructor = free
+ },
+ [AIT_APPTYPE] = {
+ .constructor = __appinfo_add_apptype,
+ .destructor = free
+ },
+ [AIT_ROOT_PATH] = {
+ .constructor = __appinfo_add_root_path,
+ .destructor = free
+ },
+ [AIT_SPLASH_SCREEN] = {
+ .constructor = __appinfo_add_splash_screens,
+ .destructor = __appinfo_remove_splash_screen
+ },
+ [AIT_SPLASH_SCREEN_DISPLAY] = {
+ .constructor = __appinfo_add_splash_screen_display,
+ .destructor = NULL
+ },
+ [AIT_API_VERSION] = {
+ .constructor = __appinfo_add_api_version,
+ .destructor = free
+ },
+ [AIT_ENABLEMENT] = {
+ .constructor = __appinfo_add_enablement,
+ .destructor = NULL
+ },
+ [AIT_COOLDOWN] = {
+ .constructor = __appinfo_add_cooldown_mode,
+ .destructor = free
+ },
+ [AIT_SYSTEM] = {
+ .constructor = __appinfo_add_system,
+ .destructor = free
+ },
+
+};
+
+static void __appinfo_remove_handler(gpointer data)
+{
+ struct appinfo *c = data;
+ int i;
+
+ if (!c)
+ return;
+
+ for (i = AIT_START; i < AIT_MAX; i++) {
+ if (appinfo_table[i].destructor && c->val[i] != NULL)
+ appinfo_table[i].destructor(c->val[i]);
+ }
+
+ free(c);
+}
+
+static int __appinfo_insert_handler (const pkgmgrinfo_appinfo_h handle,
+ void *data)
+{
+ int i;
+ struct appinfo *c;
+ struct user_appinfo *info = (struct user_appinfo *)data;
+ char *appid;
+ int ret;
+ char err_buf[1024];
+
+ if (!handle || !info) {
+ _E("null app handle");
+ return -1;
+ }
+
+ if (pkgmgrinfo_appinfo_get_appid(handle, &appid) != PMINFO_R_OK) {
+ _E("fail to get appinfo");
+ return -1;
+ }
+
+ g_hash_table_remove(info->tbl, appid);
+
+ c = calloc(1, sizeof(struct appinfo));
+ if (!c) {
+ _E("create appinfo: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return -1;
+ }
+
+ c->val[AIT_NAME] = strdup(appid);
+
+ for (i = AIT_START; i < AIT_MAX; i++) {
+ if (appinfo_table[i].constructor) {
+ ret = appinfo_table[i].constructor(handle, c, info);
+ if (ret < 0) {
+ __appinfo_remove_handler(c);
+ return -1;
+ }
+ }
+ }
+
+ SECURE_LOGD("%s : %s : %s : %s", c->val[AIT_NAME], c->val[AIT_COMPTYPE],
+ c->val[AIT_PKGTYPE], c->val[AIT_APPTYPE]);
+
+ g_hash_table_insert(info->tbl, c->val[AIT_NAME], c);
+ _app_property_insert(info->uid, c->val[AIT_NAME]);
+
+ return 0;
+}
+
+static int __appinfo_update_handler(const pkgmgrinfo_appinfo_h handle,
+ void *data)
+{
+ int i;
+ struct appinfo *c;
+ struct user_appinfo *info = (struct user_appinfo *)data;
+ char *appid;
+ int ret;
+ bool restart;
+ int auto_restart;
+
+ if (!handle || !info) {
+ _E("Invalid parameter");
+ return -1;
+ }
+
+ ret = pkgmgrinfo_appinfo_get_appid(handle, &appid);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get appinfo");
+ return -1;
+ }
+
+ c = (struct appinfo *)g_hash_table_lookup(info->tbl, appid);
+ if (!c) {
+ _E("Failed to find appinfo(%s)", appid);
+ return -1;
+ }
+
+ if (c->val[AIT_STATUS] && strcmp(c->val[AIT_STATUS], "restart") == 0)
+ restart = true;
+ else
+ restart = false;
+
+ for (i = AIT_START; i < AIT_MAX; i++) {
+ if (appinfo_table[i].destructor && c->val[i])
+ appinfo_table[i].destructor(c->val[i]);
+
+ if (appinfo_table[i].constructor) {
+ ret = appinfo_table[i].constructor(handle, c, info);
+ if (ret < 0) {
+ __appinfo_remove_handler(c);
+ return -1;
+ }
+ }
+ }
+ SECURE_LOGD("%s : %s : %s : %s",
+ c->val[AIT_NAME], c->val[AIT_COMPTYPE],
+ c->val[AIT_PKGTYPE], c->val[AIT_APPTYPE]);
+ _app_property_insert(info->uid, c->val[AIT_NAME]);
+
+ auto_restart = GPOINTER_TO_INT(c->val[AIT_RESTART]);
+ if (auto_restart && restart)
+ _launch_start_app_local(info->uid, c->val[AIT_NAME]);
+
+ return 0;
+}
+
+static int __insert_appinfo(const pkgmgrinfo_appinfo_h handle, void *data)
+{
+ int ret;
+ struct appinfo *ai;
+ struct user_appinfo *info = (struct user_appinfo *)data;
+ char *appid = NULL;
+
+ ret = __appinfo_insert_handler(handle, data);
+ if (ret < 0)
+ return -1;
+
+ ret = pkgmgrinfo_appinfo_get_appid(handle, &appid);
+ if (ret != PMINFO_R_OK)
+ return -1;
+
+ ai = (struct appinfo *)g_hash_table_lookup(info->tbl, appid);
+ if (ai == NULL)
+ return -1;
+
+ _launch_start_onboot_app_local(info->uid, appid, ai);
+
+ return 0;
+}
+
+static void __remove_user_appinfo(uid_t uid)
+{
+ g_hash_table_remove(user_tbl, GINT_TO_POINTER(uid));
+}
+
+static struct user_appinfo *__add_user_appinfo(uid_t uid)
+{
+ int r;
+ struct user_appinfo *info;
+
+ info = calloc(1, sizeof(struct user_appinfo));
+ if (info == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ info->uid = uid;
+ info->tbl = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ __appinfo_remove_handler);
+ if (info->tbl == NULL) {
+ _E("out of memory");
+ free(info);
+ return NULL;
+ }
+
+ g_hash_table_insert(user_tbl, GINT_TO_POINTER(uid), info);
+
+ r = pkgmgrinfo_appinfo_get_usr_installed_list_full(
+ __appinfo_insert_handler, uid,
+ PMINFO_APPINFO_GET_SPLASH_SCREEN, info);
+ if (r != PMINFO_R_OK) {
+ __remove_user_appinfo(uid);
+ return NULL;
+ }
+
+ _D("loaded appinfo table for uid %d", uid);
+
+ return info;
+}
+
+static struct user_appinfo *__find_user_appinfo(uid_t uid)
+{
+ return g_hash_table_lookup(user_tbl, GINT_TO_POINTER(uid));
+}
+
+static void __appinfo_set_blocking_cb(void *user_data,
+ const char *appid, struct appinfo *info)
+{
+ struct pkg_event_info *pkg_info = (struct pkg_event_info *)user_data;
+
+ if (strcmp(info->val[AIT_PKGID], pkg_info->pkgid))
+ return;
+
+ if (pkg_info->target_uid == GLOBAL_USER &&
+ !strcmp(info->val[AIT_GLOBAL], "false"))
+ return;
+ else if (pkg_info->target_uid != GLOBAL_USER &&
+ !strcmp(info->val[AIT_GLOBAL], "true"))
+ return;
+
+ free(info->val[AIT_STATUS]);
+ info->val[AIT_STATUS] = strdup("blocking");
+ _D("%s status changed: blocking", appid);
+}
+
+static void __appinfo_unset_blocking_cb(void *user_data,
+ const char *appid, struct appinfo *info)
+{
+ struct pkg_event_info *pkg_info = (struct pkg_event_info *)user_data;
+
+ if (strcmp(info->val[AIT_PKGID], pkg_info->pkgid))
+ return;
+
+ if (pkg_info->target_uid == GLOBAL_USER &&
+ !strcmp(info->val[AIT_GLOBAL], "false"))
+ return;
+ else if (pkg_info->target_uid != GLOBAL_USER &&
+ !strcmp(info->val[AIT_GLOBAL], "true"))
+ return;
+
+ free(info->val[AIT_STATUS]);
+ info->val[AIT_STATUS] = strdup("installed");
+ _D("%s status changed: installed", appid);
+}
+
+static gboolean __appinfo_remove_cb(gpointer key, gpointer value, gpointer data)
+{
+ struct pkg_event_info *pkg_info = (struct pkg_event_info *)data;
+ struct appinfo *info = (struct appinfo *)value;
+
+ if (strcmp(info->val[AIT_PKGID], pkg_info->pkgid))
+ return FALSE;
+
+ if (pkg_info->target_uid == GLOBAL_USER &&
+ !strcmp(info->val[AIT_GLOBAL], "false"))
+ return FALSE;
+ else if (pkg_info->target_uid != GLOBAL_USER &&
+ !strcmp(info->val[AIT_GLOBAL], "true"))
+ return FALSE;
+
+ _app_property_delete(GPOINTER_TO_UINT(key), info->val[AIT_NAME]);
+
+ _D("appinfo removed: %s", info->val[AIT_NAME]);
+ return TRUE;
+}
+
+static void __appinfo_delete_on_event(uid_t uid, void *data)
+{
+ struct user_appinfo *info;
+ app_property_h prop;
+
+ info = __find_user_appinfo(uid);
+ if (info == NULL) {
+ _E("cannot find appinfo for uid %d", uid);
+ return;
+ }
+
+ prop = _app_property_find(uid);
+ _app_property_cache_invalidate(prop);
+ g_hash_table_foreach_remove(info->tbl, __appinfo_remove_cb,
+ (gpointer)data);
+}
+
+static void __appinfo_insert_on_event(uid_t uid, const char *pkgid)
+{
+ app_property_h prop;
+
+ prop = _app_property_find(uid);
+ _app_property_cache_invalidate(prop);
+ _appinfo_insert(uid, pkgid);
+}
+
+static void __appinfo_update_on_event(uid_t uid, void *data)
+{
+ struct pkg_event_info *pkg_info = (struct pkg_event_info *)data;
+ struct user_appinfo *info;
+ app_property_h prop;
+ pkgmgrinfo_pkginfo_h handle;
+ int ret;
+
+ info = __find_user_appinfo(uid);
+ if (info == NULL) {
+ _E("cannot find appinfo for uid %d", uid);
+ return;
+ }
+
+ prop = _app_property_find(uid);
+ _app_property_cache_invalidate(prop);
+
+ ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkg_info->pkgid, uid, &handle);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to get pkginfo(%s)", pkg_info->pkgid);
+ return;
+ }
+
+ ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP,
+ __appinfo_update_handler, info, info->uid);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to update pkginfo(%s)", pkg_info->pkgid);
+ pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+ return;
+ }
+
+ pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+}
+
+static void __set_blocking(struct pkg_event_info *info)
+{
+ uid_t *uids = NULL;
+ int r;
+ int i;
+
+ if (info->target_uid < REGULAR_UID_MIN) {
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return;
+
+ for (i = 0; i < r; i++) {
+ _appinfo_foreach(uids[i],
+ __appinfo_set_blocking_cb, info);
+ _D("terminate apps by PackageID - %s", info->pkgid);
+ _app_status_terminate_apps_by_pkgid(info->pkgid,
+ uids[i]);
+ }
+ free(uids);
+
+ return;
+ }
+
+ _appinfo_foreach(info->target_uid, __appinfo_set_blocking_cb, info);
+ _D("terminate apps by PackageID - %s", info->pkgid);
+ _app_status_terminate_apps_by_pkgid(info->pkgid, info->target_uid);
+}
+
+static void __unset_blocking(struct pkg_event_info *info)
+{
+ uid_t *uids = NULL;
+ int r;
+ int i;
+
+ if (info->target_uid < REGULAR_UID_MIN) {
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return;
+
+ for (i = 0; i < r; i++) {
+ _appinfo_foreach(uids[i],
+ __appinfo_unset_blocking_cb, info);
+ }
+ free(uids);
+
+ return;
+ }
+
+ _appinfo_foreach(info->target_uid, __appinfo_unset_blocking_cb, info);
+}
+
+static void __delete_on_event(struct pkg_event_info *info)
+{
+ uid_t *uids = NULL;
+ int r;
+ int i;
+
+ if (info->target_uid < REGULAR_UID_MIN) {
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return;
+
+ for (i = 0; i < r; i++)
+ __appinfo_delete_on_event(uids[i], info);
+ free(uids);
+
+ return;
+ }
+
+ __appinfo_delete_on_event(info->target_uid, info);
+}
+
+static void __insert_on_event(struct pkg_event_info *info)
+{
+ uid_t *uids = NULL;
+ int r;
+ int i;
+
+ if (info->target_uid < REGULAR_UID_MIN) {
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return;
+
+ for (i = 0; i < r; i++)
+ __appinfo_insert_on_event(uids[i], info->pkgid);
+ free(uids);
+
+ return;
+ }
+
+ __appinfo_insert_on_event(info->target_uid, info->pkgid);
+}
+
+static void __update_on_event(struct pkg_event_info *info)
+{
+ uid_t *uids = NULL;
+ int r;
+ int i;
+
+ if (info->target_uid < REGULAR_UID_MIN) {
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return;
+
+ for (i = 0; i < r; i++)
+ __appinfo_update_on_event(uids[i], info);
+ free(uids);
+
+ return;
+ }
+
+ __appinfo_update_on_event(info->target_uid, info);
+}
+
+static int __appinfo_is_pkg_exist(uid_t uid, const char *pkgid)
+{
+ int r;
+ struct user_appinfo *info;
+ GHashTableIter iter;
+ gpointer key, value;
+ uid_t *uids = NULL;
+
+ if (pkgid == NULL)
+ return 0;
+
+ if (uid < REGULAR_UID_MIN) {
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return 0;
+
+ uid = uids[0];
+
+ free(uids);
+ }
+
+ info = __find_user_appinfo(uid);
+ if (info == NULL) {
+ _E("cannot find appinfo for uid %d", uid);
+ return 0;
+ }
+
+ g_hash_table_iter_init(&iter, info->tbl);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ struct appinfo *ai = (struct appinfo *)value;
+ if (strcmp(pkgid, ai->val[AIT_PKGID]) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void __appinfo_enable_pkg_apps(uid_t uid, const char *pkgid, int enable)
+{
+ int r;
+ int i;
+ struct user_appinfo *info;
+ GHashTableIter iter;
+ gpointer key, value;
+ uid_t *uids = NULL;
+ struct appinfo *ai;
+ int prev_val;
+ const char *appid;
+
+ if (pkgid == NULL)
+ return;
+
+ if (uid < REGULAR_UID_MIN) {
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return;
+
+ for (i = 0; i < r; i++)
+ __appinfo_enable_pkg_apps(uids[i], pkgid, enable);
+
+ free(uids);
+
+ return;
+ }
+
+ info = __find_user_appinfo(uid);
+ if (info == NULL) {
+ _E("cannot find appinfo for uid %d", uid);
+ return;
+ }
+
+ g_hash_table_iter_init(&iter, info->tbl);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ ai = (struct appinfo *)value;
+
+ if (strcmp(pkgid, ai->val[AIT_PKGID]) == 0) {
+ _appinfo_get_int_value(ai, AIT_ENABLEMENT, &prev_val);
+ _appinfo_set_int_value(ai, AIT_ENABLEMENT, enable);
+ if (prev_val == 0 && enable == 1) {
+ appid = _appinfo_get_value(ai, AIT_NAME);
+ _launch_start_onboot_app_local(uid, appid, ai);
+ }
+ }
+ }
+
+ return;
+}
+
+static void __update_property(uid_t uid)
+{
+ uid_t *uids = NULL;
+ int r;
+ int i;
+
+ if (uid < REGULAR_UID_MIN) {
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return;
+
+ for (i = 0; i < r; i++) {
+ _app_property_unload(uids[i]);
+ _app_property_load(uids[i]);
+ }
+
+ free(uids);
+
+ return;
+ }
+
+ _app_property_unload(uid);
+ _app_property_load(uid);
+}
+
+static int __package_event_cb(uid_t target_uid, int req_id,
+ const char *pkg_type, const char *pkgid,
+ const char *key, const char *val, const void *pmsg, void *data)
+{
+ int ret;
+ char *op;
+ struct pkg_event_info info = {
+ .target_uid = target_uid,
+ .pkgid = pkgid
+ };
+ pkgmgrinfo_pkginfo_h pkginfo;
+
+ if (!strcasecmp(key, "start")) {
+ if (!strcasecmp(val, "uninstall") ||
+ !strcasecmp(val, "update") ||
+ !strcasecmp(val, "move"))
+ __set_blocking(&info);
+
+ g_hash_table_insert(pkg_pending, strdup(pkgid), strdup(val));
+ }
+
+ if (!strcasecmp(key, "error")) {
+ op = g_hash_table_lookup(pkg_pending, pkgid);
+ if (op == NULL)
+ return 0;
+
+ if (!strcasecmp(op, "uninstall") ||
+ !strcasecmp(op, "update") ||
+ !strcasecmp(op, "move"))
+ __unset_blocking(&info);
+
+ g_hash_table_remove(pkg_pending, pkgid);
+ }
+
+ if (!strcasecmp(key, "end")) {
+ op = g_hash_table_lookup(pkg_pending, pkgid);
+ if (op == NULL)
+ return 0;
+
+ if (!strcasecmp(op, "uninstall")) {
+ ret = pkgmgrinfo_pkginfo_get_usr_disabled_pkginfo(
+ info.pkgid, info.target_uid,
+ &pkginfo);
+ if (ret == PMINFO_R_OK) {
+ pkgmgrinfo_pkginfo_destroy_pkginfo(pkginfo);
+ __unset_blocking(&info);
+ __appinfo_enable_pkg_apps(info.target_uid,
+ info.pkgid, 0);
+ } else {
+ __delete_on_event(&info);
+ }
+ __update_property(info.target_uid);
+ } else if (!strcasecmp(op, "install")) {
+ if (!__appinfo_is_pkg_exist(
+ info.target_uid,
+ info.pkgid)) {
+ __insert_on_event(&info);
+ } else {
+ __unset_blocking(&info);
+ __appinfo_enable_pkg_apps(info.target_uid,
+ info.pkgid, 1);
+ }
+ __update_property(info.target_uid);
+ } else if (!strcasecmp(op, "update") ||
+ !strcasecmp(op, "move")) {
+ __update_on_event(&info);
+ __update_property(info.target_uid);
+ _widget_send_dead_signal_for_update_widget(pkgid);
+ _app_status_send_fault_dead_for_update_app(pkgid);
+ }
+
+ g_hash_table_remove(pkg_pending, pkgid);
+ }
+
+ return 0;
+}
+
+static void __add_app_event_info(int req_id, int type, uid_t uid)
+{
+ struct app_event_info *info;
+
+ info = (struct app_event_info *)malloc(sizeof(struct app_event_info));
+ if (info == NULL) {
+ _E("Out of memory");
+ return;
+ }
+
+ info->req_id = req_id;
+ info->type = type;
+ info->uid = uid;
+
+ app_event_list = g_list_append(app_event_list, (gpointer)info);
+}
+
+static struct app_event_info *__find_app_event_info(int req_id, uid_t uid)
+{
+ GList *iter;
+ struct app_event_info *info;
+
+ iter = g_list_first(app_event_list);
+ while (iter) {
+ info = (struct app_event_info *)iter->data;
+ if (info && info->req_id == req_id && info->uid == uid)
+ return info;
+
+ iter = g_list_next(iter);
+ }
+
+ return NULL;
+}
+
+static void __remove_app_event_info(struct app_event_info *info)
+{
+ if (info == NULL)
+ return;
+
+ app_event_list = g_list_remove(app_event_list, info);
+ free(info);
+}
+
+static int __package_app_event_cb(uid_t target_uid, int req_id,
+ const char *pkg_type, const char *pkgid, const char *appid,
+ const char *key, const char *val, const void *pmsg, void *data)
+{
+ struct appinfo *ai;
+ int old;
+ struct app_event_info *ei;
+ uid_t *uids = NULL;
+ int r;
+ int i;
+ struct user_appinfo *info;
+ pkgmgrinfo_appinfo_h handle;
+
+ _D("appid:%s, key:%s, val:%s, req_id: %d, target_uid: %d ", appid, key, val, req_id, target_uid);
+ if (target_uid < REGULAR_UID_MIN) {
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return 0;
+ } else {
+ r = 1;
+ }
+
+ for (i = 0; i < r; i++) {
+ if (uids)
+ target_uid = uids[i];
+ ai = _appinfo_find(target_uid, appid);
+
+ if (!strcasecmp(key, "start")) {
+ if (!strcasecmp(val, "enable_global_app_for_uid") ||
+ !strcasecmp(val, "enable_app")) {
+ if (ai) {
+ _appinfo_get_int_value(ai, AIT_ENABLEMENT, &old);
+ old |= APP_ENABLEMENT_MASK_REQUEST;
+ _appinfo_set_int_value(ai, AIT_ENABLEMENT, old);
+ }
+ __add_app_event_info(req_id, AIT_ENABLEMENT, target_uid);
+ } else if (!strcasecmp(val, "disable_global_app_for_uid") ||
+ !strcasecmp(val, "disable_app")) {
+ __add_app_event_info(req_id, AIT_ENABLEMENT, target_uid);
+ } else if (!strcasecmp(val, "enable_app_splash_screen")) {
+ if (ai) {
+ _appinfo_get_int_value(ai, AIT_SPLASH_SCREEN_DISPLAY,
+ &old);
+ old |= APP_ENABLEMENT_MASK_REQUEST;
+ _appinfo_set_int_value(ai, AIT_SPLASH_SCREEN_DISPLAY,
+ old);
+ __add_app_event_info(req_id, AIT_SPLASH_SCREEN_DISPLAY, target_uid);
+ }
+ } else if (!strcasecmp(val, "disable_app_splash_screen")) {
+ if (ai)
+ __add_app_event_info(req_id, AIT_SPLASH_SCREEN_DISPLAY, target_uid);
+ }
+ } else if (!strcasecmp(key, "end")) {
+ ei = __find_app_event_info(req_id, target_uid);
+ if (ei == NULL)
+ continue;
+
+ if (!strcasecmp(val, "ok")) {
+ if (ei->type == AIT_ENABLEMENT ||
+ ei->type == AIT_SPLASH_SCREEN_DISPLAY) {
+ if (ai) {
+ _appinfo_get_int_value(ai, ei->type, &old);
+ old >>= 1;
+ _appinfo_set_int_value(ai, ei->type, old);
+ } else if (ei->type == AIT_ENABLEMENT) {
+ info = __find_user_appinfo(target_uid);
+ if (info == NULL) {
+ _E("load appinfo for uid %d failed", target_uid);
+ __remove_app_event_info(ei);
+ continue;
+ }
+
+ r = pkgmgrinfo_appinfo_get_usr_appinfo(appid, target_uid, &handle);
+ if (r != PMINFO_R_OK) {
+ _E("get appinfo failed: %s", appid);
+ __remove_app_event_info(ei);
+ continue;
+ }
+
+ _D("add the new appinfo");
+ __insert_appinfo(handle, info);
+ pkgmgrinfo_appinfo_destroy_appinfo(handle);
+ __remove_app_event_info(ei);
+ continue;
+ }
+
+ if (ei->type == AIT_ENABLEMENT &&
+ !(old & APP_ENABLEMENT_MASK_ACTIVE)) {
+ _E("terminate apps: %s", appid);
+ _app_status_terminate_apps(appid,
+ target_uid);
+ } else if (ei->type == AIT_ENABLEMENT &&
+ (old & APP_ENABLEMENT_MASK_ACTIVE)) {
+ _launch_start_onboot_app_local(
+ target_uid, appid, ai);
+ }
+ }
+ } else if (!strcasecmp(val, "fail")) {
+ if (ei->type == AIT_ENABLEMENT ||
+ ei->type == AIT_SPLASH_SCREEN_DISPLAY) {
+ if (ai) {
+ _appinfo_get_int_value(ai, ei->type, &old);
+ old &= APP_ENABLEMENT_MASK_ACTIVE;
+ _appinfo_set_int_value(ai, ei->type, old);
+ }
+ }
+ }
+ __remove_app_event_info(ei);
+ }
+ }
+
+ free(uids);
+ return 0;
+}
+
+static int __init_package_event_handler(void *data)
+{
+ int ret;
+
+ pc = pkgmgr_client_new(PC_LISTENING);
+ if (pc == NULL)
+ return -1;
+
+ pkgmgr_client_set_status_type(pc, PKGMGR_CLIENT_STATUS_ALL);
+
+ ret = pkgmgr_client_listen_status(pc, __package_event_cb, NULL);
+ if (ret < 0)
+ return -1;
+
+ ret = pkgmgr_client_listen_app_status(pc, __package_app_event_cb, NULL);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+static void __fini_package_event_handler(void)
+{
+ pkgmgr_client_free(pc);
+}
+
+int _appinfo_init(void)
+{
+ FILE *fp;
+ char buf[4096] = {0,};
+ char *tmp;
+ char err_buf[1024];
+
+ fp = fopen("/proc/cmdline", "r");
+ if (fp == NULL) {
+ _E("appinfo init failed: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return -1;
+ }
+
+ if (fgets(buf, sizeof(buf), fp) != NULL) {
+ tmp = strstr(buf, "gles");
+ if (tmp != NULL) {
+ if (sscanf(tmp, "gles=%d", &gles) != 1)
+ _D("Failed to convert format");
+ }
+ }
+ fclose(fp);
+
+ user_tbl = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+ __free_user_appinfo);
+ if (user_tbl == NULL)
+ return -1;
+
+ pkg_pending = g_hash_table_new_full(g_str_hash, g_str_equal,
+ free, free);
+ if (pkg_pending == NULL)
+ return -1;
+
+ if (__init_package_event_handler(NULL) < 0)
+ _signal_add_initializer(__init_package_event_handler, NULL);
+
+ return 0;
+}
+
+void _appinfo_fini(void)
+{
+ __fini_package_event_handler();
+ g_hash_table_destroy(user_tbl);
+ g_hash_table_destroy(pkg_pending);
+}
+
+struct appinfo *_appinfo_find(uid_t caller_uid, const char *appid)
+{
+ struct user_appinfo *info;
+
+ if (appid == NULL) {
+ _W("appid is NULL");
+ return NULL;
+ }
+
+ /* search from user table */
+ info = __find_user_appinfo(caller_uid);
+ if (info == NULL)
+ return NULL;
+
+ return g_hash_table_lookup(info->tbl, appid);
+}
+
+int _appinfo_insert(uid_t uid, const char *pkgid)
+{
+ int ret;
+ struct user_appinfo *info;
+ pkgmgrinfo_pkginfo_h handle;
+
+ info = __find_user_appinfo(uid);
+ if (info == NULL) {
+ _E("load appinfo for uid %d failed", uid);
+ return -1;
+ }
+
+ ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgid, uid, &handle);
+ if (ret != PMINFO_R_OK) {
+ _E("get pkginfo failed: %s", pkgid);
+ return -1;
+ }
+
+ ret = pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP,
+ __insert_appinfo, info, info->uid);
+ if (ret != PMINFO_R_OK) {
+ _E("add appinfo of pkg %s failed", pkgid);
+ pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+ return -1;
+ }
+
+ pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+
+ return 0;
+}
+
+static void __reload_appinfo(gpointer key, gpointer value, gpointer user_data)
+{
+ int r;
+ struct user_appinfo *info = (struct user_appinfo *)value;
+
+ g_hash_table_remove_all(info->tbl);
+
+ r = pkgmgrinfo_appinfo_get_usr_installed_list_full(
+ __appinfo_insert_handler, info->uid,
+ PMINFO_APPINFO_GET_SPLASH_SCREEN, info);
+ if (r != PMINFO_R_OK) {
+ __remove_user_appinfo(info->uid);
+ return;
+ }
+
+ _D("reloaded appinfo table for uid %d", info->uid);
+}
+
+void _appinfo_reload(void)
+{
+ g_hash_table_foreach(user_tbl, __reload_appinfo, NULL);
+}
+
+const char *_appinfo_get_value(const struct appinfo *c, enum appinfo_type type)
+{
+ char err_buf[1024];
+
+ if (!c) {
+ errno = EINVAL;
+ _E("appinfo get value: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return NULL;
+ }
+
+ if (type < AIT_START || type >= AIT_MAX)
+ return NULL;
+
+ return c->val[type];
+}
+
+const void *_appinfo_get_ptr_value(const struct appinfo *c,
+ enum appinfo_type type)
+{
+ char err_buf[1024];
+
+ if (!c) {
+ errno = EINVAL;
+ _E("appinfo get value: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return NULL;
+ }
+
+ if (type < AIT_START || type >= AIT_MAX)
+ return NULL;
+
+ return c->val[type];
+}
+
+int _appinfo_get_int_value(const struct appinfo *c, enum appinfo_type type,
+ int *val)
+{
+ char err_buf[1024];
+
+ if (!c) {
+ errno = EINVAL;
+ _E("appinfo get value: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return -1;
+ }
+
+ if (type < AIT_START || type >= AIT_MAX)
+ return -1;
+
+ *val = GPOINTER_TO_INT(c->val[type]);
+
+ return 0;
+}
+
+int _appinfo_get_boolean(const struct appinfo *c, enum appinfo_type type,
+ bool *val)
+{
+ char err_buf[1024] = {0, };
+
+ if (!c || type < AIT_START || type >= AIT_MAX
+ || c->val[type] == NULL) {
+ errno = EINVAL;
+ _E("appinfo get boolean: %s", strerror_r(errno, err_buf,
+ sizeof(err_buf)));
+ return -1;
+ }
+
+ if (!strcmp(c->val[type], "true") || !strcmp(c->val[type], "1")) {
+ *val = true;
+ } else if (!strcmp(c->val[type], "false") ||
+ !strcmp(c->val[type], "0")) {
+ *val = false;
+ } else {
+ errno = EINVAL;
+ _E("Unexpected appinfo field value");
+ return -1;
+ }
+ return 0;
+}
+
+int _appinfo_set_value(struct appinfo *c, enum appinfo_type type,
+ const char *val)
+{
+ if (!c || !val) {
+ errno = EINVAL;
+ _E("appinfo is NULL, type: %d, val %s", type, val);
+ return -1;
+ }
+
+ if (type < AIT_START || type >= AIT_MAX)
+ return -1;
+
+ _D("%s : %s : %s", c->val[AIT_NAME], c->val[type], val);
+ if (c->val[type])
+ free(c->val[type]);
+ c->val[type] = strdup(val);
+
+ return 0;
+}
+
+int _appinfo_set_ptr_value(struct appinfo *c, enum appinfo_type type, void *val)
+{
+ if (!c || !val) {
+ errno = EINVAL;
+ _E("appinfo is NULL, type: %d, val %p", type, val);
+ return -1;
+ }
+
+ if (type < AIT_START || type >= AIT_MAX)
+ return -1;
+
+ _D("%s : %p : %p", c->val[AIT_NAME], c->val[type], val);
+ if (appinfo_table[type].destructor && c->val[type] != NULL)
+ appinfo_table[type].destructor(c->val[type]);
+
+ c->val[type] = (char *)val;
+ return 0;
+}
+
+int _appinfo_set_int_value(struct appinfo *c, enum appinfo_type type, int val)
+{
+ if (!c) {
+ errno = EINVAL;
+ _E("appinfo is NULL, type: %d, val %d", type, val);
+ return -1;
+ }
+
+ if (type < AIT_START || type >= AIT_MAX)
+ return -1;
+
+ _D("%s : %p : %p", c->val[AIT_NAME], c->val[type], val);
+
+ c->val[type] = (char *)GINT_TO_POINTER(val);
+ return 0;
+}
+
+struct _cbinfo {
+ appinfo_iter_callback cb;
+ void *cb_data;
+};
+
+static void __iter_cb(gpointer key, gpointer value, gpointer user_data)
+{
+ struct _cbinfo *cbi = user_data;
+
+ if (cbi == NULL)
+ return;
+
+ cbi->cb(cbi->cb_data, key, value);
+}
+
+void _appinfo_foreach(uid_t uid, appinfo_iter_callback cb, void *user_data)
+{
+ struct user_appinfo *info;
+ struct _cbinfo cbi;
+ char err_buf[1024];
+
+ info = __find_user_appinfo(uid);
+ if (info == NULL)
+ return;
+
+ if (!cb) {
+ errno = EINVAL;
+ _E("appinfo foreach: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return;
+ }
+
+ cbi.cb = cb;
+ cbi.cb_data = user_data;
+
+ g_hash_table_foreach(info->tbl, __iter_cb, &cbi);
+}
+
+int _appinfo_load(uid_t uid)
+{
+ struct user_appinfo *info;
+
+ info = __find_user_appinfo(uid);
+ if (info) {
+ _D("%d appinfo already exists", uid);
+ return 0;
+ }
+
+ info = __add_user_appinfo(uid);
+ if (info == NULL) {
+ _W("Failed to load appinfo - %d", uid);
+ return -1;
+ }
+
+ _D("loaded appinfo table for uid(%d)", uid);
+ return 0;
+}
+
+void _appinfo_unload(uid_t uid)
+{
+ struct user_appinfo *info;
+
+ info = __find_user_appinfo(uid);
+ if (info == NULL) {
+ _D("%d appinfo doesn't exist");
+ return;
+ }
+
+ __remove_user_appinfo(uid);
+ _D("unloaded appinfo table for uid(%d)", uid);
+}
+
+bool _appinfo_is_pkg_updating(const char *pkgid)
+{
+ char *op;
+
+ if (pkg_pending == NULL)
+ return false;
+
+ op = g_hash_table_lookup(pkg_pending, pkgid);
+ if (op != NULL && !strcasecmp(op, "update"))
+ return true;
+
+ return false;
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <aul.h>
+
+#include "amd_util.h"
+#include "amd_app_status.h"
+#include "amd_appinfo.h"
+#include "amd_launch.h"
+#include "amd_login_monitor.h"
+#include "amd_signal.h"
+#include "amd_cooldown.h"
+
+static int cooldown_status;
+
+static void __cooldown_limitaction(app_status_h app_status, void *data)
+{
+ const struct appinfo *ai;
+ const char *taskmanage;
+ const char *cooldown;
+ const char *appid;
+ int app_type;
+ uid_t uid;
+
+ if (_app_status_is_home_app(app_status))
+ return;
+
+ app_type = _app_status_get_app_type(app_status);
+ if (app_type == AT_WIDGET_APP || app_type == AT_WATCH_APP)
+ return;
+
+ uid = _app_status_get_uid(app_status);
+ appid = _app_status_get_appid(app_status);
+ ai = _appinfo_find(uid, appid);
+ if (ai == NULL)
+ return;
+
+ cooldown = _appinfo_get_value(ai, AIT_COOLDOWN);
+ if (cooldown && strcmp(cooldown, "true") != 0) {
+ if (app_type == AT_UI_APP) {
+ taskmanage = _appinfo_get_value(ai, AIT_TASKMANAGE);
+ if (taskmanage && strcmp(taskmanage, "true") != 0)
+ return;
+ }
+
+ _app_status_terminate_apps(appid, uid);
+ }
+}
+
+static void __cooldown_release(void)
+{
+ uid_state state;
+ uid_t *uids;
+ int r;
+ int i;
+
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return;
+
+ for (i = 0; i < r; ++i) {
+ state = _login_monitor_get_uid_state(uids[i]);
+ if (state == UID_STATE_ONLINE || state == UID_STATE_ACTIVE)
+ _launch_start_onboot_apps(uids[i]);
+ }
+ free(uids);
+}
+
+static int __cooldown_signal_cb(const char *status, void *data)
+{
+ _D("status %s", status);
+ if (strcmp(status, COOLDOWN_STATUS_LIMITACTION) == 0) {
+ cooldown_status = COOLDOWN_LIMIT;
+ _app_status_foreach_running_appinfo(__cooldown_limitaction,
+ NULL);
+ } else if (strcmp(status, COOLDOWN_STATUS_RELEASE) == 0 &&
+ cooldown_status != COOLDOWN_RELEASE) {
+ cooldown_status = COOLDOWN_RELEASE;
+ __cooldown_release();
+ }
+
+ return 0;
+}
+
+int _cooldown_get_status(void)
+{
+ return cooldown_status;
+}
+
+int _cooldown_check_mode(const struct appinfo *ai)
+{
+ const char *taskmanage;
+ const char *cooldown;
+ const char *comptype;
+
+ if (cooldown_status != COOLDOWN_LIMIT)
+ return 0;
+
+ cooldown = _appinfo_get_value(ai, AIT_COOLDOWN);
+ if (cooldown && strcmp(cooldown, "true") == 0)
+ return 0;
+
+ comptype = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (comptype == NULL) {
+ _E("Failed to get comptype");
+ return -1;
+ }
+
+ if (strcmp(comptype, APP_TYPE_WIDGET) == 0 ||
+ strcmp(comptype, APP_TYPE_WATCH) == 0)
+ return 0;
+
+ if (strcmp(comptype, APP_TYPE_UI) == 0) {
+ taskmanage = _appinfo_get_value(ai, AIT_TASKMANAGE);
+ if (taskmanage && strcmp(taskmanage, "false") == 0)
+ return 0;
+ }
+
+ _W("Cannot launch this app in COOLDOWN mode");
+ return -1;
+}
+
+static int __register_cooldown_signal(void *data)
+{
+ return aul_listen_cooldown_signal(__cooldown_signal_cb, data);
+}
+
+int _cooldown_init(void)
+{
+ int r;
+
+ _D("cooldown init");
+
+ r = __register_cooldown_signal(NULL);
+ if (r < 0) {
+ _W("Failed to register cooldown signal");
+ _signal_add_initializer(__register_cooldown_signal, NULL);
+ }
+
+ return 0;
+}
+
+void _cooldown_fini(void)
+{
+ _D("cooldown fini");
+ aul_listen_cooldown_signal(NULL, NULL);
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <malloc.h>
+#include <stdlib.h>
+
+#include <cynara-client.h>
+#include <cynara-creds-socket.h>
+#include <cynara-session.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <aul_sock.h>
+#include <aul_svc.h>
+#include <aul_svc_priv_key.h>
+#include <amd_app_com.h>
+#include <amd_request.h>
+#include <amd_appinfo.h>
+#include <aul.h>
+#include <aul_screen_connector.h>
+
+#include "amd_util.h"
+#include "amd_app_status.h"
+#include "amd_widget.h"
+
+#define SYSPOPUP_NAME "_INTERNAL_SYSPOPUP_NAME_"
+#define PRIVILEGE_WIDGET_VIEWER \
+ "http://tizen.org/privilege/widget.viewer"
+#define PRIVILEGE_APPMANAGER_LAUNCH \
+ "http://tizen.org/privilege/appmanager.launch"
+#define PRIVILEGE_APPMANAGER_KILL \
+ "http://tizen.org/privilege/appmanager.kill"
+#define PRIVILEGE_APPMANAGER_KILL_BGAPP \
+ "http://tizen.org/privilege/appmanager.kill.bgapp"
+#define PRIVILEGE_DOWNLOAD \
+ "http://tizen.org/privilege/download"
+#define PRIVILEGE_CALL \
+ "http://tizen.org/privilege/call"
+#define PRIVILEGE_SYSTEM_SETTING \
+ "http://tizen.org/privilege/systemsettings.admin"
+#define PRIVILEGE_PLATFORM \
+ "http://tizen.org/privilege/internal/default/platform"
+
+static cynara *r_cynara;
+
+struct caller_info {
+ char *user;
+ char *client;
+ char *session;
+};
+
+typedef int (*checker_func)(struct caller_info *info, request_h req,
+ void *data);
+
+struct checker_info {
+ int cmd;
+ checker_func checker;
+ void *data;
+};
+
+static const char *__convert_operation_to_privilege(const char *operation)
+{
+ if (operation == NULL)
+ return NULL;
+ else if (!strcmp(operation, AUL_SVC_OPERATION_DOWNLOAD))
+ return PRIVILEGE_DOWNLOAD;
+ else if (!strcmp(operation, AUL_SVC_OPERATION_CALL))
+ return PRIVILEGE_CALL;
+ else if (!strcmp(operation, AUL_SVC_OPERATION_LAUNCH_WIDGET))
+ return PRIVILEGE_WIDGET_VIEWER;
+
+ return NULL;
+}
+
+static void __destroy_caller_info(struct caller_info *info)
+{
+ if (info == NULL)
+ return;
+
+ if (info->client)
+ free(info->client);
+
+ if (info->session)
+ free(info->session);
+
+ if (info->user)
+ free(info->user);
+}
+
+static int __get_caller_info_from_cynara(int sockfd, struct caller_info *info)
+{
+ pid_t pid;
+ int r;
+ char buf[MAX_LOCAL_BUFSZ];
+
+ if (info == NULL)
+ return -1;
+
+ r = cynara_creds_socket_get_pid(sockfd, &pid);
+ if (r != CYNARA_API_SUCCESS) {
+ cynara_strerror(r, buf, MAX_LOCAL_BUFSZ);
+ _E("cynara_creds_socket_get_pid failed: %s", buf);
+ return -1;
+ }
+
+ info->session = cynara_session_from_pid(pid);
+ if (info->session == NULL) {
+ _E("cynara_session_from_pid failed.");
+ return -1;
+ }
+
+ r = cynara_creds_socket_get_user(sockfd, USER_METHOD_DEFAULT,
+ &(info->user));
+ if (r != CYNARA_API_SUCCESS) {
+ cynara_strerror(r, buf, MAX_LOCAL_BUFSZ);
+ _E("cynara_cred_socket_get_user failed.");
+ return -1;
+ }
+
+ r = cynara_creds_socket_get_client(sockfd, CLIENT_METHOD_DEFAULT,
+ &(info->client));
+ if (r != CYNARA_API_SUCCESS) {
+ cynara_strerror(r, buf, MAX_LOCAL_BUFSZ);
+ _E("cynara_creds_socket_get_client failed.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __check_privilege(struct caller_info *info, const char *privilege)
+{
+ int ret;
+ char buf[MAX_LOCAL_BUFSZ];
+
+ ret = cynara_check(r_cynara, info->client, info->session, info->user,
+ privilege);
+ switch (ret) {
+ case CYNARA_API_ACCESS_ALLOWED:
+ _D("%s(%s) from user %s privilege %s allowed.", info->client,
+ info->session, info->user, privilege);
+ ret = 0;
+ break;
+ case CYNARA_API_ACCESS_DENIED:
+ _E("%s(%s) from user %s privilege %s denied.", info->client,
+ info->session, info->user, privilege);
+ ret = -1;
+ break;
+ default:
+ cynara_strerror(ret, buf, MAX_LOCAL_BUFSZ);
+ _E("cynara_check failed: %s", buf);
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+static int __simple_checker(struct caller_info *info, request_h req, void *data)
+{
+ return __check_privilege(info, (const char *)data);
+}
+
+static int __widget_viewer_checker(struct caller_info *info, request_h req,
+ void *data)
+{
+ char *appid = NULL;
+ const char *apptype;
+ struct appinfo *appinfo;
+ bundle *appcontrol = _request_get_bundle(req);
+
+ if (!appcontrol) {
+ _E("wrong argument");
+ return -1;
+ }
+
+ bundle_get_str(appcontrol, AUL_K_APPID, &appid);
+ if (!appid) {
+ _E("can not resolve appid. request denied.");
+ return -1;
+ }
+
+ appinfo = _appinfo_find(_request_get_target_uid(req), appid);
+ if (!appinfo) {
+ _E("can not resolve appinfo of %s. request denied.", appid);
+ return -1;
+ }
+
+ apptype = _appinfo_get_value(appinfo, AIT_COMPTYPE);
+ if (!apptype) {
+ _E("can not resolve apptype of %s. request denied.", appid);
+ return -1;
+ }
+
+ if (!strcmp(apptype, APP_TYPE_WIDGET) ||
+ !strcmp(apptype, APP_TYPE_WATCH))
+ return __check_privilege(info, PRIVILEGE_WIDGET_VIEWER);
+
+ _E("illegal app type of request: %s - " \
+ "only widget or watch apps are allowed", apptype);
+
+ return -1;
+}
+
+static int __app_term_by_pid_async_checker(struct caller_info *info,
+ request_h req, void *data)
+{
+ int pid;
+ char *term_pid;
+ bool is_widget = false;
+ bundle *kb;
+
+ kb = _request_get_bundle(req);
+ if (kb == NULL)
+ return -1;
+
+ bundle_get_str(kb, AUL_K_APPID, &term_pid);
+ if (term_pid == NULL)
+ return -1;
+
+ pid = atoi(term_pid);
+ is_widget = _widget_exist(pid, _request_get_target_uid(req));
+
+ if (is_widget)
+ return __check_privilege(info, PRIVILEGE_WIDGET_VIEWER);
+
+ return __simple_checker(info, req, data);
+}
+
+static int __appcontrol_checker(struct caller_info *info, request_h req,
+ void *data)
+{
+ bundle *appcontrol;
+ const char *op_priv = NULL;
+ char *op = NULL;
+ const char *below;
+ const char *syspopup;
+ int ret;
+
+ appcontrol = _request_get_bundle(req);
+ if (appcontrol == NULL)
+ return 0;
+
+ ret = bundle_get_str(appcontrol, AUL_SVC_K_OPERATION, &op);
+ if (ret == BUNDLE_ERROR_NONE)
+ op_priv = __convert_operation_to_privilege(op);
+
+ if (op_priv) {
+ if (!strcmp(op_priv, PRIVILEGE_WIDGET_VIEWER))
+ return __widget_viewer_checker(info, req, data);
+
+ ret = __check_privilege(info, op_priv);
+ if (ret < 0)
+ return ret;
+ }
+
+ syspopup = bundle_get_val(appcontrol, SYSPOPUP_NAME);
+ below = bundle_get_val(appcontrol, AUL_SVC_K_RELOCATE_BELOW);
+ if (below || syspopup) {
+ ret = __check_privilege(info, PRIVILEGE_PLATFORM);
+ if (ret < 0)
+ return ret;
+ }
+
+ return __check_privilege(info, PRIVILEGE_APPMANAGER_LAUNCH);
+}
+
+static int __com_create_checker(struct caller_info *info, request_h req,
+ void *data)
+{
+ char *privilege = NULL;
+ bundle *kb = _request_get_bundle(req);
+
+ bundle_get_str(kb, AUL_K_COM_PRIVILEGE, &privilege);
+ if (!privilege)
+ return 0; /* non-privileged */
+
+ return __check_privilege(info, privilege);
+}
+
+static int __com_join_checker(struct caller_info *info, request_h req,
+ void *data)
+{
+ char *endpoint = NULL;
+ const char *privilege;
+ bundle *kb = _request_get_bundle(req);
+
+ bundle_get_str(kb, AUL_K_COM_ENDPOINT, &endpoint);
+ if (!endpoint)
+ return -1;
+
+ privilege = _app_com_get_privilege(endpoint);
+ if (!privilege)
+ return 0; /* non-privileged */
+
+ return __check_privilege(info, privilege);
+}
+
+static int __label_checker(struct caller_info *info, request_h req,
+ void *data)
+{
+ if (strcmp(info->client, "System::Privileged") == 0)
+ return 0;
+
+ return -1;
+}
+
+static int __screen_connector_checker(struct caller_info *info, request_h req,
+ void *data)
+{
+ int ret;
+ bundle *b = _request_get_bundle(req);
+ const char *type_str;
+ int type;
+
+ if (b == NULL)
+ return -1;
+
+ type_str = bundle_get_val(b, AUL_K_SCREEN_TYPE);
+ if (type_str == NULL)
+ return -1;
+
+ type = atoi(type_str);
+ if (type & AUL_SCREEN_TYPE_UI)
+ ret = __check_privilege(info, PRIVILEGE_PLATFORM);
+ else
+ ret = __check_privilege(info, PRIVILEGE_WIDGET_VIEWER);
+
+ return ret;
+}
+
+static struct checker_info checker_table[] = {
+ {
+ .cmd = APP_OPEN,
+ .checker = __appcontrol_checker,
+ .data = NULL
+ },
+ {
+ .cmd = APP_RESUME,
+ .checker = __appcontrol_checker,
+ .data = NULL
+ },
+ {
+ .cmd = APP_START,
+ .checker = __appcontrol_checker,
+ .data = NULL
+ },
+ {
+ .cmd = APP_START_RES,
+ .checker = __appcontrol_checker,
+ .data = NULL
+ },
+ {
+ .cmd = APP_TERM_BY_PID_WITHOUT_RESTART,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_APPMANAGER_KILL
+ },
+ {
+ .cmd = APP_TERM_BY_PID_ASYNC,
+ .checker = __app_term_by_pid_async_checker,
+ .data = PRIVILEGE_APPMANAGER_KILL
+ },
+ {
+ .cmd = APP_TERM_BY_PID,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_APPMANAGER_KILL
+ },
+ {
+ .cmd = APP_KILL_BY_PID,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_APPMANAGER_KILL
+ },
+ {
+ .cmd = APP_TERM_BGAPP_BY_PID,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_APPMANAGER_KILL_BGAPP
+ },
+ {
+ .cmd = APP_COM_JOIN,
+ .checker = __com_create_checker,
+ .data = NULL
+ },
+ {
+ .cmd = APP_COM_CREATE,
+ .checker = __com_join_checker,
+ .data = NULL
+ },
+ {
+ .cmd = APP_SET_APP_CONTROL_DEFAULT_APP,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_SYSTEM_SETTING
+ },
+ {
+ .cmd = APP_UNSET_APP_CONTROL_DEFAULT_APP,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_SYSTEM_SETTING
+ },
+ {
+ .cmd = APP_START_ASYNC,
+ .checker = __appcontrol_checker,
+ .data = NULL
+ },
+ {
+ .cmd = APP_TERM_BY_PID_SYNC,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_APPMANAGER_KILL
+ },
+ {
+ .cmd = APP_TERM_BY_PID_SYNC_WITHOUT_RESTART,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_APPMANAGER_KILL
+ },
+ {
+ .cmd = APP_UPDATE_RUA_STAT,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_PLATFORM
+ },
+ {
+ .cmd = APP_ADD_HISTORY,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_PLATFORM
+ },
+ {
+ .cmd = APP_REMOVE_HISTORY,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_PLATFORM
+ },
+ {
+ .cmd = APP_SET_ALIAS_APPID,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_SYSTEM_SETTING
+ },
+ {
+ .cmd = APP_UNSET_ALIAS_APPID,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_SYSTEM_SETTING
+ },
+ {
+ .cmd = APP_ENABLE_ALIAS_INFO,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_SYSTEM_SETTING
+ },
+ {
+ .cmd = APP_DISABLE_ALIAS_INFO,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_SYSTEM_SETTING
+ },
+ {
+ .cmd = LAUNCHPAD_LAUNCH_SIGNAL,
+ .checker = __label_checker,
+ .data = NULL
+ },
+ {
+ .cmd = LAUNCHPAD_DEAD_SIGNAL,
+ .checker = __label_checker,
+ .data = NULL
+ },
+ {
+ .cmd = ADD_SCREEN_VIEWER,
+ .checker = __screen_connector_checker,
+ .data = NULL
+ },
+ {
+ .cmd = REMOVE_SCREEN_VIEWER,
+ .checker = __screen_connector_checker,
+ .data = NULL
+ },
+ {
+ .cmd = APP_UPDATE_REQUESTED,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_PLATFORM
+ },
+ {
+ .cmd = APP_WINDOW_ATTACH,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_PLATFORM
+ },
+ {
+ .cmd = APP_WINDOW_DETACH,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_PLATFORM
+ },
+ {
+ .cmd = APP_START_RES_ASYNC,
+ .checker = __appcontrol_checker,
+ .data = NULL
+ },
+ {
+ .cmd = WIDGET_RUNNING_INFO,
+ .checker = __simple_checker,
+ .data = PRIVILEGE_PLATFORM
+ }
+};
+
+static int checker_len = sizeof(checker_table) / sizeof(struct checker_info);
+
+static int __check_privilege_by_checker(request_h req, struct caller_info *info)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < checker_len; i++) {
+ if (checker_table[i].cmd == _request_get_cmd(req)) {
+ ret = checker_table[i].checker(info, req,
+ checker_table[i].data);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int __check_command(int cmd)
+{
+ int i;
+
+ for (i = 0; i < checker_len; i++) {
+ if (checker_table[i].cmd == cmd)
+ return 1;
+ }
+
+ return 0;
+}
+
+int _cynara_check_privilege(request_h req)
+{
+ int r;
+ struct caller_info info = {NULL, NULL, NULL};
+
+ if (!__check_command(_request_get_cmd(req)))
+ return 0;
+
+ r = __get_caller_info_from_cynara(_request_get_fd(req), &info);
+ if (r < 0) {
+ _E("Failed to get caller info");
+ __destroy_caller_info(&info);
+ return -1;
+ }
+
+ r = __check_privilege_by_checker(req, &info);
+
+ __destroy_caller_info(&info);
+
+ return r;
+}
+
+int _cynara_init(void)
+{
+ int ret;
+
+ ret = cynara_initialize(&r_cynara, NULL);
+ if (ret != CYNARA_API_SUCCESS) {
+ _E("cynara initialize failed.");
+ return ret;
+ }
+
+ return 0;
+}
+
+void _cynara_finish(void)
+{
+ if (r_cynara == NULL)
+ return;
+
+ cynara_finish(r_cynara);
+ r_cynara = NULL;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include <aul.h>
+#include <bundle_internal.h>
+#include <tzplatform_config.h>
+
+#include "amd_util.h"
+#include "amd_signal.h"
+#include "amd_app_status.h"
+#include "amd_extractor.h"
+
+#define PATH_APP_ROOT tzplatform_getenv(TZ_USER_APP)
+#define PATH_GLOBAL_APP_RO_ROOT tzplatform_getenv(TZ_SYS_RO_APP)
+#define PATH_GLOBAL_APP_RW_ROOT tzplatform_getenv(TZ_SYS_RW_APP)
+
+static GHashTable *mount_point_hash;
+
+static const char *__get_app_root_path(const struct appinfo *ai)
+{
+ const char *path_app_root;
+ const char *global;
+ const char *preload;
+
+ preload = _appinfo_get_value(ai, AIT_PRELOAD);
+ global = _appinfo_get_value(ai, AIT_GLOBAL);
+ if (global && strncmp(global, "true", strlen("true")) == 0) {
+ if (preload && strncmp(preload, "true", strlen("true")) == 0)
+ path_app_root = PATH_GLOBAL_APP_RO_ROOT;
+ else
+ path_app_root = PATH_GLOBAL_APP_RW_ROOT;
+ } else {
+ path_app_root = PATH_APP_ROOT;
+ }
+
+ return path_app_root;
+}
+
+char **_extractor_mountable_get_tep_paths(const struct appinfo *ai)
+{
+ char tep_path[PATH_MAX];
+ char **mnt_path;
+ const char *pkgid;
+ const char *tep_name;
+
+ if (ai == NULL)
+ return NULL;
+
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ if (pkgid == NULL)
+ return NULL;
+
+ tep_name = _appinfo_get_value(ai, AIT_TEP);
+ if (tep_name == NULL)
+ return NULL;
+
+ mnt_path = (char **)malloc(sizeof(char *) * 2);
+ if (mnt_path == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ mnt_path[1] = strdup(tep_name);
+ snprintf(tep_path, PATH_MAX, "%s/%s/tep/mount",
+ __get_app_root_path(ai), pkgid);
+ mnt_path[0] = strdup(tep_path);
+
+ return mnt_path;
+}
+
+char **_extractor_mountable_get_tpk_paths(const struct appinfo *ai)
+{
+ char mount_point[PATH_MAX];
+ char **mnt_path;
+ const char *pkgid;
+ const char *tpk;
+
+ if (ai == NULL)
+ return NULL;
+
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ if (pkgid == NULL)
+ return NULL;
+
+ tpk = _appinfo_get_value(ai, AIT_MOUNTABLE_PKG);
+ if (tpk == NULL)
+ return NULL;
+
+ mnt_path = (char **)malloc(sizeof(char *) * 2);
+ if (mnt_path == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ mnt_path[1] = strdup(tpk);
+ snprintf(mount_point, PATH_MAX, "%s/%s/.pkg",
+ __get_app_root_path(ai), pkgid);
+ mnt_path[0] = strdup(mount_point);
+
+ return mnt_path;
+}
+
+static void __free_path(char **path, int cnt)
+{
+ int i;
+
+ if (path == NULL)
+ return;
+
+ for (i = 0; i < cnt; i++) {
+ if (path[i])
+ free(path[i]);
+ }
+ free(path);
+}
+
+static void __free_set(gpointer data)
+{
+ g_hash_table_destroy((GHashTable *)data);
+}
+
+static void __prepare_map(void)
+{
+ if (mount_point_hash == NULL) {
+ mount_point_hash = g_hash_table_new_full(g_str_hash,
+ g_str_equal, free, __free_set);
+ }
+}
+
+static void __put_mount_path(const struct appinfo *ai, const char *str)
+{
+ const char *appid;
+ GHashTable *set;
+
+ __prepare_map();
+ set = g_hash_table_lookup(mount_point_hash, str);
+ if (set == NULL) {
+ set = g_hash_table_new_full(g_str_hash, g_str_equal,
+ free, NULL);
+ if (set == NULL)
+ return;
+ g_hash_table_insert(mount_point_hash, strdup(str), set);
+ }
+
+ appid = _appinfo_get_value(ai, AIT_NAME);
+ g_hash_table_insert(set, strdup(appid), NULL);
+}
+
+static bool __is_unmountable(const char *appid, const char *key)
+{
+ GHashTable *set;
+
+ if (_app_status_get_process_cnt(appid) > 1)
+ return false;
+
+ __prepare_map();
+ set = g_hash_table_lookup(mount_point_hash, key);
+
+ if (set == NULL)
+ return false;
+
+ g_hash_table_remove(set, appid);
+ if (g_hash_table_size(set) > 0)
+ return false;
+
+ return true;
+}
+
+void _extractor_mount(const struct appinfo *ai, bundle *kb,
+ _extractor_mountable mountable)
+{
+ int ret;
+ const char **array = NULL;
+ int len = 0;
+ const char *default_array[1] = { NULL };
+ char **new_array = NULL;
+ int i;
+ bool dup = false;
+ const char *pkgid = NULL;
+ char **mnt_path;
+
+ mnt_path = mountable(ai);
+ if (mnt_path == NULL)
+ return;
+
+ if (!mnt_path[0] || !mnt_path[1]) {
+ __free_path(mnt_path, 2);
+ return;
+ }
+
+ array = bundle_get_str_array(kb, AUL_TEP_PATH, &len);
+ if (array == NULL) {
+ default_array[0] = mnt_path[0];
+ bundle_add_str_array(kb, AUL_TEP_PATH,
+ default_array, 1);
+ } else {
+ for (i = 0; i < len; i++) {
+ if (strcmp(mnt_path[0], array[i]) == 0) {
+ dup = true;
+ break;
+ }
+ }
+
+ if (!dup) {
+ new_array = malloc(sizeof(char *) * (len + 1));
+ if (new_array == NULL) {
+ _E("out of memory");
+ __free_path(mnt_path, 2);
+ return;
+ }
+
+ for (i = 0; i < len; i++)
+ new_array[i] = strdup(array[i]);
+ new_array[len] = strdup(mnt_path[0]);
+ bundle_del(kb, AUL_TEP_PATH);
+ bundle_add_str_array(kb, AUL_TEP_PATH,
+ (const char **)new_array, len + 1);
+ __free_path(new_array, len + 1);
+ }
+ }
+
+ __put_mount_path(ai, mnt_path[0]);
+ ret = aul_is_tep_mount_dbus_done(mnt_path[0]);
+ if (ret != 1) {
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ ret = _signal_send_tep_mount(mnt_path, pkgid);
+ if (ret < 0) {
+ _E("dbus error %d", ret);
+ } else {
+ _D("Mount request was sent %s %s",
+ mnt_path[0], mnt_path[1]);
+ }
+ }
+
+ __free_path(mnt_path, 2);
+}
+
+void _extractor_unmount(int pid, _extractor_mountable mountable)
+{
+ const char *appid;
+ const struct appinfo *ai;
+ int ret;
+ char **mnt_path;
+ app_status_h app_status;
+ uid_t uid;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return;
+
+ uid = _app_status_get_uid(app_status);
+ appid = _app_status_get_appid(app_status);
+ if (appid == NULL)
+ return;
+
+ ai = _appinfo_find(uid, appid);
+ if (ai == NULL)
+ return;
+
+ mnt_path = mountable(ai);
+ if (mnt_path == NULL)
+ return;
+
+ if (!__is_unmountable(appid, mnt_path[0]))
+ return;
+
+ g_hash_table_remove(mount_point_hash, mnt_path[0]);
+ ret = _signal_send_tep_unmount(mnt_path[0]);
+ if (ret < 0)
+ _E("Failed to send unmount: %s", mnt_path[0]);
+ else
+ _D("Unmount request was sent %s", mnt_path[0]);
+
+ __free_path(mnt_path, 2);
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/inotify.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "amd_util.h"
+#include "amd_inotify.h"
+
+#define INOTIFY_BUF (1024 * ((sizeof(struct inotify_event)) + 16))
+
+struct inotify_watch_info {
+ int wd;
+ inotify_watch_cb cb;
+ void *data;
+};
+
+struct inotify_info {
+ int fd;
+ GIOChannel *io;
+ guint id;
+ bool initialized;
+};
+
+static struct inotify_info __inotify;
+static GList *__watch_list;
+
+static void __destroy_inotify_watch_info(gpointer data)
+{
+ struct inotify_watch_info *info = (struct inotify_watch_info *)data;
+
+ if (info == NULL)
+ return;
+
+ if (info->wd > 0)
+ inotify_rm_watch(__inotify.fd, info->wd);
+ free(info);
+}
+
+static struct inotify_watch_info *__create_inotify_watch_info(const char *path,
+ uint32_t mask, inotify_watch_cb cb, void *data)
+{
+ struct inotify_watch_info *info;
+
+ info = calloc(1, sizeof(struct inotify_watch_info));
+ if (info == NULL) {
+ _E("Out of memory");
+ return NULL;
+ }
+
+ info->wd = inotify_add_watch(__inotify.fd, path, mask);
+ if (info->wd < 0) {
+ _E("Failed to add inotify watch, path(%s), errno(%d)",
+ path, errno);
+ free(info);
+ return NULL;
+ }
+
+ info->cb = cb;
+ info->data = data;
+
+ return info;
+}
+
+static void __fini_inotify(void)
+{
+ if (__inotify.id) {
+ g_source_remove(__inotify.id);
+ __inotify.id = 0;
+ }
+
+ if (__inotify.io) {
+ g_io_channel_unref(__inotify.io);
+ __inotify.io = NULL;
+ }
+
+ if (__inotify.fd > 0) {
+ close(__inotify.fd);
+ __inotify.fd = 0;
+ }
+
+ __inotify.initialized = false;
+}
+
+static struct inotify_watch_info *__find_inotify_watch_info(int wd)
+{
+ struct inotify_watch_info *info;
+ GList *iter;
+
+ iter = __watch_list;
+ while (iter) {
+ info = (struct inotify_watch_info *)iter->data;
+ if (info->wd == wd)
+ return info;
+
+ iter = g_list_next(iter);
+ }
+
+ return NULL;
+}
+
+static gboolean __inotify_watch_cb(GIOChannel *io, GIOCondition cond,
+ gpointer data)
+{
+ char buf[INOTIFY_BUF];
+ ssize_t len;
+ int i = 0;
+ struct inotify_event *e;
+ int fd = g_io_channel_unix_get_fd(io);
+ struct inotify_watch_info *info;
+
+ len = read(fd, buf, sizeof(buf));
+ if (len < 0) {
+ _W("Failed to read from a inotify file descriptor");
+ return G_SOURCE_CONTINUE;
+ }
+
+ while (i < len) {
+ e = (struct inotify_event *)&buf[i];
+ if (e->len) {
+ info = __find_inotify_watch_info(e->wd);
+ if (info && !info->cb(e->name, info->data)) {
+ __watch_list = g_list_remove(__watch_list,
+ info);
+ __destroy_inotify_watch_info(info);
+ }
+ }
+
+ i += offsetof(struct inotify_event, name) + e->len;
+ if (i >= INOTIFY_BUF)
+ break;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static int __init_inotify(void)
+{
+ GIOCondition cond = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP;
+
+ if (__inotify.initialized)
+ return 0;
+
+ __inotify.fd = inotify_init1(IN_CLOEXEC);
+ if (__inotify.fd < 0) {
+ _E("Failed to initialize inotify");
+ return -1;
+ }
+
+ __inotify.io = g_io_channel_unix_new(__inotify.fd);
+ if (__inotify.io == NULL) {
+ _E("Failed to create a new GIOChannel");
+ __fini_inotify();
+ return -1;
+ }
+
+ __inotify.id = g_io_add_watch(__inotify.io, cond,
+ __inotify_watch_cb, NULL);
+ if (__inotify.id == 0) {
+ _E("Failed to add GIOChannel watch");
+ __fini_inotify();
+ return -1;
+ }
+
+ __inotify.initialized = true;
+
+ return 0;
+}
+
+int _inotify_add_watch(const char *path, uint32_t mask,
+ inotify_watch_cb callback, void *data)
+{
+ struct inotify_watch_info *info;
+
+ if (path == NULL || callback == NULL) {
+ _E("Invalid parameter");
+ return -1;
+ }
+
+ if (__init_inotify() < 0)
+ return -1;
+
+ info = __create_inotify_watch_info(path, mask, callback, data);
+ if (info == NULL)
+ return -1;
+
+ __watch_list = g_list_append(__watch_list, info);
+
+ return info->wd;
+}
+
+void _inotify_rm_watch(int wd)
+{
+ struct inotify_watch_info *info;
+
+ info = __find_inotify_watch_info(wd);
+ if (!info)
+ return;
+
+ __watch_list = g_list_remove(__watch_list, info);
+ __destroy_inotify_watch_info(info);
+}
+
+int _inotify_init(void)
+{
+ _D("inotify init");
+
+ __init_inotify();
+
+ return 0;
+}
+
+void _inotify_fini(void)
+{
+ _D("inotify fini");
+
+ if (__watch_list)
+ g_list_free_full(__watch_list, __destroy_inotify_watch_info);
+
+ __fini_inotify();
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdbool.h>
+#include <malloc.h>
+#include <sys/mman.h>
+
+#include <glib.h>
+#include <aul.h>
+#include <wayland-client.h>
+#include <tizen-extension-client-protocol.h>
+#include <xkbcommon/xkbcommon.h>
+
+#include "amd_util.h"
+#include "amd_input.h"
+#include "amd_wayland.h"
+
+#define TIMEOUT_VAL 1000
+
+static bool listener_added;
+static bool locked;
+static bool init_done;
+static guint timer;
+static struct tizen_keyrouter *keyrouter;
+static struct tizen_input_device_manager *input_devmgr;
+static struct wl_display *display;
+static struct wl_seat *seat;
+struct xkb_context *g_ctx;
+struct xkb_keymap *g_keymap;
+struct wl_keyboard *keyboard;
+
+typedef struct _keycode_map {
+ xkb_keysym_t keysym;
+ xkb_keycode_t *keycodes;
+ int nkeycodes;
+} keycode_map;
+
+static void __keyboard_keymap(void *data, struct wl_keyboard *keyboard,
+ uint32_t format, int fd, uint32_t size)
+{
+ char *map = NULL;
+
+ _D("format=%d, fd=%d, size=%d", format, fd, size);
+ if (!g_ctx) {
+ _E("This client failed to make xkb context");
+ close(fd);
+ return;
+ }
+
+ if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
+ _E("Invaild format: %d", format);
+ close(fd);
+ return;
+ }
+
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED) {
+ _E("Failed to mmap from fd(%d) size(%d)", fd, size);
+ close(fd);
+ return;
+ }
+
+ g_keymap = xkb_map_new_from_string(g_ctx, map,
+ XKB_KEYMAP_FORMAT_TEXT_V1, 0);
+ munmap(map, size);
+ if (!g_keymap)
+ _E("Failed to get keymap from fd(%d)", fd);
+ close(fd);
+}
+
+static void __keyboard_enter(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, struct wl_surface *surface,
+ struct wl_array *keys)
+{
+ _D("serial=%d", serial);
+}
+
+static void __keyboard_leave(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, struct wl_surface *surface)
+{
+ _D("serial=%d", serial);
+}
+
+static void __keyboard_key(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, uint32_t time, uint32_t key, uint32_t state_w)
+{
+ _D("serial=%d, time=%d, key=%d, state_w=%d",
+ serial, time, key, state_w);
+}
+
+static void __keyboard_modifiers(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
+ uint32_t mods_locked, uint32_t group)
+{
+ _D("serial=%d, mods_depressed=%d, mods_latched=%d mods_locked=%d, " \
+ "group=%d", serial, mods_depressed, mods_latched,
+ mods_locked, group);
+}
+
+static const struct wl_keyboard_listener keyboard_listener = {
+ .keymap = __keyboard_keymap,
+ .enter = __keyboard_enter,
+ .leave = __keyboard_leave,
+ .key = __keyboard_key,
+ .modifiers = __keyboard_modifiers
+};
+
+static void __global_registry_handler(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ if (interface == NULL)
+ return;
+
+ if (strcmp(interface, "tizen_input_device_manager") == 0) {
+ if (!input_devmgr) {
+ input_devmgr = wl_registry_bind(registry, id,
+ &tizen_input_device_manager_interface,
+ 1);
+ _D("input_devmgr = %p", input_devmgr);
+ }
+ } else if (strcmp(interface, "tizen_keyrouter") == 0) {
+ if (!keyrouter) {
+ keyrouter = wl_registry_bind(registry, id,
+ &tizen_keyrouter_interface, 1);
+ _D("keyrouter = %p", keyrouter);
+ }
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ if (!seat) {
+ seat = wl_registry_bind(registry, id,
+ &wl_seat_interface, 1);
+ if (!seat)
+ return;
+
+ _D("Succeed to bind wl_seat_interface!");
+ keyboard = wl_seat_get_keyboard(seat);
+ wl_keyboard_add_listener(keyboard, &keyboard_listener,
+ NULL);
+ _D("keyboard = %p", keyboard);
+ }
+ }
+}
+
+static void __global_registry_remover(void *data, struct wl_registry *registry,
+ uint32_t id)
+{
+ if (keyrouter) {
+ tizen_keyrouter_destroy(keyrouter);
+ keyrouter = NULL;
+ }
+
+ if (input_devmgr) {
+ tizen_input_device_manager_destroy(input_devmgr);
+ input_devmgr = NULL;
+ }
+
+ if (keyboard) {
+ wl_keyboard_destroy(keyboard);
+ keyboard = NULL;
+ }
+}
+
+static struct wl_registry_listener registry_listener = {
+ __global_registry_handler,
+ __global_registry_remover
+};
+
+static gboolean __timeout_handler(void *data)
+{
+ timer = 0;
+ _input_unlock();
+ return FALSE;
+}
+
+static void __find_keycode(struct xkb_keymap *keymap, xkb_keycode_t key,
+ void *data)
+{
+ keycode_map *found_keycodes = (keycode_map *)data;
+ xkb_keysym_t keysym = found_keycodes->keysym;
+ int nsyms = 0;
+ const xkb_keysym_t *syms_out = NULL;
+
+ nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out);
+ if (nsyms && syms_out && *syms_out == keysym) {
+ found_keycodes->nkeycodes++;
+ found_keycodes->keycodes = realloc(found_keycodes->keycodes,
+ sizeof(int) * found_keycodes->nkeycodes);
+ found_keycodes->keycodes[found_keycodes->nkeycodes - 1] = key;
+ }
+}
+
+static int __xkb_keycode_from_keysym(struct xkb_keymap *keymap,
+ xkb_keysym_t keysym, xkb_keycode_t **keycodes)
+{
+ keycode_map found_keycodes = {0,};
+
+ found_keycodes.keysym = keysym;
+ xkb_keymap_key_for_each(g_keymap, __find_keycode, &found_keycodes);
+ *keycodes = found_keycodes.keycodes;
+
+ return found_keycodes.nkeycodes;
+}
+
+static void __keygrab_request(struct tizen_keyrouter *tizen_keyrouter,
+ struct wl_surface *surface, uint32_t key, uint32_t mode)
+{
+ tizen_keyrouter_set_keygrab(tizen_keyrouter, surface, key, mode);
+ _D("request set_keygrab (key:%d, mode:%d)!", key, mode);
+}
+
+static void __keyungrab_request(struct tizen_keyrouter *tizen_keyrouter,
+ struct wl_surface *surface, uint32_t key)
+{
+ tizen_keyrouter_unset_keygrab(tizen_keyrouter, surface, key);
+ _D("request unset_keygrab (key:%d)!", key);
+}
+
+static void __do_keygrab(const char *keyname, uint32_t mode)
+{
+ xkb_keysym_t keysym = 0x0;
+ int nkeycodes = 0;
+ xkb_keycode_t *keycodes = NULL;
+ int i;
+
+ keysym = xkb_keysym_from_name(keyname, XKB_KEYSYM_NO_FLAGS);
+ nkeycodes = __xkb_keycode_from_keysym(g_keymap, keysym, &keycodes);
+
+ for (i = 0; i < nkeycodes; i++) {
+ _D("%s's keycode is %d (nkeycode: %d)",
+ keyname, keycodes[i], nkeycodes);
+ __keygrab_request(keyrouter, NULL, keycodes[i], mode);
+ }
+ free(keycodes);
+ keycodes = NULL;
+}
+
+static void __do_keyungrab(const char *keyname)
+{
+ xkb_keysym_t keysym = 0x0;
+ int nkeycodes = 0;
+ xkb_keycode_t *keycodes = NULL;
+ int i;
+
+ keysym = xkb_keysym_from_name(keyname, XKB_KEYSYM_NO_FLAGS);
+ nkeycodes = __xkb_keycode_from_keysym(g_keymap, keysym, &keycodes);
+
+ for (i = 0; i < nkeycodes; i++) {
+ _D("%s's keycode is %d (nkeycode: %d)\n",
+ keyname, keycodes[i], nkeycodes);
+ __keyungrab_request(keyrouter, NULL, keycodes[i]);
+ }
+ free(keycodes);
+ keycodes = NULL;
+}
+
+static int __xkb_init(void)
+{
+ if (!g_ctx) {
+ g_ctx = xkb_context_new(0);
+ if (!g_ctx) {
+ _E("Failed to get xkb_context");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void __xkb_fini(void)
+{
+ if (g_ctx) {
+ xkb_context_unref(g_ctx);
+ g_ctx = NULL;
+ }
+}
+
+static void __input_device_info(void *data,
+ struct tizen_input_device *tizen_input_device,
+ const char *name, uint32_t class, uint32_t subclass,
+ struct wl_array *axes)
+{
+ _D("device info - name: %s, class: %d, subclass: %d",
+ name, class, subclass);
+}
+
+static void __input_device_event_device(void *data,
+ struct tizen_input_device *tizen_input_device,
+ unsigned int serial, const char *name, uint32_t time)
+{
+ _D("event device - name: %s, time: %d", name, time);
+}
+
+static void __input_device_axis(void *data,
+ struct tizen_input_device *tizen_input_device,
+ uint32_t axis_type, wl_fixed_t value)
+{
+ _D("axis - axis_type: %d, value: %lf",
+ axis_type, wl_fixed_to_double(value));
+}
+
+static const struct tizen_input_device_listener input_device_listener = {
+ __input_device_info,
+ __input_device_event_device,
+ __input_device_axis,
+};
+
+static void __cb_device_add(void *data,
+ struct tizen_input_device_manager *tizen_input_device_manager,
+ uint32_t serial, const char *name,
+ struct tizen_input_device *device, struct wl_seat *seat)
+{
+ _D("device is added!", name);
+ tizen_input_device_add_listener(device, &input_device_listener, NULL);
+}
+
+static void __cb_device_remove(void *data,
+ struct tizen_input_device_manager *tizen_input_device_manager,
+ uint32_t serial, const char *name,
+ struct tizen_input_device *device, struct wl_seat *seat)
+{
+ _D("%s device is removed!", name);
+ tizen_input_device_destroy(device);
+}
+
+static void __cb_error(void *data,
+ struct tizen_input_device_manager *tizen_input_device_manager,
+ uint32_t errorcode)
+{
+ _E("error: %d", errorcode);
+}
+
+static void __cb_block_expired(void *data,
+ struct tizen_input_device_manager *tizen_input_device_manager)
+{
+ _D("block expired");
+}
+
+static struct tizen_input_device_manager_listener input_devmgr_listener = {
+ __cb_device_add,
+ __cb_device_remove,
+ __cb_error,
+ __cb_block_expired
+};
+
+int _input_init(void)
+{
+ if (!listener_added) {
+ _wayland_add_registry_listener(®istry_listener, NULL);
+ listener_added = true;
+ }
+
+ if (!display) {
+ display = _wayland_get_display();
+ if (!display) {
+ _E("Failed to connect to wayland compositor");
+ return -1;
+ }
+ }
+
+ if (__xkb_init() < 0)
+ return -1;
+
+ _D("Connected to wayland compositor!");
+
+ if (input_devmgr == NULL) {
+ _E("input_devmgr is null");
+ return -1;
+ }
+
+ if (keyrouter == NULL) {
+ _E("keyrouter is null");
+ return -1;
+ }
+
+ if (seat == NULL) {
+ _E("seat is null");
+ return -1;
+ }
+
+ if (keyboard == NULL) {
+ _E("keyboard is null");
+ return -1;
+ }
+
+ if (tizen_input_device_manager_add_listener(input_devmgr,
+ &input_devmgr_listener, NULL) < 0) {
+ _E("Failed to add listener");
+ }
+ wl_display_flush(display);
+ wl_display_roundtrip(display);
+
+ if (g_keymap == NULL) {
+ _E("g_keymap is null");
+ return -1;
+ }
+
+ init_done = true;
+
+ return 0;
+}
+
+int _input_fini(void)
+{
+ __xkb_fini();
+
+ return 0;
+}
+
+int _input_lock(void)
+{
+ if (locked)
+ _input_unlock();
+
+ if (!init_done && _input_init() < 0)
+ return -1;
+
+ _D("call tizen_input_device_manager_block_events");
+ tizen_input_device_manager_block_events(input_devmgr, 0,
+ TIZEN_INPUT_DEVICE_MANAGER_CLAS_TOUCHSCREEN |
+ TIZEN_INPUT_DEVICE_MANAGER_CLAS_MOUSE, TIMEOUT_VAL);
+ timer = g_timeout_add(TIMEOUT_VAL, __timeout_handler, NULL);
+ __do_keygrab("XF86Back", TIZEN_KEYROUTER_MODE_EXCLUSIVE);
+ wl_display_roundtrip(display);
+
+ locked = true;
+
+ return 0;
+}
+
+int _input_unlock(void)
+{
+ if (!locked)
+ return 0;
+
+ if (!init_done && _input_init() < 0)
+ return -1;
+
+ _D("call tizen_input_device_manager_unblock_events");
+ tizen_input_device_manager_unblock_events(input_devmgr, 0);
+ __do_keyungrab("XF86Back");
+ wl_display_roundtrip(display);
+
+ locked = false;
+ if (timer > 0) {
+ g_source_remove(timer);
+ timer = 0;
+ }
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <signal.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <aul.h>
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pkgmgr-info.h>
+#include <poll.h>
+#include <tzplatform_config.h>
+#include <cert-svc/ccert.h>
+#include <cert-svc/cinstance.h>
+#include <aul_sock.h>
+#include <aul_svc.h>
+#include <aul_svc_priv_key.h>
+#include <ttrace.h>
+#include <app2ext_interface.h>
+#include <vconf.h>
+#include <system_info.h>
+
+#include "amd_launch.h"
+#include "amd_appinfo.h"
+#include "amd_app_status.h"
+#include "amd_app_group.h"
+#include "amd_util.h"
+#include "app_signal.h"
+#include "amd_socket.h"
+#include "amd_share.h"
+#include "amd_app_com.h"
+#include "amd_splash_screen.h"
+#include "amd_input.h"
+#include "amd_suspend.h"
+#include "amd_signal.h"
+#include "amd_extractor.h"
+#include "amd_app_property.h"
+#include "amd_cooldown.h"
+#include "amd_widget.h"
+#include "amd_screen_connector.h"
+#include "amd_rua.h"
+
+#define DAC_ACTIVATE
+
+#define TERM_WAIT_SEC 3
+#define INIT_PID 1
+
+#define AUL_PR_NAME 16
+#define OSP_K_LAUNCH_TYPE "__OSP_LAUNCH_TYPE__"
+#define OSP_V_LAUNCH_TYPE_DATACONTROL "datacontrol"
+#define APP_CONTROL_OPERATION_MAIN "http://tizen.org/appcontrol/operation/main"
+
+struct launch_s {
+ const char *appid;
+ const struct appinfo *ai;
+ const char *instance_id;
+ int pid;
+ int leader_pid;
+ bool can_attach;
+ bool new_process;
+ bool is_subapp;
+ app_group_launch_mode launch_mode;
+ int prelaunch_attr;
+ int bg_category;
+ int bg_allowed;
+ shared_info_h share_info;
+ bool bg_launch;
+ bool new_instance;
+ app_status_h app_status;
+ bool debug_mode;
+};
+
+struct fgmgr {
+ guint tid;
+ int pid;
+};
+
+static GList *_fgmgr_list;
+static int __pid_of_last_launched_ui_app;
+static int __focused_pid;
+
+static void __set_reply_handler(int fd, int pid, request_h req, int cmd);
+static int __nofork_processing(int cmd, int pid, bundle *kb, request_h req);
+extern void _cleanup_dead_info(app_status_h app_status);
+
+typedef enum {
+ TIZEN_PROFILE_UNKNOWN = 0,
+ TIZEN_PROFILE_MOBILE = 0x1,
+ TIZEN_PROFILE_WEARABLE = 0x2,
+ TIZEN_PROFILE_TV = 0x4,
+ TIZEN_PROFILE_IVI = 0x8,
+ TIZEN_PROFILE_COMMON = 0x10,
+} tizen_profile_t;
+
+static tizen_profile_t __get_tizen_profile(void)
+{
+ static tizen_profile_t profile = TIZEN_PROFILE_UNKNOWN;
+ char *profile_name = NULL;
+
+ if (__builtin_expect(profile != TIZEN_PROFILE_UNKNOWN, 1))
+ return profile;
+
+ system_info_get_platform_string("http://tizen.org/feature/profile",
+ &profile_name);
+ if (profile_name == NULL)
+ return profile;
+
+ switch (*profile_name) {
+ case 'm':
+ case 'M':
+ profile = TIZEN_PROFILE_MOBILE;
+ break;
+ case 'w':
+ case 'W':
+ profile = TIZEN_PROFILE_WEARABLE;
+ break;
+ case 't':
+ case 'T':
+ profile = TIZEN_PROFILE_TV;
+ break;
+ case 'i':
+ case 'I':
+ profile = TIZEN_PROFILE_IVI;
+ break;
+ default: /* common or unknown ==> ALL ARE COMMON. */
+ profile = TIZEN_PROFILE_COMMON;
+ break;
+ }
+ free(profile_name);
+
+ return profile;
+}
+
+static void __set_stime(bundle *kb)
+{
+ struct timeval tv;
+ char tmp[MAX_LOCAL_BUFSZ];
+
+ gettimeofday(&tv, NULL);
+ snprintf(tmp, MAX_LOCAL_BUFSZ, "%ld/%ld", tv.tv_sec, tv.tv_usec);
+ bundle_add(kb, AUL_K_STARTTIME, tmp);
+}
+
+int _launch_start_app_local_with_bundle(uid_t uid, const char *appid,
+ bundle *kb)
+{
+ request_h req;
+ int r;
+ bool dummy;
+ bool dummy_mode;
+
+ __set_stime(kb);
+ bundle_add(kb, AUL_K_APPID, appid);
+ req = _request_create_local(APP_START, uid, getpid(), kb);
+ if (req == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ r = _launch_start_app(appid, req, &dummy, &dummy_mode, false);
+ _request_free_local(req);
+
+ return r;
+}
+
+int _launch_start_app_local(uid_t uid, const char *appid)
+{
+ int pid;
+ bundle *kb;
+
+ kb = bundle_create();
+ if (kb == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ pid = _launch_start_app_local_with_bundle(uid, appid, kb);
+ bundle_free(kb);
+
+ return pid;
+}
+
+int _launch_start_onboot_app_local(uid_t uid, const char *appid,
+ struct appinfo *ai)
+{
+ int ret = -1;
+ int enable = 1;
+ app_status_h app_status;
+ const char *comp_type;
+ const char *onboot;
+
+ if (appid == NULL || ai == NULL)
+ return -1;
+
+ comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (comp_type == NULL || strcmp(comp_type, APP_TYPE_SERVICE) != 0)
+ return -1;
+
+ onboot = _appinfo_get_value(ai, AIT_ONBOOT);
+ if (onboot == NULL || strcmp(onboot, "true") != 0)
+ return -1;
+
+ ret = _appinfo_get_int_value(ai, AIT_ENABLEMENT, &enable);
+ if (ret == 0 && !(enable & APP_ENABLEMENT_MASK_ACTIVE))
+ return -1;
+
+ app_status = _app_status_find_by_appid(appid, uid);
+ if (_app_status_is_running(app_status) > 0)
+ return -1;
+
+ _D("start app %s from user %d by onboot", appid, uid);
+ return _launch_start_app_local(uid, appid);
+}
+
+int _terminate_app_local(uid_t uid, int pid)
+{
+ request_h req;
+ int ret;
+
+ req = _request_create_local(APP_TERM_BY_PID, uid, getpid(), NULL);
+ if (req == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ aul_send_app_terminate_request_signal(pid, NULL, NULL, NULL);
+ ret = _term_app(pid, req);
+ _request_free_local(req);
+
+ return ret;
+}
+
+int _send_to_sigkill(int pid)
+{
+ int pgid;
+
+ if (pid <= 1)
+ return -1;
+
+ pgid = getpgid(pid);
+ if (pgid <= 1)
+ return -1;
+
+ if (killpg(pgid, SIGKILL) < 0)
+ return -1;
+
+ return 0;
+}
+
+int _resume_app(int pid, request_h req)
+{
+ int dummy;
+ int ret;
+
+ ret = aul_sock_send_raw(pid, _request_get_target_uid(req),
+ APP_RESUME_BY_PID, (unsigned char *)&dummy, 0,
+ AUL_SOCK_ASYNC);
+ if (ret < 0) {
+ if (ret == -EAGAIN) {
+ _E("resume packet timeout error");
+ } else {
+ _E("raise failed - %d resume fail\n", pid);
+ _E("we will term the app - %d\n", pid);
+ _send_to_sigkill(pid);
+ ret = -1;
+ }
+ _request_send_result(req, ret);
+ }
+ _D("resume done\n");
+
+ if (ret > 0)
+ __set_reply_handler(ret, pid, req, APP_RESUME_BY_PID);
+
+ return ret;
+}
+
+int _pause_app(int pid, request_h req)
+{
+ int dummy;
+ int ret;
+
+ ret = aul_sock_send_raw(pid, _request_get_target_uid(req),
+ APP_PAUSE_BY_PID, (unsigned char *)&dummy, 0,
+ AUL_SOCK_ASYNC);
+ if (ret < 0) {
+ if (ret == -EAGAIN) {
+ _E("pause packet timeout error");
+ } else {
+ _E("iconify failed - %d pause fail", pid);
+ _E("we will term the app - %d", pid);
+ _send_to_sigkill(pid);
+ ret = -1;
+ }
+ _request_send_result(req, ret);
+ }
+ _D("pause done");
+
+ if (ret > 0)
+ __set_reply_handler(ret, pid, req, APP_PAUSE_BY_PID);
+
+ return ret;
+}
+
+int _term_sub_app(int pid, uid_t uid)
+{
+ int dummy;
+ int ret;
+
+ ret = aul_sock_send_raw(pid, uid, APP_TERM_BY_PID_ASYNC,
+ (unsigned char *)&dummy, 0, AUL_SOCK_NOREPLY);
+ if (ret < 0) {
+ _E("terminate packet send error - use SIGKILL");
+ if (_send_to_sigkill(pid) < 0) {
+ _E("fail to killing - %d\n", pid);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int _term_app(int pid, request_h req)
+{
+ int dummy;
+ int ret;
+ int cnt;
+ int *pids = NULL;
+ int i;
+ uid_t uid = _request_get_target_uid(req);
+
+ if (_app_group_is_leader_pid(pid)) {
+ _app_group_get_group_pids(pid, &cnt, &pids);
+ for (i = cnt - 1; i >= 0; i--) {
+ if (i != 0)
+ _term_sub_app(pids[i], uid);
+ _app_group_remove(pids[i]);
+ }
+ free(pids);
+ }
+
+ ret = aul_sock_send_raw(pid, uid, APP_TERM_BY_PID,
+ (unsigned char *)&dummy, 0, AUL_SOCK_ASYNC);
+ if (ret < 0) {
+ _D("terminate packet send error - use SIGKILL");
+ if (_send_to_sigkill(pid) < 0) {
+ _E("fail to killing - %d\n", pid);
+ _request_send_result(req, -1);
+ return -1;
+ }
+ _request_send_result(req, 0);
+ }
+ _D("term done\n");
+
+ if (ret > 0)
+ __set_reply_handler(ret, pid, req, APP_TERM_BY_PID);
+
+ return 0;
+}
+
+int _term_req_app(int pid, request_h req)
+{
+ int dummy;
+ int ret;
+
+ ret = aul_sock_send_raw(pid, _request_get_target_uid(req),
+ APP_TERM_REQ_BY_PID, (unsigned char *)&dummy, 0,
+ AUL_SOCK_ASYNC);
+ if (ret < 0) {
+ _D("terminate req send error");
+ _request_send_result(req, ret);
+ }
+
+ if (ret > 0)
+ __set_reply_handler(ret, pid, req, APP_TERM_REQ_BY_PID);
+
+ return 0;
+}
+
+int _term_bgapp(int pid, request_h req)
+{
+ int dummy;
+ int ret;
+ int cnt;
+ int *pids = NULL;
+ int i;
+ int status = -1;
+ app_status_h app_status;
+ uid_t uid = _request_get_target_uid(req);
+
+ if (_app_group_is_leader_pid(pid)) {
+ _app_group_get_group_pids(pid, &cnt, &pids);
+ if (cnt > 0) {
+ app_status = _app_status_find(pids[cnt - 1]);
+ status = _app_status_get_status(app_status);
+ if (status == STATUS_BG) {
+ for (i = cnt - 1 ; i >= 0; i--) {
+ if (i != 0)
+ _term_sub_app(pids[i], uid);
+ _app_group_remove(pids[i]);
+ }
+ }
+ }
+ free(pids);
+ }
+
+ ret = aul_sock_send_raw(pid, uid, APP_TERM_BGAPP_BY_PID,
+ (unsigned char *)&dummy, sizeof(int), AUL_SOCK_ASYNC);
+ if (ret < 0) {
+ _D("terminate packet send error - use SIGKILL");
+ if (_send_to_sigkill(pid) < 0) {
+ _E("fail to killing - %d", pid);
+ _request_send_result(req, -1);
+ return -1;
+ }
+ _request_send_result(req, 0);
+ }
+ _D("term_bgapp done");
+
+ if (ret > 0)
+ __set_reply_handler(ret, pid, req, APP_TERM_BGAPP_BY_PID);
+
+ return 0;
+}
+
+int _term_app_v2(int pid, request_h req, bool *pend)
+{
+ int dummy;
+ int ret;
+ int cnt;
+ int *pids = NULL;
+ int i;
+ uid_t uid = _request_get_target_uid(req);
+
+ if (_app_group_is_leader_pid(pid)) {
+ _app_group_get_group_pids(pid, &cnt, &pids);
+ for (i = cnt - 1; i >= 0; i--) {
+ if (i != 0)
+ _term_sub_app(pids[i], uid);
+ _app_group_remove(pids[i]);
+ }
+ free(pids);
+ }
+
+ ret = aul_sock_send_raw(pid, uid, APP_TERM_BY_PID_SYNC,
+ (unsigned char *)&dummy, 0,
+ AUL_SOCK_ASYNC | AUL_SOCK_NOREPLY);
+ if (ret < 0) {
+ _D("Failed to send the terminate packet - use SIGKILL");
+ if (_send_to_sigkill(pid) < 0) {
+ _E("Failed to kill - %d\n", pid);
+ _request_send_result(req, -1);
+ return -1;
+ }
+ }
+ _D("term v2 done");
+
+ if (pend)
+ *pend = true;
+
+ return 0;
+}
+
+static int __fake_launch_app(int cmd, int pid, bundle *kb, request_h req)
+{
+ int ret;
+
+ ret = aul_sock_send_bundle(pid, _request_get_target_uid(req), cmd, kb,
+ AUL_SOCK_ASYNC);
+ if (ret < 0) {
+ _E("error request fake launch - error code = %d", ret);
+ _request_send_result(req, ret);
+ }
+
+ if (ret > 0)
+ __set_reply_handler(ret, pid, req, cmd);
+
+ return ret;
+}
+
+static int __fake_launch_app_async(int cmd, int pid, bundle *kb, request_h req)
+{
+ int ret;
+
+ ret = aul_sock_send_bundle(pid, _request_get_target_uid(req), cmd, kb,
+ AUL_SOCK_ASYNC);
+ if (ret < 0) {
+ _E("error request fake launch - error code = %d", ret);
+ _request_send_result(req, ret);
+ }
+
+ if (ret > 0) {
+ _send_result_to_client(_request_remove_fd(req), pid);
+ __set_reply_handler(ret, pid, req, cmd);
+ }
+
+ return ret;
+}
+
+static gboolean __au_glib_check(GSource *src)
+{
+ GSList *fd_list;
+ GPollFD *tmp;
+
+ fd_list = src->poll_fds;
+ do {
+ tmp = (GPollFD *) fd_list->data;
+ if ((tmp->revents & (POLLIN | POLLPRI)))
+ return TRUE;
+ fd_list = fd_list->next;
+ } while (fd_list);
+
+ return FALSE;
+}
+
+static gboolean __au_glib_dispatch(GSource *src, GSourceFunc callback,
+ gpointer data)
+{
+ callback(data);
+ return TRUE;
+}
+
+static gboolean __au_glib_prepare(GSource *src, gint *timeout)
+{
+ return FALSE;
+}
+
+static GSourceFuncs funcs = {
+ .prepare = __au_glib_prepare,
+ .check = __au_glib_check,
+ .dispatch = __au_glib_dispatch,
+ .finalize = NULL
+};
+
+struct reply_info {
+ GSource *src;
+ GPollFD *gpollfd;
+ guint timer_id;
+ int clifd;
+ int pid;
+ int cmd;
+ bundle *kb;
+};
+
+static gboolean __reply_handler(gpointer data)
+{
+ struct reply_info *r_info = (struct reply_info *)data;
+ int fd = r_info->gpollfd->fd;
+ int len;
+ int res = 0;
+ int clifd = r_info->clifd;
+ int pid = r_info->pid;
+ char err_buf[1024];
+
+ len = recv(fd, &res, sizeof(int), 0);
+ if (len == -1) {
+ if (errno == EAGAIN) {
+ _E("recv timeout : %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ res = -EAGAIN;
+ } else {
+ _E("recv error : %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ res = -ECOMM;
+ }
+ }
+ close(fd);
+
+ if (res >= 0)
+ res = pid;
+ _send_result_to_client(clifd, res);
+
+ _D("listen fd : %d , send fd : %d, pid : %d", fd, clifd, pid);
+
+ g_source_remove(r_info->timer_id);
+ g_source_remove_poll(r_info->src, r_info->gpollfd);
+ g_source_destroy(r_info->src);
+ g_source_unref(r_info->src);
+ g_free(r_info->gpollfd);
+ if (r_info->kb)
+ bundle_free(r_info->kb);
+ free(r_info);
+
+ return TRUE;
+}
+
+static gboolean __recv_timeout_handler(gpointer data)
+{
+ struct reply_info *r_info = (struct reply_info *)data;
+ int fd = r_info->gpollfd->fd;
+ int clifd = r_info->clifd;
+ const char *appid;
+ const struct appinfo *ai;
+ const char *taskmanage;
+ app_status_h app_status;
+ uid_t uid;
+ int ret = -EAGAIN;
+
+ _E("application is not responding: pid(%d) cmd(%d)",
+ r_info->pid, r_info->cmd);
+ close(fd);
+
+ switch (r_info->cmd) {
+ case APP_OPEN:
+ case APP_RESUME:
+ case APP_START:
+ case APP_START_RES:
+ case APP_START_ASYNC:
+ case APP_START_RES_ASYNC:
+ app_status = _app_status_find(r_info->pid);
+ if (app_status == NULL)
+ break;
+
+ uid = _app_status_get_uid(app_status);
+ if (_app_status_get_app_type(app_status) == AT_WIDGET_APP)
+ _widget_verify_instance(r_info->kb, r_info->pid, uid);
+
+ appid = _app_status_get_appid(app_status);
+ ai = _appinfo_find(uid, appid);
+ if (ai == NULL)
+ break;
+ taskmanage = _appinfo_get_value(ai, AIT_TASKMANAGE);
+ if (taskmanage && strcmp(taskmanage, "true") == 0)
+ _signal_send_watchdog(r_info->pid, SIGKILL);
+ break;
+ case APP_TERM_BY_PID:
+ case APP_TERM_BGAPP_BY_PID:
+ if (_send_to_sigkill(r_info->pid) == 0)
+ ret = 0;
+ break;
+ }
+
+ _send_result_to_client(clifd, ret);
+ g_source_remove_poll(r_info->src, r_info->gpollfd);
+ g_source_destroy(r_info->src);
+ g_source_unref(r_info->src);
+ g_free(r_info->gpollfd);
+ if (r_info->kb)
+ bundle_free(r_info->kb);
+ free(r_info);
+
+ return FALSE;
+}
+
+static void __set_reply_handler(int fd, int pid, request_h req, int cmd)
+{
+ GPollFD *gpollfd;
+ GSource *src;
+ struct reply_info *r_info;
+ struct timeval tv;
+ bundle *kb = _request_get_bundle(req);
+
+ src = g_source_new(&funcs, sizeof(GSource));
+ if (src == NULL) {
+ _E("Out of memory");
+ return;
+ }
+
+ gpollfd = (GPollFD *)g_malloc(sizeof(GPollFD));
+ if (gpollfd == NULL) {
+ _E("Out of memory");
+ g_source_unref(src);
+ return;
+ }
+
+ gpollfd->events = POLLIN;
+ gpollfd->fd = fd;
+
+ r_info = malloc(sizeof(*r_info));
+ if (r_info == NULL) {
+ _E("out of memory");
+ g_free(gpollfd);
+ g_source_unref(src);
+ return;
+ }
+
+ if (kb) {
+ r_info->kb = bundle_dup(kb);
+ if (r_info->kb == NULL) {
+ _E("Out of memory");
+ free(r_info);
+ g_free(gpollfd);
+ g_source_unref(src);
+ return;
+ }
+ } else {
+ r_info->kb = NULL;
+ }
+
+ r_info->clifd = _request_remove_fd(req);
+ r_info->pid = pid;
+ r_info->src = src;
+ r_info->gpollfd = gpollfd;
+ r_info->cmd = cmd;
+
+ tv = aul_sock_get_rcv_timeval();
+ r_info->timer_id = g_timeout_add_seconds(tv.tv_sec,
+ __recv_timeout_handler, (gpointer)r_info);
+ g_source_add_poll(src, gpollfd);
+ g_source_set_callback(src, (GSourceFunc)__reply_handler,
+ (gpointer)r_info, NULL);
+ g_source_set_priority(src, G_PRIORITY_DEFAULT);
+ g_source_attach(src, NULL);
+
+ _D("listen fd : %d, send fd : %d", fd, r_info->clifd);
+}
+
+static void __check_request_for_app_boosting(request_h req)
+{
+ int cmd = _request_get_cmd(req);
+ bundle *kb = _request_get_bundle(req);
+ int lcd_status = 0;
+ const char *op;
+
+ if (kb == NULL)
+ return;
+
+ op = bundle_get_val(kb, AUL_SVC_K_OPERATION);
+ if ((op && !strcmp(op, APP_CONTROL_OPERATION_MAIN)) ||
+ cmd == APP_OPEN) {
+ vconf_get_int(VCONFKEY_PM_STATE, &lcd_status);
+ if (lcd_status == VCONFKEY_PM_STATE_LCDOFF)
+ _D("LCD OFF: Skip app launch boost");
+ else
+ _signal_send_cpu_boost(APP_BOOSTING_PERIOD);
+ }
+}
+
+static int __nofork_processing(int cmd, int pid, bundle *kb, request_h req)
+{
+ int ret;
+
+ __check_request_for_app_boosting(req);
+
+ switch (cmd) {
+ case APP_OPEN:
+ case APP_RESUME:
+ _D("resume app's pid : %d\n", pid);
+ ret = _resume_app(pid, req);
+ if (ret < 0)
+ _E("__resume_app failed. error code = %d", ret);
+ _D("resume app done");
+ break;
+ case APP_START:
+ case APP_START_RES:
+ _D("fake launch pid : %d\n", pid);
+ ret = __fake_launch_app(cmd, pid, kb, req);
+ if (ret < 0)
+ _E("fake_launch failed. error code = %d", ret);
+ _D("fake launch done");
+ break;
+ case APP_START_ASYNC:
+ case APP_START_RES_ASYNC:
+ ret = __fake_launch_app_async(cmd, pid, kb, req);
+ if (ret < 0)
+ _E("fake_launch_async failed. error code = %d", ret);
+ _D("fake launch async done");
+ break;
+ default:
+ _E("unknown command: %d", cmd);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int __compare_signature(const struct appinfo *ai, int cmd,
+ uid_t caller_uid, const char *appid, const char *caller_appid)
+{
+ const char *permission;
+ const struct appinfo *caller_ai;
+ const char *preload;
+ const char *api_version;
+ pkgmgrinfo_cert_compare_result_type_e compare_result;
+
+ permission = _appinfo_get_value(ai, AIT_PERM);
+ if (permission && strcmp(permission, "signature") == 0) {
+ if (caller_uid != 0 && (cmd == APP_START ||
+ cmd == APP_START_RES ||
+ cmd == APP_START_ASYNC ||
+ cmd == APP_START_RES_ASYNC)) {
+ caller_ai = _appinfo_find(caller_uid, caller_appid);
+ preload = _appinfo_get_value(caller_ai, AIT_PRELOAD);
+ if (!preload || strcmp(preload, "true") == 0)
+ return 0;
+
+ api_version = _appinfo_get_value(caller_ai,
+ AIT_API_VERSION);
+ if (api_version && strverscmp(api_version, "2.4") < 0)
+ return 0;
+
+ /* is admin is global */
+ if (caller_uid != GLOBAL_USER) {
+ pkgmgrinfo_pkginfo_compare_usr_app_cert_info(
+ caller_appid, appid,
+ caller_uid, &compare_result);
+ } else {
+ pkgmgrinfo_pkginfo_compare_app_cert_info(
+ caller_appid, appid,
+ &compare_result);
+ }
+
+ if (compare_result != PMINFO_CERT_COMPARE_MATCH)
+ return -EILLEGALACCESS;
+ }
+ }
+
+ return 0;
+}
+
+static int __get_pid_for_app_group(const char *appid, uid_t uid, bundle *kb,
+ struct launch_s *handle)
+{
+ int status;
+ int found_pid = -1;
+ int found_lpid = -1;
+ int ret;
+
+ if (_app_group_is_group_app(kb, uid)) {
+ handle->pid = -1;
+ handle->is_subapp = true;
+ handle->app_status = NULL;
+ } else {
+ if (handle->new_instance)
+ handle->is_subapp = true;
+ else
+ handle->is_subapp = false;
+ }
+
+ status = _app_status_get_status(handle->app_status);
+ if (handle->pid <= 0 || status == STATUS_DYING) {
+ ret = _app_group_find_singleton(appid, &found_pid, &found_lpid);
+ if (ret == 0) {
+ handle->pid = found_pid;
+ handle->new_process = false;
+ } else {
+ handle->new_process = true;
+ }
+
+ ret = _app_group_can_start_app(appid, kb, &handle->can_attach,
+ &handle->leader_pid, &handle->launch_mode, uid);
+ if (ret != 0) {
+ _E("can't make group info");
+ return -EILLEGALACCESS;
+ }
+
+ if (handle->can_attach && handle->leader_pid == found_lpid) {
+ _E("can't launch singleton app in the same group");
+ return -EILLEGALACCESS;
+ }
+
+ if (found_pid != -1) {
+ _W("_app_group_clear_top, pid: %d", found_pid);
+ _app_group_clear_top(found_pid, uid);
+ }
+ }
+
+ if (handle->pid == -1 && handle->can_attach)
+ handle->pid = _app_group_find_pid_from_recycle_bin(appid);
+
+ if (handle->pid > 0)
+ handle->app_status = _app_status_find(handle->pid);
+
+ return 0;
+}
+
+static void __prepare_to_suspend_services(int pid, uid_t uid)
+{
+ int dummy;
+
+ SECURE_LOGD("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+ aul_sock_send_raw(pid, uid, APP_SUSPEND, (unsigned char *)&dummy,
+ sizeof(int), AUL_SOCK_NOREPLY);
+}
+
+static void __prepare_to_wake_services(int pid, uid_t uid)
+{
+ int dummy;
+
+ SECURE_LOGD("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+ aul_sock_send_raw(pid, uid, APP_WAKE, (unsigned char *)&dummy,
+ sizeof(int), AUL_SOCK_NOREPLY);
+}
+
+static gboolean __check_service_only(gpointer user_data)
+{
+ int pid = GPOINTER_TO_INT(user_data);
+ app_status_h app_status;
+
+ SECURE_LOGD("[__SUSPEND__] pid :%d", pid);
+ app_status = _app_status_find(pid);
+ _app_status_check_service_only(app_status,
+ __prepare_to_suspend_services);
+
+ return FALSE;
+}
+
+static char *__get_cert_value_from_pkginfo(const char *pkgid, uid_t uid)
+{
+ int ret;
+ const char *cert_value;
+ char *ret_cert;
+ pkgmgrinfo_certinfo_h certinfo;
+
+ ret = pkgmgrinfo_pkginfo_create_certinfo(&certinfo);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to create certinfo");
+ return NULL;
+ }
+
+ ret = pkgmgrinfo_pkginfo_load_certinfo(pkgid, certinfo, uid);
+ if (ret != PMINFO_R_OK) {
+ _E("Failed to load certinfo");
+ pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
+ return NULL;
+ }
+
+ ret = pkgmgrinfo_pkginfo_get_cert_value(certinfo,
+ PMINFO_DISTRIBUTOR_ROOT_CERT, &cert_value);
+ if (ret != PMINFO_R_OK || cert_value == NULL) {
+ _E("Failed to get cert value");
+ pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
+ return NULL;
+ }
+
+ ret_cert = strdup(cert_value);
+ pkgmgrinfo_pkginfo_destroy_certinfo(certinfo);
+
+ return ret_cert;
+}
+
+static int __get_visibility_from_certsvc(const char *cert_value)
+{
+ int ret;
+ CertSvcInstance instance;
+ CertSvcCertificate certificate;
+ CertSvcVisibility visibility = CERTSVC_VISIBILITY_PUBLIC;
+
+ if (cert_value == NULL)
+ return (int)visibility;
+
+ ret = certsvc_instance_new(&instance);
+ if (ret != CERTSVC_SUCCESS) {
+ _E("certsvc_instance_new() is failed.");
+ return (int)visibility;
+ }
+
+ ret = certsvc_certificate_new_from_memory(instance,
+ (const unsigned char *)cert_value,
+ strlen(cert_value),
+ CERTSVC_FORM_DER_BASE64,
+ &certificate);
+ if (ret != CERTSVC_SUCCESS) {
+ _E("certsvc_certificate_new_from_memory() is failed.");
+ certsvc_instance_free(instance);
+ return (int)visibility;
+ }
+
+ ret = certsvc_certificate_get_visibility(certificate, &visibility);
+ if (ret != CERTSVC_SUCCESS)
+ _E("certsvc_certificate_get_visibility() is failed.");
+
+ certsvc_certificate_free(certificate);
+ certsvc_instance_free(instance);
+
+ return (int)visibility;
+}
+
+static int __check_allowed_appid(const char *callee_appid,
+ const char *caller_appid, uid_t uid)
+{
+ app_property_h app_property;
+ GList *list;
+ GList *iter;
+ char *allowed_appid;
+
+ app_property = _app_property_find(uid);
+ if (app_property == NULL)
+ return -1;
+
+ list = _app_property_get_allowed_app_list(app_property, callee_appid);
+ iter = g_list_first(list);
+ while (iter) {
+ allowed_appid = (char *)iter->data;
+ if (allowed_appid && strcmp(allowed_appid, caller_appid) == 0) {
+ _D("allowed appid(%s), appid(%s)",
+ allowed_appid, callee_appid);
+ return 0;
+ }
+
+ iter = g_list_next(iter);
+ }
+
+ return -1;
+}
+
+static int __check_execute_permission(const char *callee_pkgid,
+ const char *caller_appid, uid_t caller_uid, bundle *kb)
+{
+ struct appinfo *ai;
+ const char *caller_pkgid;
+ const char *launch_type;
+ const char *v;
+ const char *callee_appid = bundle_get_val(kb, AUL_K_APPID);
+ char num[256];
+ int vi_num;
+ int visibility;
+ char *cert_value;
+ int ret;
+
+ if (callee_pkgid == NULL)
+ return -1;
+
+ ai = _appinfo_find(caller_uid, caller_appid);
+ if (ai == NULL)
+ return 0;
+
+ caller_pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ if (caller_pkgid == NULL)
+ return 0;
+
+ if (strcmp(caller_pkgid, callee_pkgid) == 0)
+ return 0;
+
+ ret = __check_allowed_appid(callee_appid, caller_appid, caller_uid);
+ if (ret == 0)
+ return 0;
+
+ launch_type = bundle_get_val(kb, OSP_K_LAUNCH_TYPE);
+ if (launch_type == NULL
+ || strcmp(launch_type, OSP_V_LAUNCH_TYPE_DATACONTROL) != 0) {
+ v = _appinfo_get_value(ai, AIT_VISIBILITY);
+ if (v == NULL) {
+ cert_value = __get_cert_value_from_pkginfo(caller_pkgid,
+ caller_uid);
+ vi_num = __get_visibility_from_certsvc(cert_value);
+ if (cert_value)
+ free(cert_value);
+
+ snprintf(num, sizeof(num), "%d", vi_num);
+ _appinfo_set_value(ai, AIT_VISIBILITY, num);
+ v = num;
+ }
+
+ visibility = atoi(v);
+ if (!(visibility & CERTSVC_VISIBILITY_PLATFORM)) {
+ _E("Couldn't launch service app in other packages");
+ return -EREJECTED;
+ }
+ }
+
+ return 0;
+}
+
+static gboolean __fg_timeout_handler(gpointer data)
+{
+ struct fgmgr *fg = data;
+ app_status_h app_status;
+
+ if (!fg)
+ return FALSE;
+
+ app_status = _app_status_find(fg->pid);
+ if (app_status == NULL)
+ return FALSE;
+
+ _W("%d is running in the background", fg->pid);
+ _app_status_update_status(app_status, STATUS_BG, true, true);
+
+ _fgmgr_list = g_list_remove(_fgmgr_list, fg);
+ free(fg);
+
+ return FALSE;
+}
+
+int _launch_add_fgmgr(int pid)
+{
+ struct fgmgr *fg;
+
+ fg = calloc(1, sizeof(struct fgmgr));
+ if (!fg) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ fg->pid = pid;
+ fg->tid = g_timeout_add(5000, __fg_timeout_handler, fg);
+
+ _fgmgr_list = g_list_append(_fgmgr_list, fg);
+
+ return 0;
+}
+
+void _launch_remove_fgmgr(int pid)
+{
+ GList *iter = NULL;
+ struct fgmgr *fg;
+
+ if (pid < 0)
+ return;
+
+ for (iter = _fgmgr_list; iter != NULL; iter = g_list_next(iter)) {
+ fg = (struct fgmgr *)iter->data;
+ if (fg->pid == pid) {
+ g_source_remove(fg->tid);
+ _fgmgr_list = g_list_remove(_fgmgr_list, fg);
+ free(fg);
+ return;
+ }
+ }
+}
+
+static int __send_hint_for_visibility(uid_t uid)
+{
+ bundle *b;
+ int ret;
+
+ b = bundle_create();
+ if (b == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ ret = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK, uid,
+ PAD_CMD_VISIBILITY, b);
+ bundle_free(b);
+ __pid_of_last_launched_ui_app = 0;
+
+ return ret;
+}
+
+#ifdef TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP
+static void __terminate_unmanageable_app(app_status_h app_status)
+{
+ const char *appid = NULL;
+ int cnt = 0;
+ int *pids = NULL;
+ int i;
+ const char *taskmanage = NULL;
+ const struct appinfo *ai = NULL;
+ int bg_category = 0x00;
+ app_status_h status_h;
+ int st;
+ uid_t uid;
+
+ if (!_app_status_is_home_app(app_status))
+ return;
+
+ _app_group_get_leader_pids(&cnt, &pids);
+ if (pids == NULL)
+ return;
+
+ for (i = 0; i < cnt; i++) {
+ status_h = _app_status_find(pids[i]);
+ if (!status_h)
+ continue;
+
+ if (_app_status_is_home_app(status_h))
+ continue;
+
+ appid = _app_status_get_appid(status_h);
+ ai = _appinfo_find(_app_status_get_uid(status_h), appid);
+ taskmanage = _appinfo_get_value(ai, AIT_TASKMANAGE);
+ _appinfo_get_int_value(ai, AIT_BG_CATEGORY, &bg_category);
+ uid = _app_status_get_uid(status_h);
+
+ if (taskmanage && strcmp("false", taskmanage) == 0
+ && bg_category == 0) {
+ st = _app_status_get_status(status_h);
+ if (st == STATUS_BG) {
+ _W("terminate %d %s %d", pids[i], appid, st);
+ aul_send_app_terminate_request_signal(pids[i],
+ NULL, NULL, NULL);
+ _term_sub_app(pids[i], uid);
+ }
+ }
+ }
+
+ free(pids);
+}
+#endif /* TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP */
+
+static const char *__get_name(const char *appid)
+{
+ char *name_token;
+
+ if (!appid)
+ return NULL;
+
+ name_token = strrchr(appid, '.');
+ if (name_token == NULL)
+ return appid;
+
+ name_token++;
+
+ return name_token;
+}
+
+static int __app_status_handler(int pid, int status, void *data)
+{
+ const char *appid;
+ const char *name;
+ int bg_category;
+ int old_status;
+ const struct appinfo *ai;
+ app_status_h app_status;
+ uid_t uid;
+ unsigned int surf;
+
+ _W("pid(%d) status(%d)", pid, status);
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return 0;
+
+ old_status = _app_status_get_status(app_status);
+ if (old_status == STATUS_DYING && old_status != PROC_STATUS_LAUNCH)
+ return 0;
+
+ uid = _app_status_get_uid(app_status);
+ switch (status) {
+ case PROC_STATUS_FG:
+ _launch_remove_fgmgr(pid);
+ _app_status_update_status(app_status, STATUS_VISIBLE, false, true);
+ _suspend_remove_timer(pid);
+
+ if (pid == __pid_of_last_launched_ui_app)
+ __send_hint_for_visibility(uid);
+
+#ifdef TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP
+ __terminate_unmanageable_app(app_status);
+#endif /* TIZEN_FEATURE_TERMINATE_UNMANAGEABLE_APP */
+
+ surf = (unsigned int)_app_group_get_window(pid);
+ _screen_connector_update_app_screen(pid, surf, uid);
+ _rua_update_screen_info(pid, surf);
+ break;
+ case PROC_STATUS_BG:
+ _app_status_update_status(app_status, STATUS_BG, false, true);
+ appid = _app_status_get_appid(app_status);
+ if (appid) {
+ ai = _appinfo_find(uid, appid);
+ bg_category = (bool)_appinfo_get_value(ai,
+ AIT_BG_CATEGORY);
+ if (!bg_category)
+ _suspend_add_timer(pid, ai);
+ }
+ break;
+ case PROC_STATUS_FOCUS:
+ __focused_pid = pid;
+ surf = (unsigned int)_app_group_get_window(pid);
+ _screen_connector_update_app_screen(pid, surf, uid);
+ _rua_update_screen_info(pid, surf);
+ break;
+
+ case PROC_STATUS_HIDE:
+ _app_status_update_status(app_status, STATUS_BG, false, false);
+ break;
+
+ case PROC_STATUS_LAUNCH:
+ _signal_send_cpu_boost(APP_BOOSTING_STOP);
+ appid = _app_status_get_appid(app_status);
+ if (appid) {
+ name = __get_name(appid);
+ if (name)
+ LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]", name);
+ }
+ break;
+
+ }
+
+ return 0;
+}
+
+void _launch_set_focused_pid(int pid)
+{
+ __focused_pid = pid;
+}
+
+int _launch_get_focused_pid(void)
+{
+ return __focused_pid;
+}
+
+static int __listen_app_status_signal(void *data)
+{
+ int ret;
+
+ ret = aul_listen_app_status_signal(__app_status_handler, data);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+int _launch_init(void)
+{
+ int ret;
+
+ _D("_launch_init");
+
+ ret = __listen_app_status_signal(NULL);
+ if (ret < 0)
+ _signal_add_initializer(__listen_app_status_signal, NULL);
+
+ return 0;
+}
+
+static int __check_ver(const char *required, const char *actual)
+{
+ int ret;
+
+ if (required && actual) {
+ ret = strverscmp(required, actual);
+ if (ret < 1)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int __get_prelaunch_attribute(const struct appinfo *ai,
+ const char *appid, uid_t uid)
+{
+ int attribute_val = RESOURCED_BACKGROUND_MANAGEMENT_ATTRIBUTE;
+ const char *api_version;
+ const char *comp;
+ const char *pkg_type;
+ bool system = false;
+ app_property_h prop;
+
+ api_version = _appinfo_get_value(ai, AIT_API_VERSION);
+ if (api_version && __check_ver("2.4", api_version))
+ attribute_val |= RESOURCED_API_VER_2_4_ATTRIBUTE;
+
+ comp = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (comp && !strcmp(comp, APP_TYPE_SERVICE))
+ attribute_val |= RESOURCED_ATTRIBUTE_SERVICE_APP;
+
+ pkg_type = _appinfo_get_value(ai, AIT_PKGTYPE);
+ if (pkg_type && !strcmp(pkg_type, "wgt")) {
+ attribute_val |= RESOURCED_ATTRIBUTE_LARGEMEMORY;
+ attribute_val |= RESOURCED_ATTRIBUTE_WEB_APP;
+ }
+
+ _appinfo_get_boolean(ai, AIT_SYSTEM, &system);
+ if (!system)
+ attribute_val |= RESOURCED_ATTRIBUTE_DOWNLOAD_APP;
+
+ prop = _app_property_find(uid);
+ if (prop) {
+ if (_app_property_metadata_query_activation(prop, appid, METADATA_LARGEMEMORY))
+ attribute_val |= RESOURCED_ATTRIBUTE_LARGEMEMORY;
+ if (_app_property_metadata_query_activation(prop, appid, METADATA_OOMTERMINATION))
+ attribute_val |= RESOURCED_ATTRIBUTE_OOMTERMINATION;
+ }
+
+ _D("api-version: %s", api_version);
+ _D("prelaunch attribute %d%d%d%d%d",
+ (attribute_val & 0x10) >> 4,
+ (attribute_val & 0x8) >> 3,
+ (attribute_val & 0x4) >> 2,
+ (attribute_val & 0x2) >> 1,
+ (attribute_val & 0x1));
+
+ return attribute_val;
+}
+
+static int __get_background_category(const struct appinfo *ai)
+{
+ int category = 0x0;
+
+ category = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY);
+
+ _D("background category: %#x", category);
+
+ return category;
+}
+
+static bool __is_allowed_background(const char *component_type, int bg_category)
+{
+ bool bg_allowed = false;
+
+ /*
+ * 2.4 bg-categorized (uiapp || svcapp) || watch || widget -> bg allowed
+ * 2.3 uiapp -> not allowed, 2.3 svcapp -> bg allowed
+ */
+ if (!strcmp(component_type, APP_TYPE_UI) ||
+ !strcmp(component_type, APP_TYPE_SERVICE)) {
+ if (bg_category)
+ bg_allowed = true;
+ } else {
+ bg_allowed = true;
+ }
+
+ return bg_allowed;
+}
+
+static void __set_caller_appinfo(const char *caller_appid, int caller_pid,
+ uid_t caller_uid, bundle *kb)
+{
+ char buf[MAX_PID_STR_BUFSZ];
+
+ snprintf(buf, sizeof(buf), "%d", caller_pid);
+ bundle_del(kb, AUL_K_CALLER_PID);
+ bundle_add(kb, AUL_K_CALLER_PID, buf);
+
+ snprintf(buf, sizeof(buf), "%d", caller_uid);
+ bundle_del(kb, AUL_K_CALLER_UID);
+ bundle_add(kb, AUL_K_CALLER_UID, buf);
+
+ if (caller_appid) {
+ bundle_del(kb, AUL_K_CALLER_APPID);
+ bundle_add(kb, AUL_K_CALLER_APPID, caller_appid);
+ }
+}
+
+static const char *__get_caller_appid(int caller_pid, uid_t caller_uid)
+{
+ app_status_h app_status;
+
+ app_status = _app_status_find(caller_pid);
+ if (app_status == NULL && caller_uid >= REGULAR_UID_MIN)
+ app_status = _app_status_find(getpgid(caller_pid));
+
+ return _app_status_get_appid(app_status);
+}
+
+static int __check_executable(const struct appinfo *ai)
+{
+ const char *status;
+ int enable;
+ int ret;
+
+ status = _appinfo_get_value(ai, AIT_STATUS);
+ if (status == NULL)
+ return -1;
+
+ if (strcmp(status, "blocking") == 0) {
+ _D("Blocking");
+ return -EREJECTED;
+ }
+
+ ret = _appinfo_get_int_value(ai, AIT_ENABLEMENT, &enable);
+ if (ret == 0 && !(enable & APP_ENABLEMENT_MASK_ACTIVE)) {
+ _D("Disabled");
+ return -EREJECTED;
+ }
+
+ return 0;
+}
+
+static void __set_appinfo_for_launchpad(const struct appinfo *ai, bundle *kb)
+{
+ const char *str;
+
+ str = _appinfo_get_value(ai, AIT_HWACC);
+ if (str) {
+ bundle_del(kb, AUL_K_HWACC);
+ bundle_add(kb, AUL_K_HWACC, str);
+ }
+
+ str = _appinfo_get_value(ai, AIT_ROOT_PATH);
+ if (str) {
+ bundle_del(kb, AUL_K_ROOT_PATH);
+ bundle_add(kb, AUL_K_ROOT_PATH, str);
+ }
+
+ str = _appinfo_get_value(ai, AIT_EXEC);
+ if (str) {
+ bundle_del(kb, AUL_K_EXEC);
+ bundle_add(kb, AUL_K_EXEC, str);
+ }
+
+ str = _appinfo_get_value(ai, AIT_PKGTYPE);
+ if (str) {
+ bundle_del(kb, AUL_K_PACKAGETYPE);
+ bundle_add(kb, AUL_K_PACKAGETYPE, str);
+ }
+
+ str = _appinfo_get_value(ai, AIT_PKGID);
+ if (str) {
+ bundle_del(kb, AUL_K_PKGID);
+ bundle_add(kb, AUL_K_PKGID, str);
+ }
+
+ str = _appinfo_get_value(ai, AIT_POOL);
+ if (str) {
+ bundle_del(kb, AUL_K_INTERNAL_POOL);
+ bundle_add(kb, AUL_K_INTERNAL_POOL, str);
+ }
+
+ str = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (str) {
+ bundle_del(kb, AUL_K_COMP_TYPE);
+ bundle_add(kb, AUL_K_COMP_TYPE, str);
+ }
+
+ str = _appinfo_get_value(ai, AIT_APPTYPE);
+ if (str) {
+ bundle_del(kb, AUL_K_APP_TYPE);
+ bundle_add(kb, AUL_K_APP_TYPE, str);
+ }
+
+ str = _appinfo_get_value(ai, AIT_API_VERSION);
+ if (str) {
+ bundle_del(kb, AUL_K_API_VERSION);
+ bundle_add(kb, AUL_K_API_VERSION, str);
+ }
+}
+
+static int __get_app_status(struct launch_s *handle, request_h req,
+ const char *comp_type, const char *caller_appid)
+{
+ const char *widget_viewer;
+ const char *multiple;
+ int *target_pid = NULL;
+ size_t target_pid_sz;
+ bundle *kb = _request_get_bundle(req);
+ int caller_pid = _request_get_pid(req);
+ uid_t target_uid = _request_get_target_uid(req);
+ int ret;
+
+ if (caller_appid && strcmp(comp_type, APP_TYPE_WIDGET) == 0) {
+ handle->is_subapp = true;
+ widget_viewer = bundle_get_val(kb, AUL_K_WIDGET_VIEWER);
+ if (widget_viewer && strcmp(widget_viewer, caller_appid) == 0) {
+ _D("widget_viewer(%s)", widget_viewer);
+ handle->app_status = _app_status_find_with_org_caller(
+ handle->appid, target_uid, caller_pid);
+ } else {
+ ret = bundle_get_byte(kb, AUL_K_TARGET_PID,
+ (void **)&target_pid, &target_pid_sz);
+ if (ret != BUNDLE_ERROR_NONE) {
+ _E("Cannot launch widget app");
+ return -EREJECTED;
+ }
+
+ handle->app_status = _app_status_find(*target_pid);
+ if (handle->app_status == NULL) {
+ _E("Cannot find widget app(%d)", *target_pid);
+ return -EREJECTED;
+ }
+ }
+ } else if (strcmp(comp_type, APP_TYPE_WATCH) == 0) {
+ handle->is_subapp = true;
+ widget_viewer = bundle_get_val(kb, AUL_K_WIDGET_VIEWER);
+ if (widget_viewer && caller_appid &&
+ !strcmp(widget_viewer, caller_appid)) {
+ _D("watch_viewer(%s)", widget_viewer);
+ handle->app_status = _app_status_find_with_org_caller(
+ handle->appid, target_uid, caller_pid);
+ } else {
+ ret = bundle_get_byte(kb, AUL_K_TARGET_PID,
+ (void **)&target_pid, &target_pid_sz);
+ if (ret != BUNDLE_ERROR_NONE) {
+ handle->app_status =
+ _app_status_find_by_appid_v2(
+ handle->appid,
+ target_uid);
+ } else {
+ handle->app_status =
+ _app_status_find(*target_pid);
+ }
+
+ if (handle->app_status == NULL) {
+ _E("Cannot find watch app(%s)", handle->appid);
+ return -EREJECTED;
+ }
+ }
+ } else {
+ handle->instance_id = bundle_get_val(kb, AUL_K_INSTANCE_ID);
+ if (handle->instance_id) {
+ handle->app_status = _app_status_find_by_instance_id(
+ handle->appid, handle->instance_id,
+ target_uid);
+ if (!handle->app_status && !handle->new_instance) {
+ _E("Failed to find app instance(%s)",
+ handle->instance_id);
+ return -EREJECTED;
+ }
+ } else {
+ multiple = _appinfo_get_value(handle->ai, AIT_MULTI);
+ if (multiple == NULL || !strcmp(multiple, "false")) {
+ handle->app_status = _app_status_find_by_appid(
+ handle->appid, target_uid);
+ }
+ }
+ }
+
+ handle->pid = _app_status_get_pid(handle->app_status);
+
+ return 0;
+}
+
+static int __prepare_starting_app(struct launch_s *handle, request_h req,
+ const char *appid, bool new_instance)
+{
+ int ret;
+ const char *pkgid;
+ const char *comp_type;
+ const char *caller_appid;
+ const char *installed_storage;
+ const char *bg_launch;
+ const char *global;
+ int cmd = _request_get_cmd(req);
+ int caller_pid = _request_get_pid(req);
+ uid_t caller_uid = _request_get_uid(req);
+ uid_t target_uid = _request_get_target_uid(req);
+ uid_t pkg_uid;
+ bundle *kb = _request_get_bundle(req);
+#ifdef TIZEN_FEATURE_BLOCK_INPUT
+ int status;
+#endif /* TIZEN_FEATURE_BLOCK_INPUT */
+ const struct appinfo *caller_ai;
+
+ handle->new_instance = new_instance;
+ handle->appid = appid;
+ handle->ai = _appinfo_find(target_uid, appid);
+ if (handle->ai == NULL) {
+ _D("Failed to find appinfo of %s", appid);
+ return -ENOENT;
+ }
+
+ ret = __check_executable(handle->ai);
+ if (ret < 0)
+ return -1;
+
+ caller_appid = __get_caller_appid(caller_pid, caller_uid);
+ if (caller_appid) {
+ caller_ai = _appinfo_find(caller_uid, caller_appid);
+ if (caller_ai) {
+ comp_type = _appinfo_get_value(caller_ai, AIT_COMPTYPE);
+ if (comp_type && !strcmp(comp_type, APP_TYPE_UI))
+ bundle_del(kb, AUL_SVC_K_CAN_BE_LEADER);
+ }
+ }
+ __set_caller_appinfo(caller_appid, caller_pid, caller_uid, kb);
+
+ ret = __compare_signature(handle->ai, cmd, target_uid, appid,
+ caller_appid);
+ if (ret < 0)
+ return ret;
+
+ ret = _cooldown_check_mode(handle->ai);
+ if (ret < 0) {
+ _E("Unable to launch %s in cooldown mode", handle->appid);
+ return ret;
+ }
+
+ pkgid = _appinfo_get_value(handle->ai, AIT_PKGID);
+ installed_storage = _appinfo_get_value(handle->ai, AIT_STORAGE_TYPE);
+ if (installed_storage && strcmp(installed_storage, "external") == 0) {
+ global = _appinfo_get_value(handle->ai, AIT_GLOBAL);
+
+ if (global && strcmp("true", global) == 0)
+ pkg_uid = GLOBAL_USER;
+ else
+ pkg_uid = target_uid;
+
+ if (app2ext_usr_enable_external_pkg(pkgid, pkg_uid) < 0) {
+ _E("Failed to enable exteranl pkg(%s)", pkgid);
+ return -1;
+ }
+ }
+
+ bg_launch = bundle_get_val(kb, AUL_SVC_K_BG_LAUNCH);
+ if (bg_launch && strcmp(bg_launch, "enable") == 0)
+ handle->bg_launch = true;
+
+ comp_type = _appinfo_get_value(handle->ai, AIT_COMPTYPE);
+ if (comp_type == NULL)
+ return -1;
+
+ ret = __get_app_status(handle, req, comp_type, caller_appid);
+ if (ret < 0)
+ return ret;
+
+ if (strcmp(comp_type, APP_TYPE_UI) == 0) {
+ ret = __get_pid_for_app_group(appid, target_uid, kb, handle);
+ if (ret < 0)
+ return ret;
+
+#ifdef TIZEN_FEATURE_BLOCK_INPUT
+ status = _app_status_get_status(handle->app_status);
+ if (status != STATUS_VISIBLE && !handle->bg_launch)
+ _input_lock();
+#endif /* TIZEN_FEATURE_BLOCK_INPUT */
+ } else if (caller_appid && strcmp(comp_type, APP_TYPE_SERVICE) == 0) {
+ ret = __check_execute_permission(pkgid, caller_appid,
+ target_uid, kb);
+ if (ret < 0)
+ return ret;
+ } else if (caller_appid && strcmp(comp_type, APP_TYPE_WIDGET) == 0) {
+ ret = _widget_verify_cmd(req);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (cmd == APP_START_RES) {
+ bundle_del(kb, AUL_K_WAIT_RESULT);
+ bundle_add(kb, AUL_K_WAIT_RESULT, "1");
+ }
+
+ if (caller_appid) {
+ handle->share_info = _temporary_permission_create(caller_pid,
+ appid, kb, target_uid);
+ if (handle->share_info == NULL)
+ _W("No sharable path: %d %s", caller_pid, appid);
+ }
+
+ _extractor_mount(handle->ai, kb, _extractor_mountable_get_tep_paths);
+ _extractor_mount(handle->ai, kb, _extractor_mountable_get_tpk_paths);
+
+ handle->prelaunch_attr = __get_prelaunch_attribute(
+ handle->ai, appid, target_uid);
+ handle->bg_category = __get_background_category(handle->ai);
+ handle->bg_allowed = __is_allowed_background(comp_type,
+ handle->bg_category);
+ if (handle->bg_allowed) {
+ _D("[__SUSPEND__] allowed background, appid: %s, app-type: %s",
+ appid, comp_type);
+ bundle_del(kb, AUL_K_ALLOWED_BG);
+ bundle_add(kb, AUL_K_ALLOWED_BG, "ALLOWED_BG");
+ }
+
+ return 0;
+}
+
+static int __do_starting_app(struct launch_s *handle, request_h req,
+ bool *pending, bool *bg_launch)
+{
+ int status = -1;
+ int cmd = _request_get_cmd(req);
+ int caller_pid = _request_get_pid(req);
+ uid_t target_uid = _request_get_target_uid(req);
+ bundle *kb = _request_get_bundle(req);
+ const char *pkgid;
+ const char *comp_type;
+ const char *pad_type = LAUNCHPAD_PROCESS_POOL_SOCK;
+ splash_image_h splash_image = NULL;
+ int ret;
+ char err_buf[1024];
+ bool socket_exists;
+
+ pkgid = _appinfo_get_value(handle->ai, AIT_PKGID);
+ comp_type = _appinfo_get_value(handle->ai, AIT_COMPTYPE);
+ status = _app_status_get_status(handle->app_status);
+ if (handle->pid > 0 && status != STATUS_DYING) {
+ if (handle->pid == caller_pid) {
+ SECURE_LOGD("caller & callee process are same. %s:%d,",
+ handle->appid, handle->pid);
+ return -ELOCALLAUNCH_ID;
+ }
+
+ _util_save_log("RESUMING", handle->appid);
+
+ aul_send_app_resume_request_signal(handle->pid,
+ handle->appid, pkgid, comp_type);
+ _suspend_remove_timer(handle->pid);
+ if (comp_type && !strcmp(comp_type, APP_TYPE_SERVICE)) {
+ if (handle->bg_allowed == false) {
+ __prepare_to_wake_services(handle->pid,
+ target_uid);
+ }
+ }
+
+ ret = __nofork_processing(cmd, handle->pid, kb, req);
+ if (ret < 0) {
+ _temporary_permission_destroy(handle->share_info);
+ socket_exists =
+ _app_status_socket_exists(handle->app_status);
+ if (ret == -ECOMM && socket_exists) {
+ _E("ECOMM error, we will term the app - %s:%d",
+ handle->appid, handle->pid);
+ _send_to_sigkill(handle->pid);
+ _app_status_cleanup(handle->app_status);
+ return -1;
+ }
+ }
+
+ _app_status_update_last_caller_pid(
+ handle->app_status, caller_pid);
+ _app_status_update_bg_launch(
+ handle->app_status, handle->bg_launch);
+ *bg_launch = _app_status_get_bg_launch(handle->app_status);
+
+ return ret;
+ }
+
+ if (handle->pid > 0 && status == STATUS_DYING) {
+ ret = kill(handle->pid, SIGKILL);
+ if (ret == -1) {
+ _W("Failed to send SIGKILL: %d:%s,", handle->pid,
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ }
+ _app_status_cleanup(handle->app_status);
+ }
+
+ __set_appinfo_for_launchpad(handle->ai, kb);
+ if (bundle_get_type(kb, AUL_K_SDK) != BUNDLE_TYPE_NONE) {
+ aul_svc_set_loader_id(kb, PAD_LOADER_ID_DIRECT);
+ handle->debug_mode = true;
+ }
+
+ if (handle->instance_id == NULL && handle->bg_launch == false) {
+ splash_image = _splash_screen_create_image(handle->ai, kb, cmd,
+ handle->is_subapp);
+ _splash_screen_send_image(splash_image);
+ }
+
+ _signal_send_proc_prelaunch(handle->appid, pkgid,
+ handle->prelaunch_attr, handle->bg_category);
+ _signal_send_cpu_boost(APP_BOOSTING_PERIOD);
+
+ if (__get_tizen_profile() == TIZEN_PROFILE_WEARABLE)
+ bundle_add(kb, AUL_K_PROFILE, "wearable");
+ ret = _send_cmd_to_launchpad(pad_type, target_uid, PAD_CMD_LAUNCH, kb);
+ if (ret < 0) {
+ _signal_send_cpu_boost(APP_BOOSTING_STOP);
+ _temporary_permission_destroy(handle->share_info);
+ _splash_screen_destroy_image(splash_image);
+ return ret;
+ }
+
+ handle->pid = ret;
+ *pending = true;
+ *bg_launch = handle->bg_launch;
+
+ if (splash_image) {
+ _splash_screen_send_pid(splash_image, handle->pid);
+ } else if (comp_type && !strcmp(comp_type, APP_TYPE_UI)) {
+ _splash_screen_set_effect_type(handle->pid, handle->appid,
+ handle->is_subapp);
+ }
+
+ _suspend_add_proc(handle->pid);
+ aul_send_app_launch_request_signal(handle->pid, handle->appid,
+ pkgid, comp_type);
+
+ _util_save_log("LAUNCHING", handle->appid);
+ if (handle->debug_mode) {
+ _W("Exclude - %s(%d)", handle->appid, handle->pid);
+ aul_update_freezer_status(handle->pid, "exclude");
+ return ret;
+ }
+
+ if (comp_type && !strcmp(comp_type, APP_TYPE_SERVICE)) {
+ if (!handle->bg_allowed)
+ g_idle_add(__check_service_only, GINT_TO_POINTER(ret));
+ }
+
+ return ret;
+}
+
+static int __complete_starting_app(struct launch_s *handle, request_h req)
+{
+ bundle *kb = _request_get_bundle(req);
+ uid_t target_uid = _request_get_target_uid(req);
+ int caller_pid = _request_get_pid(req);
+ const char *comp_type;
+ int ret;
+ char log_status[AUL_PR_NAME];
+
+ comp_type = _appinfo_get_value(handle->ai, AIT_COMPTYPE);
+ if (comp_type && !strcmp(comp_type, APP_TYPE_UI)) {
+ if (handle->new_process) {
+ _D("Add app group info %d", handle->pid);
+ __pid_of_last_launched_ui_app = handle->pid;
+ _app_group_start_app(handle->pid, kb,
+ handle->leader_pid,
+ handle->can_attach,
+ handle->launch_mode);
+ } else {
+ _app_group_restart_app(handle->pid, kb);
+ }
+ }
+
+ _app_status_add_app_info(handle->ai, handle->pid, handle->is_subapp,
+ target_uid, caller_pid, handle->bg_launch,
+ handle->instance_id, handle->debug_mode);
+
+ if (handle->share_info) {
+ ret = _temporary_permission_apply(handle->pid, target_uid,
+ handle->share_info);
+ if (ret < 0)
+ _D("Couldn't apply temporary permission: %d", ret);
+
+ _temporary_permission_destroy(handle->share_info);
+ }
+
+ snprintf(log_status, sizeof(log_status), "SUCCESS: %d", handle->pid);
+ _util_save_log(log_status, handle->appid);
+ return handle->pid;
+}
+
+static void __handle_onboot(void *user_data, const char *appid,
+ struct appinfo *info)
+{
+ uid_t uid = GPOINTER_TO_UINT(user_data);
+
+ _launch_start_onboot_app_local(uid, appid, info);
+}
+
+static gboolean __load_onboot_apps(gpointer data)
+{
+ uid_t uid = GPOINTER_TO_UINT(data);
+
+ _D("onboot uid(%d)", uid);
+ _appinfo_foreach(uid, __handle_onboot, data);
+ _signal_send_display_unlock_state(SYSTEM_LCD_OFF, SYSTEM_SLEEP_MARGIN);
+
+ return FALSE;
+}
+
+int _launch_start_onboot_apps(uid_t uid)
+{
+ _signal_send_display_lock_state(SYSTEM_LCD_OFF,
+ SYSTEM_STAY_CUR_STATE, 0);
+ g_idle_add(__load_onboot_apps, GUINT_TO_POINTER(uid));
+
+ return 0;
+}
+
+int _launch_start_app(const char *appid, request_h req, bool *pending,
+ bool *bg_launch, bool new_instance)
+{
+ int ret;
+ struct launch_s launch_data = {0,};
+ int caller_pid = _request_get_pid(req);
+ uid_t caller_uid = _request_get_uid(req);
+ int cmd = _request_get_cmd(req);
+
+ traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "AMD:START_APP");
+ _D("_launch_start_app: appid=%s caller pid=%d uid=%d",
+ appid, caller_pid, caller_uid);
+
+ ret = __prepare_starting_app(&launch_data, req, appid, new_instance);
+ if (ret < 0) {
+ _request_send_result(req, ret);
+ traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
+ _util_save_log("FAILURE", appid);
+ return -1;
+ }
+
+ ret = __do_starting_app(&launch_data, req, pending, bg_launch);
+ if (ret < 0) {
+ _request_send_result(req, ret);
+ traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
+ _util_save_log("FAILURE", appid);
+ return -1;
+ }
+
+ if (cmd == APP_START_ASYNC || cmd == APP_START_RES_ASYNC)
+ _request_send_result(req, ret);
+
+ ret = __complete_starting_app(&launch_data, req);
+ traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
+ if (ret < 0)
+ _util_save_log("FAILURE", appid);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <systemd/sd-login.h>
+#include <tzplatform_config.h>
+#include <bundle_internal.h>
+
+#include "amd_util.h"
+#include "amd_login_monitor.h"
+#include "amd_appinfo.h"
+#include "amd_app_property.h"
+#include "amd_app_status.h"
+#include "amd_wayland.h"
+#include "amd_socket.h"
+#include "amd_request.h"
+#include "amd_screen_connector.h"
+#include "amd_launch.h"
+#include "amd_signal.h"
+#include "amd_rua.h"
+
+#define PATH_AUL_DAEMONS "/run/aul/daemons"
+#define LOGIN_TIMEOUT_SEC 90
+
+typedef int (*login_cb)(uid_t uid);
+typedef void (*logout_cb)(uid_t uid);
+
+typedef struct login_handler_s {
+ uid_state state;
+ login_cb login;
+} login_handler;
+
+typedef struct logout_handler_s {
+ uid_state state;
+ logout_cb logout;
+} logout_handler;
+
+struct login_monitor_s {
+ sd_login_monitor *m;
+ GIOChannel *io;
+ guint sid;
+};
+
+struct user_s {
+ uid_t uid;
+ uid_state state;
+ guint timer;
+};
+
+static struct login_monitor_s *login_monitor;
+static GList *user_list;
+static login_handler login_table[] = {
+ {
+ .state = UID_STATE_OPENING | UID_STATE_ONLINE |
+ UID_STATE_ACTIVE,
+ .login = _appinfo_load
+ },
+ {
+ .state = UID_STATE_OPENING | UID_STATE_ONLINE |
+ UID_STATE_ACTIVE,
+ .login = _app_property_load
+ },
+ {
+ .state = UID_STATE_OPENING | UID_STATE_ONLINE |
+ UID_STATE_ACTIVE,
+ .login = _app_status_usr_init
+ },
+ {
+ .state = UID_STATE_OPENING | UID_STATE_ONLINE |
+ UID_STATE_ACTIVE,
+ .login = _screen_connector_usr_init
+ },
+ {
+ .state = UID_STATE_ONLINE | UID_STATE_ACTIVE,
+ .login = _request_usr_init
+ },
+ {
+ .state = UID_STATE_ACTIVE,
+ .login = _launch_start_onboot_apps
+ },
+ {
+ .state = UID_STATE_ONLINE | UID_STATE_ACTIVE,
+ .login = _rua_usr_init
+ }
+};
+static logout_handler logout_table[] = {
+ {
+ .state = UID_STATE_OFFLINE,
+ .logout = _appinfo_unload
+ },
+ {
+ .state = UID_STATE_OFFLINE,
+ .logout = _app_property_unload
+ },
+ {
+ .state = UID_STATE_CLOSING | UID_STATE_OFFLINE,
+ .logout = _app_status_usr_fini
+ },
+ {
+ .state = UID_STATE_CLOSING | UID_STATE_OFFLINE,
+ .logout = _screen_connector_usr_fini
+ },
+ {
+ .state = UID_STATE_CLOSING | UID_STATE_OFFLINE,
+ .logout = _rua_usr_fini
+ }
+};
+
+static int __connect_to_launchpad(uid_t uid);
+static void __user_login(struct user_s *user);
+
+static gboolean __login_timout_handler(gpointer data)
+{
+ struct user_s *user = (struct user_s *)data;
+
+ if (user->state == UID_STATE_ACTIVE) {
+ user->timer = 0;
+ return FALSE;
+ }
+
+ user->timer = 0;
+ user->state = UID_STATE_ACTIVE;
+ __user_login(user);
+
+ return FALSE;
+}
+
+static void __user_login(struct user_s *user)
+{
+ unsigned int i;
+
+ if (user->state == UID_STATE_OPENING) {
+ if (__connect_to_launchpad(user->uid) == 0) {
+ user->state = UID_STATE_ONLINE;
+ user->timer = g_timeout_add_seconds(
+ LOGIN_TIMEOUT_SEC,
+ __login_timout_handler,
+ user);
+ }
+ }
+
+ _D("user login - uid(%d), state(%d)", user->uid, user->state);
+ for (i = 0; i < ARRAY_SIZE(login_table); i++) {
+ if (login_table[i].state & user->state) {
+ if (login_table[i].login)
+ login_table[i].login(user->uid);
+ }
+ }
+}
+
+static void __user_logout(struct user_s *user)
+{
+ unsigned int i;
+
+ _D("user logout - uid(%d), state(%d)", user->uid, user->state);
+ for (i = 0; i < ARRAY_SIZE(logout_table); i++) {
+ if (logout_table[i].state & user->state) {
+ if (logout_table[i].logout)
+ logout_table[i].logout(user->uid);
+ }
+ }
+}
+
+void _login_monitor_set_uid_state(uid_t uid, uid_state state)
+{
+ GList *iter;
+ struct user_s *user;
+
+ if (uid < REGULAR_UID_MIN)
+ return;
+
+ iter = g_list_first(user_list);
+ while (iter) {
+ user = (struct user_s *)iter->data;
+ if (user && user->uid == uid && user->state != state) {
+ user->state = state;
+ if (user->state == UID_STATE_ONLINE) {
+ user->timer = g_timeout_add_seconds(
+ LOGIN_TIMEOUT_SEC,
+ __login_timout_handler,
+ user);
+ __user_login(user);
+ } else {
+ __user_logout(user);
+ }
+ break;
+ }
+ iter = g_list_next(iter);
+ }
+}
+
+uid_state _login_monitor_get_uid_state(uid_t uid)
+{
+ GList *iter;
+ uid_state res = UID_STATE_UNKNOWN;
+ struct user_s *user;
+
+ if (uid < REGULAR_UID_MIN)
+ return res;
+
+ iter = g_list_first(user_list);
+ while (iter) {
+ user = (struct user_s *)iter->data;
+ if (user && user->uid == uid) {
+ res = user->state;
+ break;
+ }
+ iter = g_list_next(iter);
+ }
+
+ return res;
+}
+
+int _login_monitor_get_uids(uid_t **uids)
+{
+ int r;
+ uid_t *l;
+ GList *iter;
+ unsigned int i = 0;
+ struct user_s *user;
+
+ if (uids == NULL) {
+ _E("Invalid parameter");
+ return -1;
+ }
+
+ if (user_list == NULL)
+ return -1;
+
+ r = g_list_length(user_list);
+ if (r == 0)
+ return 0;
+
+ l = calloc(r, sizeof(uid_t));
+ if (l == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ iter = g_list_first(user_list);
+ while (iter) {
+ user = (struct user_s *)iter->data;
+ l[i++] = user->uid;
+ iter = g_list_next(iter);
+ }
+
+ *uids = l;
+
+ return r;
+}
+
+static int __connect_to_launchpad(uid_t uid)
+{
+ int r;
+ bundle *b;
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof(path), "%s/%d/%s",
+ PATH_AUL_DAEMONS, uid, LAUNCHPAD_PROCESS_POOL_SOCK);
+ if (access(path, F_OK) != 0) {
+ _D("%s doesn't exist", path);
+ return -1;
+ }
+
+ b = bundle_create();
+ if (b == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ r = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK,
+ uid, PAD_CMD_PING, b);
+ bundle_free(b);
+ if (r != 0) {
+ _E("Failed to connect launchpad - uid(%d), result(%d)", uid, r);
+ return -1;
+ }
+
+ return 0;
+}
+
+static gint __compare_uids(gconstpointer a, gconstpointer b)
+{
+ struct user_s *user = (struct user_s *)a;
+ uid_t cur_uid = GPOINTER_TO_UINT(b);
+
+ if (user == NULL)
+ return -1;
+
+ if (user->uid == cur_uid)
+ return 0;
+
+ return -1;
+}
+
+static void __check_user_state(void)
+{
+ uid_t *uids = NULL;
+ int ret;
+ int i;
+ GList *list;
+ char *state = NULL;
+ struct user_s *user;
+
+ ret = sd_get_uids(&uids);
+ if (ret <= 0) {
+ _W("Failed to get uids - %d", ret);
+ return;
+ }
+
+ for (i = 0; i < ret; i++) {
+ if (uids[i] < REGULAR_UID_MIN)
+ continue;
+
+ if (sd_uid_get_state(uids[i], &state) < 0)
+ continue;
+
+ list = g_list_find_custom(user_list,
+ GUINT_TO_POINTER(uids[i]),
+ __compare_uids);
+
+ if (strcmp(state, "opening") == 0 ||
+ strcmp(state, "online") == 0) {
+ if (list == NULL) {
+ user = malloc(sizeof(struct user_s));
+ if (user == NULL) {
+ _E("out of memory");
+ free(uids);
+ return;
+ }
+ user->uid = uids[i];
+ user->state = UID_STATE_OPENING;
+ user->timer = 0;
+ user_list = g_list_append(user_list, user);
+ __user_login(user);
+ }
+ } else if (strcmp(state, "closing") == 0) {
+ if (list) {
+ user = (struct user_s *)list->data;
+ if (user) {
+ user->state = UID_STATE_CLOSING;
+ __user_logout(user);
+ }
+ }
+ } else if (strcmp(state, "offline") == 0) {
+ if (list) {
+ user = (struct user_s *)list->data;
+ if (user) {
+ user_list = g_list_remove(user_list,
+ user);
+ user->state = UID_STATE_OFFLINE;
+ __user_logout(user);
+ if (user->timer)
+ g_source_remove(user->timer);
+ free(user);
+ }
+ }
+ }
+ _D("uid(%d), state(%s)", uids[i], state);
+ free(state);
+ state = NULL;
+ }
+ free(uids);
+}
+
+static gboolean __monitor_login_cb(GIOChannel *io, GIOCondition condition,
+ gpointer data)
+{
+ _D("login monitor");
+ sd_login_monitor_flush(login_monitor->m);
+
+ __check_user_state();
+
+ return TRUE;
+}
+
+static int __init_login_monitor(void)
+{
+ int r;
+ int fd;
+
+ login_monitor = (struct login_monitor_s *)calloc(1,
+ sizeof(struct login_monitor_s));
+ if (login_monitor == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ r = sd_login_monitor_new("uid", &login_monitor->m);
+ if (r < 0) {
+ _E("Failed to create sd login monitor");
+ return -1;
+ }
+
+ fd = sd_login_monitor_get_fd(login_monitor->m);
+ if (fd < 0) {
+ _E("Failed to get file descriptor");
+ return -1;
+ }
+
+ login_monitor->io = g_io_channel_unix_new(fd);
+ if (login_monitor->io == NULL) {
+ _E("Failed to create GIOChannel");
+ return -1;
+ }
+
+ login_monitor->sid = g_io_add_watch(login_monitor->io,
+ G_IO_IN | G_IO_HUP, __monitor_login_cb, NULL);
+ if (login_monitor->sid == 0) {
+ _E("Failed to add gio watch");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __fini_login_monitor(void)
+{
+ if (login_monitor == NULL)
+ return;
+
+ if (login_monitor->sid) {
+ g_source_remove(login_monitor->sid);
+ login_monitor->sid = 0;
+ }
+
+ if (login_monitor->io) {
+ g_io_channel_unref(login_monitor->io);
+ login_monitor->io = NULL;
+ }
+
+ if (login_monitor->m) {
+ sd_login_monitor_unref(login_monitor->m);
+ login_monitor->m = NULL;
+ }
+
+ free(login_monitor);
+ login_monitor = NULL;
+}
+
+static int __startup_finished_cb(uid_t uid, void *user_data)
+{
+ GList *list;
+ struct user_s *user;
+
+ _D("uid(%d)", uid);
+ if (uid < REGULAR_UID_MIN)
+ return -1;
+
+ list = g_list_find_custom(user_list, GUINT_TO_POINTER(uid),
+ __compare_uids);
+ if (list == NULL) {
+ user = malloc(sizeof(struct user_s));
+ if (user == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+ user->uid = uid;
+ user->timer = 0;
+ user_list = g_list_append(user_list, user);
+ } else {
+ user = (struct user_s *)list->data;
+ if (user == NULL)
+ return -1;
+ }
+
+ if (user->timer) {
+ g_source_remove(user->timer);
+ user->timer = 0;
+ }
+
+ user->state = UID_STATE_ACTIVE;
+ __user_login(user);
+
+ return 0;
+}
+
+static int __subscribe_startup_finished(void *data)
+{
+ return _signal_subscribe_startup_finished(__startup_finished_cb, data);
+}
+
+int _login_monitor_init(void)
+{
+ uid_t uid;
+ struct user_s *user;
+
+ _D("login monitor init");
+ if (__init_login_monitor()) {
+ _E("Failed to initialize login monitor");
+ __fini_login_monitor();
+ return -1;
+ }
+
+ __check_user_state();
+
+ if (user_list == NULL || g_list_length(user_list) == 0) {
+ uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
+ _D("default user(%d)", uid);
+ user = malloc(sizeof(struct user_s));
+ if (user == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+ user->uid = uid;
+ user->timer = 0;
+ user->state = UID_STATE_OPENING;
+ user_list = g_list_append(user_list, user);
+ __user_login(user);
+ }
+
+ if (__subscribe_startup_finished(NULL) < 0)
+ _signal_add_initializer(__subscribe_startup_finished, NULL);
+
+ return 0;
+}
+
+void _login_monitor_fini(void)
+{
+ _D("login monitor fini");
+
+ _signal_unsubscribe_startup_finished();
+
+ if (user_list)
+ g_list_free_full(user_list, free);
+
+ __fini_login_monitor();
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <aul.h>
+#include <glib.h>
+#include <tzplatform_config.h>
+#include <systemd/sd-daemon.h>
+
+#include "amd_util.h"
+#include "amd_appinfo.h"
+#include "amd_app_status.h"
+#include "amd_launch.h"
+#include "amd_request.h"
+#include "amd_app_group.h"
+#include "amd_cynara.h"
+#include "amd_app_com.h"
+#include "amd_share.h"
+#include "amd_socket.h"
+#include "amd_splash_screen.h"
+#include "amd_input.h"
+#include "amd_signal.h"
+#include "amd_wayland.h"
+#include "amd_extractor.h"
+#include "amd_suspend.h"
+#include "amd_widget.h"
+#include "amd_app_property.h"
+#include "amd_screen_connector.h"
+#include "amd_login_monitor.h"
+#include "amd_rua.h"
+#include "amd_inotify.h"
+
+struct restart_info {
+ char *appid;
+ int count;
+ guint timer;
+};
+
+static GHashTable *restart_tbl;
+
+static gboolean __restart_timeout_handler(void *data)
+{
+ struct restart_info *ri = (struct restart_info *)data;
+
+ _D("ri (%x)", ri);
+ _D("appid (%s)", ri->appid);
+
+ g_hash_table_remove(restart_tbl, ri->appid);
+ free(ri->appid);
+ free(ri);
+
+ return FALSE;
+}
+
+static bool __check_restart(const char *appid)
+{
+ struct restart_info *ri = NULL;
+ char err_buf[1024];
+
+ ri = g_hash_table_lookup(restart_tbl, appid);
+ if (!ri) {
+ ri = malloc(sizeof(struct restart_info));
+ if (!ri) {
+ _E("create restart info: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return false;
+ }
+ memset(ri, 0, sizeof(struct restart_info));
+ ri->appid = strdup(appid);
+ ri->count = 1;
+ g_hash_table_insert(restart_tbl, ri->appid, ri);
+
+ _D("ri (%x)", ri);
+ _D("appid (%s)", appid);
+
+ ri->timer = g_timeout_add(10 * 1000, __restart_timeout_handler,
+ ri);
+ } else {
+ ri->count++;
+ _D("count (%d)", ri->count);
+ if (ri->count > 5) {
+ g_source_remove(ri->timer);
+ g_hash_table_remove(restart_tbl, ri->appid);
+ free(ri->appid);
+ free(ri);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool __can_restart_app(const char *appid, uid_t uid)
+{
+ const char *pkg_status;
+ const char *component_type;
+ struct appinfo *ai;
+ int r;
+ int val = 0;
+ int enable = 1;
+
+ _D("appid: %s", appid);
+ ai = _appinfo_find(uid, appid);
+ if (!ai)
+ return false;
+
+ component_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (!component_type)
+ return false;
+
+ if (strcmp(component_type, APP_TYPE_SERVICE) != 0)
+ return false;
+
+ r = _appinfo_get_int_value(ai, AIT_ENABLEMENT, &enable);
+ if (r == 0 && !(enable & APP_ENABLEMENT_MASK_ACTIVE)) {
+ _D("Disabled");
+ return false;
+ }
+
+ pkg_status = _appinfo_get_value(ai, AIT_STATUS);
+ if (pkg_status && strcmp(pkg_status, "blocking") == 0) {
+ _appinfo_set_value(ai, AIT_STATUS, "restart");
+ } else if (pkg_status && strcmp(pkg_status, "norestart") == 0) {
+ _appinfo_set_value(ai, AIT_STATUS, "installed");
+ } else {
+ r = _appinfo_get_int_value(ai, AIT_RESTART, &val);
+ if (r == 0 && val && __check_restart(appid))
+ return true;
+ }
+
+ return false;
+}
+
+static int __app_dead_handler(int pid, void *data)
+{
+ bool restart = false;
+ char *appid = NULL;
+ const char *tmp_appid;
+ app_status_h app_status;
+ splash_image_h splash_image;
+ uid_t uid;
+ char buf[MAX_LOCAL_BUFSZ];
+ int app_type;
+
+ if (pid <= 0)
+ return 0;
+
+ _D("APP_DEAD_SIGNAL : %d", pid);
+
+ splash_image = _splash_screen_get_image(pid);
+ if (splash_image)
+ _splash_screen_destroy_image(splash_image);
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return 0;
+
+ tmp_appid = _app_status_get_appid(app_status);
+ if (tmp_appid == NULL)
+ return 0;
+
+ uid = _app_status_get_uid(app_status);
+ app_type = _app_status_get_app_type(app_status);
+
+ if (app_type == AT_WIDGET_APP) {
+ _widget_dead_handler(
+ pid,
+ uid,
+ _app_status_get_pkgid(app_status),
+ _app_status_get_org_caller_pid(app_status),
+ _app_status_get_is_exit_notified(app_status),
+ __check_restart(tmp_appid)
+ );
+ } else if (app_type == AT_WATCH_APP) {
+ _app_status_fault_recovery(
+ pid,
+ uid,
+ _app_status_get_pkgid(app_status),
+ tmp_appid,
+ app_type,
+ _app_status_get_is_exit_notified(app_status));
+
+ }
+
+ restart = __can_restart_app(tmp_appid, uid);
+ if (restart)
+ appid = strdup(tmp_appid);
+
+ _request_flush_pending_request(pid);
+ _app_status_publish_status(pid, STATUS_TERMINATE);
+ _app_status_cleanup(app_status);
+
+ if (restart)
+ _launch_start_app_local(uid, appid);
+ if (appid)
+ free(appid);
+
+ snprintf(buf, sizeof(buf), "%d", pid);
+ _util_save_log("TERMINATED", buf);
+ return 0;
+}
+
+static int __listen_app_dead_signal(void *data)
+{
+ int ret;
+
+ ret = aul_listen_app_dead_signal(__app_dead_handler, data);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+static void __ignore_app_dead_signal(void)
+{
+ aul_listen_app_dead_signal(NULL, NULL);
+}
+
+static int __init(void)
+{
+ int r;
+
+ if (_appinfo_init()) {
+ _E("_appinfo_init failed");
+ return -1;
+ }
+
+ if (__listen_app_dead_signal(NULL) < 0) {
+ _W("aul_listen_app_dead_signal failed");
+ _signal_add_initializer(__listen_app_dead_signal, NULL);
+ }
+
+ restart_tbl = g_hash_table_new(g_str_hash, g_str_equal);
+
+ r = _cynara_init();
+ if (r != 0) {
+ _E("cynara initialize failed.");
+ return -1;
+ }
+
+ _request_init();
+ _app_status_init();
+ _app_group_init();
+ _app_com_broker_init();
+ _launch_init();
+ _splash_screen_init();
+#ifdef TIZEN_FEATURE_BLOCK_INPUT
+ _input_init();
+#endif /* TIZEN_FEATURE_BLOCK_INPUT */
+ _wayland_init();
+ _suspend_init();
+ _signal_init();
+ _widget_init();
+ _app_property_init();
+ _screen_connector_init();
+ _login_monitor_init();
+ _util_init();
+ _rua_init();
+ _inotify_init();
+
+ return 0;
+}
+
+static void __ready(void)
+{
+ int fd;
+
+ _D("AMD is ready");
+
+ fd = creat("/run/.amd_ready",
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ if (fd != -1)
+ close(fd);
+
+ sd_notify(0, "READY=1");
+}
+
+static void __finish(void)
+{
+ _inotify_fini();
+ _rua_fini();
+ _util_fini();
+ _login_monitor_fini();
+ _screen_connector_fini();
+ _app_property_fini();
+ _widget_fini();
+ _suspend_fini();
+ _wayland_finish();
+#ifdef TIZEN_FEATURE_BLOCK_INPUT
+ _input_fini();
+#endif /* TIZEN_FEATURE_BLOCK_INPUT */
+ _app_com_broker_fini();
+ _app_group_fini();
+ _app_status_finish();
+ _request_fini();
+ _cynara_finish();
+
+ if (restart_tbl) {
+ g_hash_table_destroy(restart_tbl);
+ restart_tbl = NULL;
+ }
+
+ __ignore_app_dead_signal();
+
+ _appinfo_fini();
+}
+
+int main(int argc, char *argv[])
+{
+ GMainLoop *mainloop = NULL;
+
+ if (__init() != 0) {
+ _E("AMD Initialization failed!\n");
+ return -1;
+ }
+
+ __ready();
+
+ mainloop = g_main_loop_new(NULL, FALSE);
+ if (!mainloop) {
+ _E("failed to create glib main loop");
+ return -1;
+ }
+ g_main_loop_run(mainloop);
+
+ __finish();
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <poll.h>
+#include <ctype.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <aul.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <rua_internal.h>
+#include <rua_stat_internal.h>
+#include <tzplatform_config.h>
+#include <systemd/sd-login.h>
+#include <aul_sock.h>
+#include <aul_svc.h>
+#include <aul_app_com.h>
+#include <aul_screen_connector.h>
+
+#include "amd_util.h"
+#include "amd_request.h"
+#include "amd_launch.h"
+#include "amd_appinfo.h"
+#include "amd_app_status.h"
+#include "amd_app_group.h"
+#include "amd_cynara.h"
+#include "amd_socket.h"
+#include "amd_app_com.h"
+#include "amd_share.h"
+#include "amd_input.h"
+#include "amd_widget.h"
+#include "aul_svc_priv_key.h"
+#include "amd_signal.h"
+#include "amd_app_property.h"
+#include "amd_screen_connector.h"
+#include "amd_login_monitor.h"
+#include "amd_rua.h"
+
+#define INHOUSE_UID tzplatform_getuid(TZ_USER_NAME)
+
+#define MAX_NR_OF_DESCRIPTORS 2
+#define PENDING_REQUEST_TIMEOUT 5000 /* msec */
+#define SYSTEM_REQUEST_TIMEOUT 90000 /* msec */
+#define PENDING_MESSAGE_MAX_CNT 100
+#define MULTI_INSTANCE_SHORTCUT "multi-instance-shortcut"
+#define QUERY_KEY_ID "id="
+#define QUERY_KEY_ICON "icon="
+#define QUERY_KEY_NAME "name="
+
+static int amd_fd;
+static GIOChannel *amd_io;
+static guint amd_wid;
+static GHashTable *__dc_socket_pair_hash;
+static GHashTable *pending_table;
+
+struct pending_item {
+ int pid;
+ guint timer;
+ GList *pending_list;
+ GList *reply_list;
+};
+
+struct request_s {
+ GTimeVal start;
+ guint timer;
+ int cmd;
+ int clifd;
+ pid_t pid;
+ pid_t t_pid;
+ uid_t uid;
+ uid_t t_uid;
+ bundle *kb;
+ int len;
+ int opt;
+ unsigned char data[1];
+};
+
+typedef struct _rua_stat_pkt_t {
+ pid_t pid;
+ uid_t uid;
+ char *stat_tag;
+ char *stat_caller;
+ char *appid;
+ char *instance_id;
+ char *instance_name;
+ char *icon;
+ char *uri;
+ gboolean is_group_app;
+ char *data;
+ int len;
+} rua_stat_pkt_t;
+
+struct reply_info {
+ guint timer;
+ pid_t pid;
+ int result;
+ int cmd;
+ int clifd;
+ rua_stat_pkt_t *rua;
+};
+
+struct instance_info {
+ char *id;
+ char *name;
+ char *icon;
+ char *uri;
+};
+
+typedef int (*app_cmd_dispatch_func)(request_h req);
+static gboolean __timeout_pending_item(gpointer user_data);
+static gboolean __dispatch_request(gpointer data);
+static gboolean __timeout_request(gpointer data);
+static gboolean __timeout_reply(gpointer data);
+static struct reply_info *__create_reply_info(guint interval, pid_t pid,
+ int result, int cmd, int clifd, rua_stat_pkt_t *rua);
+
+static int __send_message(int sock, const struct iovec *vec, int vec_size,
+ const int *desc, int nr_desc)
+{
+ struct msghdr msg = {0,};
+ int sndret;
+ int desclen = 0;
+ struct cmsghdr *cmsg = NULL;
+ char buff[CMSG_SPACE(sizeof(int) * MAX_NR_OF_DESCRIPTORS)] = {0,};
+
+ if (vec == NULL || vec_size < 1)
+ return -EINVAL;
+ if (nr_desc < 0 || nr_desc > MAX_NR_OF_DESCRIPTORS)
+ return -EINVAL;
+ if (desc == NULL)
+ nr_desc = 0;
+
+ msg.msg_iov = (struct iovec *)vec;
+ msg.msg_iovlen = vec_size;
+
+ /* sending ancillary data */
+ if (nr_desc > 0) {
+ msg.msg_control = buff;
+ msg.msg_controllen = sizeof(buff);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg == NULL)
+ return -EINVAL;
+
+ /* packing files descriptors */
+ if (nr_desc > 0) {
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ desclen = cmsg->cmsg_len =
+ CMSG_LEN(sizeof(int) * nr_desc);
+ memcpy((int *)CMSG_DATA(cmsg), desc,
+ sizeof(int) * nr_desc);
+ cmsg = CMSG_NXTHDR(&msg, cmsg);
+ _D("packing file descriptors done");
+ }
+
+ /* finished packing updating the corect length */
+ msg.msg_controllen = desclen;
+ } else {
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ }
+
+ sndret = sendmsg(sock, &msg, 0);
+ _D("sendmsg ret : %d", sndret);
+ if (sndret < 0)
+ return -errno;
+
+ return sndret;
+}
+
+static int __get_caller_pid(bundle *kb)
+{
+ const char *pid_str;
+ int pid;
+
+ pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
+ if (pid_str)
+ goto end;
+
+ pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
+ if (pid_str == NULL)
+ return -1;
+
+end:
+ pid = atoi(pid_str);
+ if (pid <= 1)
+ return -1;
+
+ return pid;
+}
+
+static int __app_process_by_pid(request_h req, const char *pid_str,
+ bool *pending)
+{
+ int pid;
+ int ret;
+ int dummy;
+ const char *appid;
+ const char *pkgid;
+ const char *type;
+ const struct appinfo *ai;
+ uid_t target_uid = _request_get_target_uid(req);
+ app_status_h app_status;
+
+ if (pid_str == NULL)
+ return -1;
+
+ pid = atoi(pid_str);
+ if (pid <= 1) {
+ _E("invalid pid");
+ return -1;
+ }
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ _E("pid %d is not an application", pid);
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ appid = _app_status_get_appid(app_status);
+ ai = _appinfo_find(target_uid, appid);
+ if (ai == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ type = _appinfo_get_value(ai, AIT_COMPTYPE);
+
+ switch (req->cmd) {
+ case APP_RESUME_BY_PID:
+ case APP_RESUME_BY_PID_ASYNC:
+ case APP_PAUSE_BY_PID:
+ aul_send_app_resume_request_signal(pid, appid, pkgid, type);
+ break;
+ default:
+ aul_send_app_terminate_request_signal(pid, appid, pkgid, type);
+ break;
+ }
+
+ switch (req->cmd) {
+ case APP_RESUME_BY_PID_ASYNC:
+ _request_send_result(req, 0);
+ case APP_RESUME_BY_PID:
+ ret = _resume_app(pid, req);
+ break;
+ case APP_TERM_BY_PID:
+ case APP_TERM_BY_PID_WITHOUT_RESTART:
+ ret = _term_app(pid, req);
+ break;
+ case APP_TERM_BGAPP_BY_PID:
+ ret = _term_bgapp(pid, req);
+ break;
+ case APP_KILL_BY_PID:
+ ret = _send_to_sigkill(pid);
+ if (ret < 0)
+ _E("fail to killing - %d\n", pid);
+ _app_status_update_status(app_status, STATUS_DYING, false, true);
+ _request_send_result(req, ret);
+ break;
+ case APP_TERM_REQ_BY_PID:
+ ret = _term_req_app(pid, req);
+ break;
+ case APP_TERM_BY_PID_ASYNC:
+ ret = aul_sock_send_raw(pid, target_uid, req->cmd,
+ (unsigned char *)&dummy, sizeof(int),
+ AUL_SOCK_NOREPLY);
+ if (ret < 0)
+ _D("terminate req packet send error");
+
+ _request_send_result(req, ret);
+ break;
+ case APP_PAUSE_BY_PID:
+ ret = _pause_app(pid, req);
+ break;
+ case APP_TERM_BY_PID_SYNC:
+ case APP_TERM_BY_PID_SYNC_WITHOUT_RESTART:
+ if (_app_status_get_status(app_status) == STATUS_DYING) {
+ _W("%d is dying", pid);
+ if (pending)
+ *pending = true;
+ ret = 0;
+ break;
+ }
+ ret = _term_app_v2(pid, req, pending);
+ break;
+ default:
+ _E("unknown command: %d", req->cmd);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static void __set_effective_appid(uid_t uid, bundle *kb)
+{
+ const struct appinfo *ai;
+ const struct appinfo *effective_ai;
+ const char *appid;
+ const char *effective_appid;
+ const char *pkgid;
+ const char *effective_pkgid;
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ if (appid == NULL)
+ return;
+
+ ai = _appinfo_find(uid, appid);
+ if (ai == NULL)
+ return;
+
+ bundle_del(kb, AUL_SVC_K_PKG_NAME);
+ bundle_add(kb, AUL_SVC_K_PKG_NAME, appid);
+
+ effective_appid = _appinfo_get_value(ai, AIT_EFFECTIVE_APPID);
+ if (effective_appid == NULL)
+ return;
+
+ effective_ai = _appinfo_find(uid, effective_appid);
+ if (effective_ai == NULL)
+ return;
+
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ effective_pkgid = _appinfo_get_value(effective_ai, AIT_PKGID);
+ if (pkgid && effective_pkgid && strcmp(pkgid, effective_pkgid) == 0) {
+ _D("use effective appid instead of the real appid");
+ bundle_del(kb, AUL_K_APPID);
+ bundle_add(kb, AUL_K_APPID, effective_appid);
+ }
+}
+
+static void __set_real_appid(uid_t uid, bundle *kb)
+{
+ const char *alias_appid;
+ const char *appid;
+ const char *alias_info;
+ app_property_h app_property;
+
+ alias_appid = bundle_get_val(kb, AUL_K_APPID);
+ if (alias_appid == NULL)
+ return;
+
+ alias_info = bundle_get_val(kb, AUL_SVC_K_ALIAS_INFO);
+ if (alias_info && strcmp(alias_info, "disable") == 0)
+ return;
+
+ app_property = _app_property_find(uid);
+ if (app_property == NULL)
+ return;
+
+ appid = _app_property_get_real_appid(app_property, alias_appid);
+ if (appid == NULL)
+ return;
+
+ _D("alias_appid(%s), appid(%s)", alias_appid, appid);
+ bundle_del(kb, AUL_K_ORG_APPID);
+ bundle_add(kb, AUL_K_ORG_APPID, alias_appid);
+ bundle_del(kb, AUL_K_APPID);
+ bundle_add(kb, AUL_K_APPID, appid);
+}
+
+static void __free_rua_stat_pkt(rua_stat_pkt_t *pkt)
+{
+ if (pkt == NULL)
+ return;
+
+ if (pkt->data)
+ free(pkt->data);
+ if (pkt->uri)
+ free(pkt->uri);
+ if (pkt->icon)
+ free(pkt->icon);
+ if (pkt->instance_name)
+ free(pkt->instance_name);
+ if (pkt->instance_id)
+ free(pkt->instance_id);
+ if (pkt->appid)
+ free(pkt->appid);
+ if (pkt->stat_caller)
+ free(pkt->stat_caller);
+ if (pkt->stat_tag)
+ free(pkt->stat_tag);
+
+ free(pkt);
+}
+
+static gboolean __add_history_handler(gpointer user_data)
+{
+ struct rua_rec rec = { 0, };
+ int ret;
+ struct appinfo *ai;
+ rua_stat_pkt_t *pkt = (rua_stat_pkt_t *)user_data;
+
+ if (!pkt)
+ return FALSE;
+
+ if (!pkt->is_group_app) {
+ ai = _appinfo_find(pkt->uid, pkt->appid);
+
+ rec.pkg_name = pkt->appid;
+ rec.app_path = (char *)_appinfo_get_value(ai, AIT_EXEC);
+
+ if (pkt->len > 0)
+ rec.arg = pkt->data;
+
+ rec.launch_time = time(NULL);
+ rec.instance_id = pkt->instance_id;
+ rec.instance_name = pkt->instance_name;
+ rec.icon = pkt->icon;
+ rec.uri = pkt->uri;
+ rec.image = (char *)_rua_get_image_path(pkt->pid);
+
+ SECURE_LOGD("add rua history %s %s",
+ rec.pkg_name, rec.app_path);
+ ret = rua_usr_db_add_history(&rec, pkt->uid);
+ if (ret == -1)
+ _D("rua add history error");
+ }
+
+ if (pkt->stat_caller != NULL && pkt->stat_tag != NULL) {
+ SECURE_LOGD("rua_stat_caller: %s, rua_stat_tag: %s",
+ pkt->stat_caller, pkt->stat_tag);
+ rua_stat_usr_db_update(pkt->stat_caller, pkt->stat_tag,
+ pkt->uid);
+ }
+
+ __free_rua_stat_pkt(pkt);
+
+ return FALSE;
+}
+
+static rua_stat_pkt_t *__create_rua_stat_pkt(request_h req, bundle *kb,
+ const char *appid, struct instance_info *info, int pid)
+{
+ const char *stat_caller;
+ const char *stat_tag;
+ rua_stat_pkt_t *rua_stat_item;
+
+ rua_stat_item = calloc(1, sizeof(rua_stat_pkt_t));
+ if (rua_stat_item == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ rua_stat_item->pid = pid;
+
+ if (req->len > 0) {
+ rua_stat_item->data = calloc(req->len + 1, sizeof(char));
+ if (rua_stat_item->data == NULL) {
+ _E("out of memory");
+ __free_rua_stat_pkt(rua_stat_item);
+ return NULL;
+ }
+ memcpy(rua_stat_item->data, req->data, req->len);
+ }
+ rua_stat_item->len = req->len;
+
+ stat_caller = bundle_get_val(kb, AUL_SVC_K_RUA_STAT_CALLER);
+ if (stat_caller != NULL) {
+ rua_stat_item->stat_caller = strdup(stat_caller);
+ if (rua_stat_item->stat_caller == NULL) {
+ _E("Out of memory");
+ __free_rua_stat_pkt(rua_stat_item);
+ return NULL;
+ }
+ }
+
+ stat_tag = bundle_get_val(kb, AUL_SVC_K_RUA_STAT_TAG);
+ if (stat_tag != NULL) {
+ rua_stat_item->stat_tag = strdup(stat_tag);
+ if (rua_stat_item->stat_tag == NULL) {
+ _E("Out of memory");
+ __free_rua_stat_pkt(rua_stat_item);
+ return NULL;
+ }
+
+ }
+
+ if (appid) {
+ rua_stat_item->appid = strdup(appid);
+ if (rua_stat_item->appid == NULL) {
+ _E("Out of memory");
+ __free_rua_stat_pkt(rua_stat_item);
+ return NULL;
+ }
+ }
+
+ if (info->id) {
+ rua_stat_item->instance_id = strdup(info->id);
+ if (rua_stat_item->instance_id == NULL) {
+ _E("Out of memory");
+ __free_rua_stat_pkt(rua_stat_item);
+ return NULL;
+ }
+ }
+
+ if (info->name) {
+ rua_stat_item->instance_name = strdup(info->name);
+ if (rua_stat_item->instance_name == NULL) {
+ _E("Out of memory");
+ __free_rua_stat_pkt(rua_stat_item);
+ return NULL;
+ }
+ }
+
+ if (info->icon) {
+ rua_stat_item->icon = strdup(info->icon);
+ if (rua_stat_item->icon == NULL) {
+ _E("Out of memory");
+ __free_rua_stat_pkt(rua_stat_item);
+ return NULL;
+ }
+ }
+
+ if (info->uri) {
+ rua_stat_item->uri = strdup(info->uri);
+ if (rua_stat_item->uri == NULL) {
+ _E("Out of memory");
+ __free_rua_stat_pkt(rua_stat_item);
+ return NULL;
+ }
+ }
+
+ rua_stat_item->uid = _request_get_target_uid(req);
+ rua_stat_item->is_group_app = _app_group_is_group_app(kb,
+ rua_stat_item->uid);
+
+ return rua_stat_item;
+}
+
+static int __dispatch_get_mp_socket_pair(request_h req)
+{
+ int handles[2] = {0, 0};
+ struct iovec vec[3];
+ int msglen = 0;
+ char buffer[1024];
+ int ret;
+ struct timeval read_timeout;
+ struct timeval write_timeout;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) {
+ _E("error create socket pair");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ if (handles[0] == -1) {
+ _E("error socket open");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ read_timeout.tv_sec = 5;
+ read_timeout.tv_usec = 0;
+ write_timeout.tv_sec = 25; /*dbus default timeout */
+ write_timeout.tv_usec = 0;
+
+ ret = setsockopt(handles[0], SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof(read_timeout));
+ if (ret < 0) {
+ _E("Cannot Set SO_RCVTIMEO for socket %d", handles[0]);
+ _request_send_result(req, -1);
+ goto out;
+ }
+
+ ret = setsockopt(handles[0], SOL_SOCKET, SO_SNDTIMEO, &write_timeout, sizeof(write_timeout));
+ if (ret < 0) {
+ _E("Cannot Set SO_SNDTIMEO for socket %d", handles[0]);
+ _request_send_result(req, -1);
+ goto out;
+ }
+
+ ret = setsockopt(handles[1], SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof(read_timeout));
+ if (ret < 0) {
+ _E("Cannot Set SO_RCVTIMEO for socket %d", handles[1]);
+ _request_send_result(req, -1);
+ goto out;
+ }
+
+ ret = setsockopt(handles[1], SOL_SOCKET, SO_SNDTIMEO, &write_timeout, sizeof(write_timeout));
+ if (ret < 0) {
+ _E("Cannot Set SO_SNDTIMEO for socket %d", handles[1]);
+ _request_send_result(req, -1);
+ goto out;
+ }
+
+ _D("amd send mp fd : [%d, %d]", handles[0], handles[1]);
+ vec[0].iov_base = buffer;
+ vec[0].iov_len = strlen(buffer) + 1;
+
+ msglen = __send_message(req->clifd, vec, 1, handles, 2);
+ if (msglen < 0) {
+ _E("Error[%d]: while sending message\n", -msglen);
+ _request_send_result(req, -1);
+ ret = -1;
+ }
+out:
+ close(handles[0]);
+ close(handles[1]);
+
+ return ret;
+}
+
+static int __dispatch_get_dc_socket_pair(request_h req)
+{
+ const char *caller;
+ const char *callee;
+ const char *datacontrol_type;
+ char *socket_pair_key = NULL;
+ int socket_pair_key_len;
+ int *handles = NULL;
+ struct iovec vec[3];
+ int msglen = 0;
+ char buffer[1024];
+ bundle *kb = req->kb;
+ struct timeval tv;
+ int ret;
+
+ caller = bundle_get_val(kb, AUL_K_CALLER_APPID);
+ if (caller == NULL)
+ goto err_out;
+ callee = bundle_get_val(kb, AUL_K_CALLEE_APPID);
+ if (callee == NULL)
+ goto err_out;
+ datacontrol_type = bundle_get_val(kb, "DATA_CONTOL_TYPE");
+
+ socket_pair_key_len = strlen(caller) + strlen(callee) + 2;
+
+ socket_pair_key = (char *)calloc(socket_pair_key_len, sizeof(char));
+ if (socket_pair_key == NULL) {
+ _E("calloc fail");
+ goto err_out;
+ }
+
+ snprintf(socket_pair_key, socket_pair_key_len, "%s_%s", caller, callee);
+ _D("socket pair key : %s", socket_pair_key);
+
+ handles = g_hash_table_lookup(__dc_socket_pair_hash, socket_pair_key);
+ if (handles == NULL) {
+ handles = (int *)calloc(2, sizeof(int));
+ if (handles == NULL) {
+ _E("calloc fail");
+ goto err_out;
+ }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) {
+ _E("error create socket pair");
+ _request_send_result(req, -1);
+ free(handles);
+ handles = NULL;
+ goto err_out;
+ }
+
+ if (handles[0] == -1 || handles[1] == -1) {
+ _E("error socket open");
+ _request_send_result(req, -1);
+ free(handles);
+ handles = NULL;
+ goto err_out;
+ }
+
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ ret = setsockopt(handles[0], SOL_SOCKET, SO_RCVTIMEO, &tv,
+ sizeof(tv));
+ if (ret < 0) {
+ _E("Cannot Set SO_RCVTIMEO for socket %d", handles[0]);
+ _request_send_result(req, -1);
+ close(handles[0]);
+ close(handles[1]);
+ free(handles);
+ handles = NULL;
+ goto err_out;
+ }
+
+ ret = setsockopt(handles[1], SOL_SOCKET, SO_RCVTIMEO, &tv,
+ sizeof(tv));
+ if (ret < 0) {
+ _E("Cannot Set SO_RCVTIMEO for socket %d", handles[1]);
+ _request_send_result(req, -1);
+ close(handles[0]);
+ close(handles[1]);
+ free(handles);
+ handles = NULL;
+ goto err_out;
+ }
+
+ g_hash_table_insert(__dc_socket_pair_hash,
+ strdup(socket_pair_key), handles);
+ _D("New socket pair insert done.");
+ }
+
+ SECURE_LOGD("amd send fd : [%d, %d]", handles[0], handles[1]);
+ vec[0].iov_base = buffer;
+ vec[0].iov_len = 1;
+
+ if (datacontrol_type != NULL) {
+ _D("datacontrol_type : %s", datacontrol_type);
+ if (strcmp(datacontrol_type, "consumer") == 0) {
+ msglen = __send_message(req->clifd, vec, 1,
+ &handles[0], 1);
+ if (msglen < 0) {
+ _E("Error[%d]: while sending message", -msglen);
+ _request_send_result(req, -1);
+ goto err_out;
+ }
+ close(handles[0]);
+ handles[0] = -1;
+ if (handles[1] == -1) {
+ _E("remove from hash : %s", socket_pair_key);
+ g_hash_table_remove(__dc_socket_pair_hash,
+ socket_pair_key);
+ }
+
+ } else {
+ msglen = __send_message(req->clifd, vec, 1,
+ &handles[1], 1);
+ if (msglen < 0) {
+ _E("Error[%d]: while sending message", -msglen);
+ _request_send_result(req, -1);
+ goto err_out;
+ }
+ close(handles[1]);
+ handles[1] = -1;
+ if (handles[0] == -1) {
+ _E("remove from hash : %s", socket_pair_key);
+ g_hash_table_remove(__dc_socket_pair_hash,
+ socket_pair_key);
+ }
+ }
+ }
+ SECURE_LOGD("send_message msglen : [%d]\n", msglen);
+ if (socket_pair_key)
+ free(socket_pair_key);
+
+ return 0;
+
+err_out:
+ if (socket_pair_key) {
+ g_hash_table_remove(__dc_socket_pair_hash, socket_pair_key);
+ free(socket_pair_key);
+ }
+
+ return -1;
+}
+
+static int __dispatch_update_rua_stat(request_h req)
+{
+ int result;
+ char *caller = NULL;
+ char *tag = NULL;
+ uid_t uid = _request_get_target_uid(req);
+
+ bundle_get_str(req->kb, AUL_SVC_K_RUA_STAT_CALLER, &caller);
+ bundle_get_str(req->kb, AUL_SVC_K_RUA_STAT_TAG, &tag);
+ result = rua_stat_usr_db_update(caller, tag, uid);
+ _D("rua_stat_usr_db_update - uid(%d), result(%d)", uid, result);
+ _request_send_result(req, result);
+
+ return 0;
+}
+
+static int __dispatch_add_history(request_h req)
+{
+ int result;
+ struct rua_rec rec = {0,};
+ char *time_str;
+ uid_t uid = _request_get_target_uid(req);
+ bundle *b = _request_get_bundle(req);
+
+ bundle_get_str(b, AUL_K_RUA_PKGNAME, &rec.pkg_name);
+ bundle_get_str(b, AUL_K_RUA_APPPATH, &rec.app_path);
+ bundle_get_str(b, AUL_K_RUA_ARG, &rec.arg);
+ bundle_get_str(b, AUL_K_RUA_TIME, &time_str);
+ if (time_str != NULL)
+ rec.launch_time = atoi(time_str);
+ else
+ rec.launch_time = (int)time(NULL);
+ bundle_get_str(b, AUL_K_RUA_INSTANCE_ID, &rec.instance_id);
+ bundle_get_str(b, AUL_K_RUA_INSTANCE_NAME, &rec.instance_name);
+ bundle_get_str(b, AUL_K_RUA_ICON, &rec.icon);
+ bundle_get_str(b, AUL_K_RUA_URI, &rec.uri);
+
+ result = rua_usr_db_add_history(&rec, uid);
+ _D("rua_usr_db_add_history - uid(%d), result(%d)", uid, result);
+ _request_send_result(req, result);
+
+ return 0;
+}
+
+static int __dispatch_remove_history(request_h req)
+{
+ int result;
+ bundle *b = _request_get_bundle(req);
+ uid_t uid = _request_get_target_uid(req);
+
+ result = rua_usr_db_delete_history(b, uid);
+ _D("rua_usr_db_delete_history - uid(%d), result(%d)", uid, result);
+ _request_send_result(req, result);
+
+ _rua_delete_info(b, uid);
+
+ return 0;
+}
+
+static int __dispatch_app_group_get_window(request_h req)
+{
+ char *buf;
+ int pid;
+ int wid;
+
+ bundle_get_str(req->kb, AUL_K_PID, &buf);
+ pid = atoi(buf);
+ wid = _app_group_get_window(pid);
+ _request_send_result(req, wid);
+
+ return 0;
+}
+
+static int __dispatch_app_group_set_window(request_h req)
+{
+ char *buf;
+ int pid = _request_get_pid(req);
+ uid_t uid = _request_get_target_uid(req);
+ int wid;
+ int ret;
+
+ bundle_get_str(req->kb, AUL_K_WID, &buf);
+ wid = atoi(buf);
+ ret = _app_group_set_window(pid, wid);
+ _request_send_result(req, ret);
+ _D("pid(%d), wid(%d)", pid, wid);
+ _screen_connector_add_app_screen(pid, wid, NULL, uid);
+
+ return ret;
+}
+
+static int __dispatch_app_group_get_fg_flag(request_h req)
+{
+ char *buf;
+ int pid;
+ int fg;
+
+ bundle_get_str(req->kb, AUL_K_PID, &buf);
+ pid = atoi(buf);
+ fg = _app_group_get_fg_flag(pid);
+ _request_send_result(req, fg);
+
+ return 0;
+}
+
+static int __dispatch_app_group_clear_top(request_h req)
+{
+ int pid = _request_get_pid(req);
+ uid_t uid = _request_get_target_uid(req);
+
+ _app_group_clear_top(pid, uid);
+ _request_send_result(req, 0);
+
+ return 0;
+}
+
+static int __dispatch_app_group_get_leader_pid(request_h req)
+{
+ char *buf;
+ int pid;
+ int lpid;
+
+ bundle_get_str(req->kb, AUL_K_PID, &buf);
+ pid = atoi(buf);
+ lpid = _app_group_get_leader_pid(pid);
+ _request_send_result(req, lpid);
+
+ return 0;
+}
+
+static int __dispatch_app_group_get_leader_pids(request_h req)
+{
+ int cnt;
+ int *pids;
+ unsigned char empty[1] = {0,};
+
+ _app_group_get_leader_pids(&cnt, &pids);
+
+ if (pids == NULL || cnt == 0) {
+ _request_send_raw(req, APP_GROUP_GET_LEADER_PIDS, empty, 0);
+ } else {
+ _request_send_raw(req, APP_GROUP_GET_LEADER_PIDS,
+ (unsigned char *)pids, cnt * sizeof(int));
+ }
+
+ if (pids != NULL)
+ free(pids);
+
+ return 0;
+}
+
+static int __dispatch_app_group_get_idle_pids(request_h req)
+{
+ int cnt;
+ int *pids;
+ unsigned char empty[1] = {0,};
+
+ _app_group_get_idle_pids(&cnt, &pids);
+ if (pids == NULL || cnt == 0) {
+ _request_send_raw(req, APP_GROUP_GET_IDLE_PIDS, empty, 0);
+ } else {
+ _request_send_raw(req, APP_GROUP_GET_IDLE_PIDS,
+ (unsigned char *)pids, cnt * sizeof(int));
+ }
+
+ if (pids != NULL)
+ free(pids);
+
+ return 0;
+}
+
+static int __dispatch_app_group_get_group_pids(request_h req)
+{
+ char *buf;
+ int leader_pid;
+ int cnt;
+ int *pids;
+ unsigned char empty[1] = { 0 };
+
+ bundle_get_str(req->kb, AUL_K_LEADER_PID, &buf);
+ leader_pid = atoi(buf);
+
+ _app_group_get_group_pids(leader_pid, &cnt, &pids);
+ if (pids == NULL || cnt == 0) {
+ _request_send_raw(req, APP_GROUP_GET_GROUP_PIDS, empty, 0);
+ } else {
+ _request_send_raw(req, APP_GROUP_GET_GROUP_PIDS,
+ (unsigned char *)pids, cnt * sizeof(int));
+ }
+
+ if (pids != NULL)
+ free(pids);
+
+ return 0;
+}
+
+static int __dispatch_app_group_lower(request_h req)
+{
+ int ret = 0;
+
+ _app_group_lower(req->pid, &ret);
+ _request_send_result(req, ret);
+
+ return ret;
+}
+
+static int __dispatch_app_group_activate_below(request_h req)
+{
+ char *buf = NULL;
+ int ret;
+
+ bundle_get_str(req->kb, AUL_K_APPID, &buf);
+ ret = _app_group_activate_below(req->pid, buf);
+ _request_send_result(req, ret);
+
+ return 0;
+}
+
+static int __dispatch_app_group_activate_above(request_h req)
+{
+ char *buf = NULL;
+ int ret;
+
+ bundle_get_str(req->kb, AUL_K_APPID, &buf);
+ ret = _app_group_activate_above(req->pid, buf);
+ _request_send_result(req, ret);
+
+ return 0;
+}
+
+static guint __get_pending_interval(GTimeVal *start, GTimeVal *end)
+{
+ guint sec;
+ guint usec;
+ guint interval;
+
+ sec = (end->tv_sec - start->tv_sec) * 1000;
+ usec = (end->tv_usec - start->tv_usec) / 1000;
+ interval = sec + usec;
+ if (interval >= PENDING_REQUEST_TIMEOUT)
+ return 0;
+
+ return PENDING_REQUEST_TIMEOUT - interval;
+}
+
+static char *__get_value_from_query(const char *src, const char *key)
+{
+ int src_len = strlen(src);
+ int key_len = strlen(key);
+
+ if (src_len > key_len) {
+ if (strncmp(src, key, key_len) == 0)
+ return g_uri_unescape_string(src + key_len, NULL);
+ }
+
+ return NULL;
+}
+
+static void __free_instance_info(struct instance_info *info)
+{
+ if (info->uri) {
+ free(info->uri);
+ info->uri = NULL;
+ }
+
+ if (info->id) {
+ free(info->id);
+ info->id = NULL;
+ }
+
+ if (info->icon) {
+ free(info->icon);
+ info->icon = NULL;
+ }
+
+ if (info->name) {
+ free(info->name);
+ info->name = NULL;
+ }
+}
+
+static int __get_instance_info(bundle *kb, struct instance_info *info)
+{
+ const char *uri;
+ gchar *scheme;
+ gchar *query;
+ char *token;
+ char *dup_uri;
+
+ uri = bundle_get_val(kb, AUL_SVC_K_URI);
+ if (uri == NULL)
+ return -1;
+
+ scheme = g_uri_parse_scheme(uri);
+ if (scheme == NULL)
+ return -1;
+
+ if (strcmp(scheme, MULTI_INSTANCE_SHORTCUT) != 0) {
+ g_free(scheme);
+ return -1;
+ }
+ g_free(scheme);
+
+ dup_uri = strdup(uri);
+ if (dup_uri == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ info->uri = strdup(uri);
+ if (info->uri == NULL) {
+ _E("Out of memory");
+ free(dup_uri);
+ return -1;
+ }
+
+ query = index(dup_uri, '?');
+ if (query == NULL || query + 1 == NULL) {
+ __free_instance_info(info);
+ free(dup_uri);
+ return -1;
+ }
+
+ token = strtok(query + 1, "&");
+ while (token != NULL) {
+ if (info->id == NULL)
+ info->id = __get_value_from_query(token, QUERY_KEY_ID);
+ if (info->icon == NULL) {
+ info->icon = __get_value_from_query(token,
+ QUERY_KEY_ICON);
+ }
+ if (info->name == NULL) {
+ info->name = __get_value_from_query(token,
+ QUERY_KEY_NAME);
+ }
+
+ token = strtok(NULL, "&");
+ }
+ free(dup_uri);
+
+ if (info->id == NULL || info->icon == NULL || info->name == NULL) {
+ _W("Failed to get instance info");
+ __free_instance_info(info);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __dispatch_app_start(request_h req)
+{
+ const char *appid;
+ const char *instance_id;
+ int ret;
+ bundle *kb;
+ bool pending = false;
+ struct pending_item *item;
+ GTimeVal end;
+ guint interval;
+ bool bg_launch = false;
+ bool new_instance = false;
+ struct instance_info info = {0,};
+ struct reply_info *reply;
+ int clifd;
+ rua_stat_pkt_t *rua = NULL;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ __set_real_appid(_request_get_target_uid(req), kb);
+ __set_effective_appid(_request_get_target_uid(req), kb);
+ if (__get_instance_info(kb, &info) == 0) {
+ bundle_del(kb, AUL_K_INSTANCE_ID);
+ bundle_add(kb, AUL_K_INSTANCE_ID, info.id);
+ new_instance = true;
+ _D("Multiple instance launch - id(%s), name(%s), icon(%s)",
+ info.id, info.name, info.icon);
+ } else {
+ instance_id = bundle_get_val(kb, AUL_K_INSTANCE_ID);
+ if (instance_id) {
+ info.id = strdup(instance_id);
+ _D("Multiple instance launch - id(%s)", info.id);
+ }
+ }
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ ret = _launch_start_app(appid, req, &pending, &bg_launch, new_instance);
+#ifdef TIZEN_FEATURE_BLOCK_INPUT
+ if (ret <= 0)
+ _input_unlock();
+#endif /* TIZEN_FEATURE_BLOCK_INPUT */
+
+ /* add pending list to wait app launched successfully */
+ if (pending) {
+ item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(ret));
+ if (item == NULL) {
+ item = calloc(1, sizeof(struct pending_item));
+ if (item == NULL) {
+ _E("Out of memory");
+ _request_send_result(req, ret);
+ __free_instance_info(&info);
+ return -1;
+ }
+ item->pid = ret;
+ g_hash_table_insert(pending_table, GINT_TO_POINTER(ret),
+ item);
+ } else {
+ if (item->timer) {
+ g_source_remove(item->timer);
+ item->timer = 0;
+ }
+ }
+
+ if (!bg_launch) {
+ rua = __create_rua_stat_pkt(req, kb, appid, &info, ret);
+ if (rua && !rua->is_group_app)
+ _rua_add_info(ret, new_instance);
+ }
+
+ clifd = _request_remove_fd(req);
+ g_get_current_time(&end);
+ interval = __get_pending_interval(&req->start, &end);
+ reply = __create_reply_info(interval, ret, ret,
+ req->cmd, clifd, rua);
+ if (reply == NULL) {
+ _send_result_to_client(clifd, ret);
+ __free_instance_info(&info);
+ return -1;
+ }
+
+ item->reply_list = g_list_append(item->reply_list, reply);
+ __free_instance_info(&info);
+ return 0;
+ }
+
+ if (ret > 0 && !bg_launch) {
+ rua = __create_rua_stat_pkt(req, kb, appid, &info, ret);
+ if (rua == NULL) {
+ __free_instance_info(&info);
+ return -1;
+ }
+ g_timeout_add(1500, __add_history_handler, rua);
+ }
+ __free_instance_info(&info);
+
+ return 0;
+}
+
+static int __get_caller_uid(bundle *kb, uid_t *uid)
+{
+ const char *val;
+
+ val = bundle_get_val(kb, AUL_K_ORG_CALLER_UID);
+ if (val == NULL)
+ val = bundle_get_val(kb, AUL_K_CALLER_UID);
+
+ if (val == NULL) {
+ _E("Failed to get caller uid");
+ return -1;
+ }
+
+ *uid = atol(val);
+ _D("caller uid(%d)", *uid);
+
+ return 0;
+}
+
+static void __set_instance_id(bundle *kb)
+{
+ app_status_h app_status;
+ const char *instance_id;
+ const char *callee_pid;
+ int pid;
+
+ callee_pid = bundle_get_val(kb, AUL_K_FWD_CALLEE_PID);
+ if (callee_pid == NULL)
+ callee_pid = bundle_get_val(kb, AUL_K_CALLEE_PID);
+
+ if (callee_pid == NULL) {
+ _E("Failed to get callee pid");
+ return;
+ }
+
+ pid = atoi(callee_pid);
+ if (pid <= 0)
+ return;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return;
+
+ instance_id = _app_status_get_instance_id(app_status);
+ if (instance_id == NULL)
+ return;
+
+ bundle_del(kb, AUL_K_INSTANCE_ID);
+ bundle_add(kb, AUL_K_INSTANCE_ID, instance_id);
+ _D("instance_id(%s)", instance_id);
+}
+
+static int __dispatch_app_result(request_h req)
+{
+ bundle *kb;
+ int pid;
+ int pgid;
+ char tmp_pid[MAX_PID_STR_BUFSZ];
+ int res;
+ shared_info_h si = NULL;
+ const char *appid;
+ int ret;
+ uid_t target_uid = _request_get_target_uid(req);
+ app_status_h app_status;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ pid = __get_caller_pid(kb);
+ if (pid < 0)
+ return AUL_R_ERROR;
+
+ pgid = getpgid(req->pid);
+ if (pgid > 0) {
+ snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", pgid);
+ bundle_del(kb, AUL_K_CALLEE_PID);
+ bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
+ }
+
+ if (__get_caller_uid(kb, &target_uid) < 0)
+ return AUL_R_ERROR;
+
+ __set_instance_id(kb);
+ app_status = _app_status_find(getpgid(pid));
+ appid = _app_status_get_appid(app_status);
+ if (appid) {
+ si = _temporary_permission_create(pgid, appid, kb, target_uid);
+ if (si == NULL)
+ _D("No sharable path : %d %s", pgid, appid);
+ }
+
+ res = aul_sock_send_bundle(pid, target_uid, req->cmd, kb,
+ AUL_SOCK_NOREPLY);
+ if (res < 0)
+ res = AUL_R_ERROR;
+
+ if (si) {
+ if (res >= 0) {
+ ret = _temporary_permission_apply(pid, target_uid, si);
+ if (ret != 0) {
+ _D("Couldn't apply temporary permission: %d",
+ ret);
+ }
+ }
+ _temporary_permission_destroy(si);
+ }
+
+ return 0;
+}
+
+static int __dispatch_app_pause(request_h req)
+{
+ const char *appid;
+ bundle *kb;
+ int ret;
+ app_status_h app_status;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ app_status = _app_status_find_by_appid(appid,
+ _request_get_target_uid(req));
+ ret = _app_status_get_pid(app_status);
+ if (ret > 0)
+ ret = _pause_app(ret, req);
+ else
+ _E("%s is not running", appid);
+
+ return 0;
+}
+
+static int __dispatch_app_process_by_pid(request_h req)
+{
+ const char *appid;
+ bundle *kb;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ __app_process_by_pid(req, appid, NULL);
+
+ return 0;
+}
+
+static int __dispatch_app_term_async(request_h req)
+{
+ const char *appid;
+ bundle *kb;
+ const char *term_pid;
+ struct appinfo *ai;
+ app_status_h app_status;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ term_pid = bundle_get_val(kb, AUL_K_APPID);
+ app_status = _app_status_find(atoi(term_pid));
+ appid = _app_status_get_appid(app_status);
+ ai = _appinfo_find(_request_get_target_uid(req), appid);
+ if (ai) {
+ _appinfo_set_value(ai, AIT_STATUS, "norestart");
+ __app_process_by_pid(req, term_pid, NULL);
+ }
+
+ return 0;
+}
+
+static int __dispatch_app_term(request_h req)
+{
+ const char *appid;
+ bundle *kb;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ __app_process_by_pid(req, appid, NULL);
+
+ return 0;
+}
+
+static int __dispatch_app_running_info(request_h req)
+{
+ int ret;
+
+ ret = _app_status_send_running_appinfo(_request_remove_fd(req),
+ req->cmd, _request_get_target_uid(req));
+ return ret;
+}
+
+static int __dispatch_app_all_running_info(request_h req)
+{
+ int ret;
+
+ ret = _app_status_send_running_appinfo(_request_remove_fd(req),
+ req->cmd, _request_get_target_uid(req));
+ return ret;
+}
+
+static int __dispatch_app_is_running(request_h req)
+{
+ const char *appid;
+ int ret;
+ app_status_h app_status;
+ bundle *b = _request_get_bundle(req);
+
+ if (b == NULL) {
+ _E("Failed to get bundle");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ appid = bundle_get_val(b, AUL_K_APPID);
+ if (appid == NULL) {
+ _E("Failed to get appid");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ app_status = _app_status_find_by_appid(appid,
+ _request_get_target_uid(req));
+ ret = _app_status_is_running(app_status);
+ SECURE_LOGD("APP_IS_RUNNING : %s : %d", appid, ret);
+ _request_send_result(req, ret);
+
+ return 0;
+}
+
+static int __dispatch_app_get_appid_by_pid(request_h req)
+{
+ int pid;
+ int ret;
+ const char *pid_str;
+ bundle *b = _request_get_bundle(req);
+
+ if (b == NULL) {
+ _E("Failed to get bundle");
+ aul_sock_send_raw_with_fd(_request_remove_fd(req),
+ APP_GET_INFO_ERROR, NULL, 0, AUL_SOCK_NOREPLY);
+ return -1;
+ }
+
+ pid_str = bundle_get_val(b, AUL_K_PID);
+ if (pid_str == NULL || !isdigit(pid_str[0])) {
+ _E("Failed to get pid");
+ aul_sock_send_raw_with_fd(_request_remove_fd(req),
+ APP_GET_INFO_ERROR, NULL, 0, AUL_SOCK_NOREPLY);
+ return -1;
+ }
+
+ pid = atoi(pid_str);
+ ret = _app_status_get_appid_bypid(_request_remove_fd(req), pid);
+ _D("app_status_get_appid_bypid : %d : %d", pid, ret);
+
+ return 0;
+}
+
+static int __dispatch_app_get_pkgid_by_pid(request_h req)
+{
+ int pid;
+ int ret;
+ const char *pid_str;
+ bundle *b = _request_get_bundle(req);
+
+ if (b == NULL) {
+ _E("Failed to get bundle");
+ aul_sock_send_raw_with_fd(_request_remove_fd(req),
+ APP_GET_INFO_ERROR, NULL, 0, AUL_SOCK_NOREPLY);
+ return -1;
+ }
+
+ pid_str = bundle_get_val(b, AUL_K_PID);
+ if (pid_str == NULL || !isdigit(pid_str[0])) {
+ _E("Failed to get pid");
+ aul_sock_send_raw_with_fd(_request_remove_fd(req),
+ APP_GET_INFO_ERROR, NULL, 0, AUL_SOCK_NOREPLY);
+ return -1;
+ }
+
+ pid = atoi(pid_str);
+ ret = _app_status_get_pkgid_bypid(_request_remove_fd(req), pid);
+ _D("APP_GET_PKGID_BYPID : %d : %d", pid, ret);
+
+ return 0;
+}
+
+static int __dispatch_legacy_command(request_h req)
+{
+ _request_send_result(req, 0);
+ return 0;
+}
+
+static int __dispatch_app_status_update(request_h req)
+{
+ int *status;
+ const char *appid;
+ struct appinfo *ai;
+ app_status_h app_status;
+
+ app_status = _app_status_find(req->pid);
+ if (app_status == NULL)
+ return -1;
+
+ status = (int *)req->data;
+ switch (*status) {
+ case STATUS_NORESTART:
+ appid = _app_status_get_appid(app_status);
+ ai = _appinfo_find(_request_get_target_uid(req), appid);
+ _appinfo_set_value((struct appinfo *)ai, AIT_STATUS,
+ "norestart");
+ break;
+ case STATUS_VISIBLE:
+ case STATUS_BG:
+ break;
+ default:
+ _app_status_update_status(app_status, *status, false, true);
+ break;
+ }
+
+ return 0;
+}
+
+static int __dispatch_app_get_status(request_h req)
+{
+ int pid;
+ int status;
+ app_status_h app_status;
+ const char *pid_str;
+ bundle *b;
+
+ b = _request_get_bundle(req);
+ if (b == NULL) {
+ _E("Failed to get bundle");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ pid_str = bundle_get_val(b, AUL_K_PID);
+ if (pid_str == NULL || !isdigit(pid_str[0])) {
+ _E("Falied to get pid");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ pid = atoi(pid_str);
+ app_status = _app_status_find(pid);
+ status = _app_status_get_status(app_status);
+ _request_send_result(req, status);
+
+ return 0;
+}
+
+static int __dispatch_app_add_loader(request_h req)
+{
+ bundle *kb;
+ int ret;
+ char tmpbuf[MAX_PID_STR_BUFSZ];
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ snprintf(tmpbuf, sizeof(tmpbuf), "%d", getpgid(req->pid));
+ bundle_add(kb, AUL_K_CALLER_PID, tmpbuf);
+ ret = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK,
+ _request_get_target_uid(req), PAD_CMD_ADD_LOADER, kb);
+ _request_send_result(req, ret);
+
+ return ret;
+}
+
+static int __dispatch_app_remove_loader(request_h req)
+{
+ bundle *kb;
+ int ret;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ ret = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK,
+ _request_get_target_uid(req), PAD_CMD_REMOVE_LOADER,
+ kb);
+ _request_send_result(req, ret);
+
+ return ret;
+}
+
+static int __dispatch_launchpad_dead_signal(request_h req)
+{
+ uid_t target_uid = _request_get_target_uid(req);
+
+ _D("uid(%d)", target_uid);
+ _login_monitor_set_uid_state(target_uid, UID_STATE_CLOSING);
+ close(_request_remove_fd(req));
+
+ return 0;
+}
+
+static int __dispatch_amd_reload_appinfo(request_h req)
+{
+ _D("AMD_RELOAD_APPINFO");
+ _appinfo_reload();
+ _request_send_result(req, 0);
+
+ return 0;
+}
+
+static int __dispatch_app_com_create(request_h req)
+{
+ bundle *kb;
+ int ret;
+ size_t propagate_size;
+ unsigned int propagate = 0;
+ const char *privilege;
+ const char *endpoint;
+ unsigned int *prop;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ endpoint = bundle_get_val(kb, AUL_K_COM_ENDPOINT);
+ if (endpoint == NULL) {
+ _request_send_result(req, AUL_APP_COM_R_ERROR_FATAL_ERROR);
+ return 0;
+ }
+
+ privilege = bundle_get_val(kb, AUL_K_COM_PRIVILEGE);
+ if (!privilege) {
+ /* privilege is not mandatory so far */
+ _D("non-privileged endpoint: %s", endpoint);
+ }
+
+ ret = bundle_get_byte(kb, AUL_K_COM_PROPAGATE, (void **)&prop,
+ &propagate_size);
+ if (ret == 0)
+ propagate = *prop;
+
+ _D("endpoint: %s propagate: %x privilege: %s",
+ endpoint, propagate, privilege);
+
+ ret = _app_com_add_endpoint(endpoint, propagate, privilege);
+ if (ret == AUL_APP_COM_R_ERROR_OK ||
+ ret == AUL_APP_COM_R_ERROR_ENDPOINT_ALREADY_EXISTS) {
+ ret = _app_com_join(endpoint, getpgid(req->pid), NULL,
+ _request_get_uid(req));
+ if (ret == AUL_APP_COM_R_ERROR_ILLEGAL_ACCESS) {
+ _E("illegal access: remove endpoint");
+ _app_com_remove_endpoint(endpoint);
+ }
+ }
+
+ _request_send_result(req, ret);
+ return 0;
+}
+
+static int __dispatch_app_com_join(request_h req)
+{
+ bundle *kb;
+ int ret;
+ const char *endpoint;
+ const char *filter;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ endpoint = bundle_get_val(kb, AUL_K_COM_ENDPOINT);
+ if (endpoint == NULL) {
+ bundle_free(kb);
+ _request_send_result(req, AUL_APP_COM_R_ERROR_FATAL_ERROR);
+ return 0;
+ }
+
+ filter = bundle_get_val(kb, AUL_K_COM_FILTER);
+
+ ret = _app_com_join(endpoint, getpgid(req->pid), filter,
+ _request_get_uid(req));
+
+ _request_send_result(req, ret);
+
+ return 0;
+}
+
+static int __dispatch_app_com_send(request_h req)
+{
+ bundle *kb;
+ int ret;
+ const char *endpoint;
+ int sender_pid = _request_get_pid(req);
+ char sender_pid_str[MAX_PID_STR_BUFSZ];
+ uid_t sender_uid = _request_get_uid(req);
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ snprintf(sender_pid_str, MAX_PID_STR_BUFSZ, "%d", sender_pid);
+ bundle_del(kb, AUL_K_COM_SENDER_PID);
+ bundle_add(kb, AUL_K_COM_SENDER_PID, sender_pid_str);
+ endpoint = bundle_get_val(kb, AUL_K_COM_ENDPOINT);
+ if (endpoint == NULL) {
+ _request_send_result(req, AUL_APP_COM_R_ERROR_FATAL_ERROR);
+ return 0;
+ }
+
+ ret = _app_com_send(endpoint, getpgid(sender_pid), kb, sender_uid);
+ _request_send_result(req, ret);
+
+ return 0;
+}
+
+static int __dispatch_app_com_leave(request_h req)
+{
+ bundle *kb;
+ int ret;
+ const char *endpoint;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ endpoint = bundle_get_val(kb, AUL_K_COM_ENDPOINT);
+ if (endpoint == NULL) {
+ _request_send_result(req, AUL_APP_COM_R_ERROR_FATAL_ERROR);
+ return 0;
+ }
+
+ ret = _app_com_leave(endpoint, getpgid(req->pid));
+ _request_send_result(req, ret);
+
+ return 0;
+}
+
+static int __dispatch_app_register_pid(request_h req)
+{
+ bundle *kb;
+ const struct appinfo *ai;
+ const char *appid;
+ const char *component_type;
+ const char *pid_str;
+ int pid;
+ int ret;
+ uid_t target_uid = _request_get_target_uid(req);
+ int caller_pid = _request_get_pid(req);
+ app_status_h app_status;
+ int status = -1;
+ int focused = -1;
+
+ kb = req->kb;
+ if (kb == NULL)
+ return -1;
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ if (appid == NULL)
+ return -1;
+
+ pid_str = bundle_get_val(kb, AUL_K_PID);
+ if (pid_str == NULL)
+ return -1;
+
+ pid = atoi(pid_str);
+ app_status = _app_status_find_by_appid(appid, target_uid);
+ ret = _app_status_is_running(app_status);
+ if (ret > 0) {
+ if (ret != pid)
+ kill(pid, SIGKILL);
+ _D("status info is already exist: %s", appid);
+ return 0;
+ }
+ _D("appid: %s, pid: %d", appid, pid);
+
+ ai = _appinfo_find(target_uid, appid);
+ component_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (component_type && strcmp(component_type, APP_TYPE_UI) == 0) {
+ _app_group_start_app(pid, kb, pid, FALSE,
+ APP_GROUP_LAUNCH_MODE_SINGLE);
+ }
+
+ _app_status_add_app_info(ai, pid, false, target_uid, caller_pid,
+ false, NULL, false);
+
+ if (component_type && strcmp(component_type, APP_TYPE_SERVICE) != 0) {
+ ret = _signal_get_proc_status(pid, &status, &focused);
+ if (ret < 0)
+ return -1;
+
+ if (focused == 1)
+ _launch_set_focused_pid(pid);
+
+ if (status == PROC_STATUS_FG)
+ status = STATUS_VISIBLE;
+ else if (status == PROC_STATUS_BG)
+ status = STATUS_BG;
+ else
+ return -1;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return -1;
+
+ _app_status_update_status(app_status, status, false, true);
+ }
+
+ return 0;
+}
+
+static int __dispatch_app_set_app_control_default_app(request_h req)
+{
+ bundle *kb = NULL;
+ const char *op;
+ const char *mime_type;
+ const char *uri;
+ const char *appid;
+ int ret;
+ app_property_h prop;
+
+ kb = req->kb;
+ if (kb == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ op = aul_svc_get_operation(kb);
+ appid = aul_svc_get_appid(kb);
+ if (op == NULL || appid == NULL) {
+ _E("Invalid operation, appid");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ mime_type = aul_svc_get_mime(kb);
+ uri = aul_svc_get_uri(kb);
+
+ ret = aul_svc_set_defapp_for_uid(op, mime_type, uri,
+ appid, _request_get_target_uid(req));
+ if (ret < 0) {
+ _E("Error[%d], aul_svc_set_defapp", ret);
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ prop = _app_property_find(_request_get_target_uid(req));
+ _app_property_cache_invalidate(prop);
+ _request_send_result(req, 0);
+ return 0;
+}
+
+static int __dispatch_app_unset_app_control_default_app(request_h req)
+{
+ char appid[MAX_PACKAGE_STR_SIZE];
+ int ret;
+ app_property_h prop;
+
+ snprintf(appid, MAX_PACKAGE_STR_SIZE - 1, "%s",
+ (const char *)req->data);
+
+ ret = aul_svc_unset_defapp_for_uid(appid, _request_get_target_uid(req));
+ if (ret < 0) {
+ _E("Error[%d], aul_svc_unset_defapp", ret);
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ prop = _app_property_find(_request_get_target_uid(req));
+ _app_property_cache_invalidate(prop);
+ _request_send_result(req, 0);
+ return 0;
+}
+
+static int __dispatch_app_set_process_group(request_h req)
+{
+ int owner_pid;
+ int child_pid;
+ bundle *kb = NULL;
+ const char *child_appid;
+ const char *child_pkgid = NULL;
+ const struct appinfo *ai;
+ const char *str_pid;
+ app_status_h app_status;
+ int ret;
+
+ kb = req->kb;
+ if (kb == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ str_pid = bundle_get_val(kb, AUL_K_OWNER_PID);
+ if (str_pid == NULL) {
+ _E("No owner pid");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ owner_pid = atoi(str_pid);
+ str_pid = bundle_get_val(kb, AUL_K_CHILD_PID);
+ if (str_pid == NULL) {
+ _E("No child pid");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ child_pid = atoi(str_pid);
+ app_status = _app_status_find(child_pid);
+ if (app_status) {
+ child_appid = _app_status_get_appid(app_status);
+ ai = _appinfo_find(_request_get_target_uid(req), child_appid);
+ child_pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ }
+
+ ret = aul_send_app_group_signal(owner_pid, child_pid, child_pkgid);
+
+ _request_send_result(req, ret);
+ return 0;
+}
+
+static int __dispatch_app_prepare_candidate_process(request_h req)
+{
+ bundle *b = NULL;
+ int ret;
+
+ b = bundle_create();
+ if (b == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = _send_cmd_to_launchpad(LAUNCHPAD_PROCESS_POOL_SOCK,
+ _request_get_target_uid(req), PAD_CMD_DEMAND, b);
+ bundle_free(b);
+
+ _request_send_result(req, ret);
+ return 0;
+}
+
+static int __dispatch_app_term_sync(request_h req)
+{
+ int ret;
+ int pid;
+ const char *appid;
+ bundle *kb;
+ struct pending_item *item;
+ bool pending = false;
+ GTimeVal end;
+ guint interval;
+ struct reply_info *reply;
+ int clifd;
+
+ kb = req->kb;
+ if (kb == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ ret = __app_process_by_pid(req, appid, &pending);
+ if (ret < 0)
+ return -1;
+
+ /* add pending list to wait app terminated successfully */
+ if (pending) {
+ pid = atoi(appid);
+ clifd = _request_remove_fd(req);
+ g_get_current_time(&end);
+ interval = __get_pending_interval(&req->start, &end);
+ reply = __create_reply_info(interval, pid, -EAGAIN,
+ req->cmd, clifd, NULL);
+ if (reply == NULL) {
+ _send_result_to_client(clifd, ret);
+ return -1;
+ }
+
+ item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
+ if (item == NULL) {
+ item = calloc(1, sizeof(struct pending_item));
+ if (item == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+ item->pid = pid;
+ g_hash_table_insert(pending_table, GINT_TO_POINTER(pid),
+ item);
+ } else {
+ if (item->timer) {
+ g_source_remove(item->timer);
+ item->timer = 0;
+ }
+ }
+ item->reply_list = g_list_append(item->reply_list, reply);
+ item->timer = g_timeout_add(interval, __timeout_pending_item,
+ item);
+ }
+
+ return 0;
+}
+
+static int __dispatch_app_term_sync_without_restart(request_h req)
+{
+ int ret = -1;
+ const char *appid;
+ const char *term_pid;
+ const char *component_type;
+ struct appinfo *ai;
+ app_status_h app_status;
+
+ term_pid = bundle_get_val(req->kb, AUL_K_APPID);
+ if (term_pid == NULL)
+ goto exception;
+
+ app_status = _app_status_find(atoi(term_pid));
+ if (app_status == NULL)
+ goto exception;
+
+ appid = _app_status_get_appid(app_status);
+ if (appid == NULL)
+ goto exception;
+
+ ai = _appinfo_find(_request_get_target_uid(req), appid);
+ if (ai == NULL)
+ goto exception;
+
+ component_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (!component_type)
+ goto exception;
+
+ ret = __dispatch_app_term_sync(req);
+ if (ret < 0)
+ return ret;
+
+ if (strcmp(component_type, APP_TYPE_SERVICE) == 0)
+ _appinfo_set_value(ai, AIT_STATUS, "norestart");
+ return 0;
+
+exception:
+ _request_send_result(req, ret);
+ return ret;
+}
+
+static int __dispatch_app_get_status_by_appid(request_h req)
+{
+ int status;
+ int pid;
+ uid_t uid;
+ const char *appid;
+ bundle *kb;
+ app_status_h app_status;
+
+ kb = _request_get_bundle(req);
+ if (kb == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ uid = _request_get_target_uid(req);
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ if (appid == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ app_status = _app_status_find_by_appid(appid, uid);
+ pid = _app_status_is_running(app_status);
+ if (pid <= 0) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ status = _app_status_get_status(app_status);
+ if (status == STATUS_VISIBLE) {
+ if (_launch_get_focused_pid() == pid)
+ status = STATUS_FOCUS;
+ }
+
+ _request_send_result(req, status);
+ _D("appid: %s, pid: %d, status: %d", appid, pid, status);
+
+ return 0;
+}
+
+static int __validate_widget_owner(request_h req)
+{
+ app_status_h status;
+ const char *appid;
+ char *widget_id = NULL;
+ const char *appid_part = NULL;
+ bundle *kb = req->kb;
+
+ status = _app_status_find(req->pid);
+ if (!status)
+ return -1;
+
+ appid = _app_status_get_appid(status);
+ bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+ if (!widget_id || !appid)
+ return -1;
+
+ appid_part = g_strstr_len(widget_id, strlen(widget_id), "@");
+ if (appid_part)
+ appid_part = appid_part + 1;
+ else
+ appid_part = widget_id;
+
+ return strcmp(appid_part, appid);
+}
+
+static int __dispatch_widget_add_del(request_h req)
+{
+ bundle *kb = req->kb;
+ char *widget_id = NULL;
+ char *instance_id = NULL;
+ int ret;
+
+ if (__validate_widget_owner(req) < 0) {
+ _request_send_result(req, -EINVAL);
+ return -1;
+ }
+
+ bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+ bundle_get_str(kb, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
+ if (!widget_id || !instance_id) {
+ _request_send_result(req, -EINVAL);
+ return -1;
+ }
+
+ if (req->cmd == WIDGET_ADD)
+ ret = _widget_add(widget_id, instance_id, req->pid, req->uid);
+ else
+ ret = _widget_del(widget_id, instance_id);
+
+ _request_send_result(req, ret);
+
+ return ret;
+}
+
+static int __validate_widget_caller(request_h req)
+{
+ bundle *kb = req->kb;
+ char *appid = NULL;
+ struct appinfo *target;
+ const char *target_pkgid;
+ app_status_h caller_status;
+ const char *caller_pkgid;
+
+ if (req->uid < REGULAR_UID_MIN) {
+ _D("bypass caller package check");
+ return 0;
+ }
+
+ bundle_get_str(kb, AUL_K_APPID, &appid);
+ if (!appid) {
+ _E("no appid provided");
+ return -1;
+ }
+
+ target = _appinfo_find(req->uid, appid);
+ if (!target) {
+ _E("can not find appinfo of %s", appid);
+ return -1;
+ }
+
+ target_pkgid = _appinfo_get_value(target, AIT_PKGID);
+ if (!target_pkgid) {
+ _E("can not get pkgid %s", target_pkgid);
+ return -1;
+ }
+
+ caller_status = _app_status_find(req->pid);
+ if (!caller_status)
+ return 0; /* not app? */
+
+ caller_pkgid = _app_status_get_pkgid(caller_status);
+ if (!caller_pkgid) {
+ _E("can not get caller pkgid");
+ return -1;
+ }
+
+ _D("compare pkgid %s:%s", caller_pkgid, target_pkgid);
+ if (strcmp(caller_pkgid, target_pkgid) == 0)
+ return 0;
+
+ return -1;
+}
+
+static int __dispatch_widget_get_content(request_h req)
+{
+ int handles[2] = {0,};
+ struct iovec vec[3];
+ int msglen = 0;
+ char buffer[1024];
+ int ret;
+ bundle *kb = req->kb;
+ struct timeval tv;
+ int pid;
+ char *widget_id = NULL;
+ char *instance_id = NULL;
+
+ if (__validate_widget_caller(req) < 0) {
+ _request_send_result(req, -EILLEGALACCESS);
+ return -1;
+ }
+
+ bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+ bundle_get_str(kb, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
+
+ pid = _widget_get_pid(widget_id, instance_id);
+ if (pid < 0) {
+ _E("can not find widget");
+ _request_send_result(req, -ENOENT);
+ return -1;
+ }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) {
+ _E("error create socket pair");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ if (handles[0] == -1) {
+ _E("error socket open");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+
+ ret = setsockopt(handles[1], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ if (ret < 0) {
+ _E("cannot set SO_RCVTIMEO for socket %d", handles[0]);
+ _request_send_result(req, -1);
+ goto out;
+ }
+
+ vec[0].iov_base = buffer;
+ vec[0].iov_len = strlen(buffer) + 1;
+
+ ret = aul_sock_send_bundle(pid, _request_get_target_uid(req), req->cmd,
+ req->kb, AUL_SOCK_ASYNC);
+
+ msglen = __send_message(ret, vec, 1, &(handles[0]), 1);
+ if (msglen < 0) {
+ _E("Error[%d]: while sending message to widget", -msglen);
+ _request_send_result(req, -1);
+ ret = -1;
+ goto out;
+ }
+
+ msglen = __send_message(req->clifd, vec, 1, &(handles[1]), 1);
+ if (msglen < 0) {
+ _E("Error[%d]: while sending message to caller", -msglen);
+ _request_send_result(req, -1);
+ ret = -1;
+ }
+
+out:
+ close(handles[0]);
+ close(handles[1]);
+
+ return ret;
+}
+
+static int __dispatch_widget_list(request_h req)
+{
+ bundle *kb = req->kb;
+ char *widget_id = NULL;
+ int ret;
+
+ if (__validate_widget_caller(req) < 0) {
+ _request_send_result(req, -EILLEGALACCESS);
+ return -1;
+ }
+
+ bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+ if (!widget_id) {
+ _request_send_result(req, -EINVAL);
+ return -1;
+ }
+
+ ret = _widget_list(widget_id, req);
+
+ return ret;
+}
+
+static int __dispatch_widget_update(request_h req)
+{
+ bundle *kb = _request_get_bundle(req);
+ char *widget_id = NULL;
+ int ret;
+
+ if (__validate_widget_caller(req) < 0) {
+ _request_send_result(req, -EILLEGALACCESS);
+ return -1;
+ }
+
+ bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+ if (!widget_id) {
+ _request_send_result(req, -EINVAL);
+ return -1;
+ }
+
+ /* update will pass bundle by app_control */
+ req->cmd = APP_START_ASYNC;
+
+ ret = _widget_update(widget_id, req);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+static int __dispatch_widget_count(request_h req)
+{
+ bundle *kb = req->kb;
+ char *widget_id = NULL;
+ int count;
+
+ bundle_get_str(kb, AUL_K_WIDGET_ID, &widget_id);
+ if (!widget_id) {
+ _request_send_result(req, -EINVAL);
+ return -1;
+ }
+ count = _widget_count(widget_id, _request_get_uid(req));
+ _D("dispatch widget count %d", count);
+ _request_send_result(req, count);
+
+ return 0;
+}
+
+static int __dispatch_app_get_last_caller_pid(request_h req)
+{
+ int pid;
+ int ret;
+ app_status_h app_status;
+ const char *pid_str;
+ bundle *b = _request_get_bundle(req);
+
+ if (b == NULL) {
+ _E("Failed to get bundle");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ pid_str = bundle_get_val(b, AUL_K_PID);
+ if (pid_str == NULL || !isdigit(pid_str[0])) {
+ _E("Failed to get pid");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ pid = atoi(pid_str);
+ app_status = _app_status_find(pid);
+ ret = _app_status_get_last_caller_pid(app_status);
+ _D("app_get_last_caller_pid: %d : %d", pid, ret);
+ _request_send_result(req, ret);
+
+ return ret;
+}
+
+static int __dispatch_app_set_alias_appid(request_h req)
+{
+ int ret;
+ const char *appid;
+ const char *alias_appid;
+ const struct appinfo *ai;
+ bundle *kb;
+ uid_t uid = _request_get_target_uid(req);
+ app_property_h app_property;
+
+ kb = _request_get_bundle(req);
+ if (kb == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ alias_appid = bundle_get_val(kb, AUL_K_ALIAS_APPID);
+ if (alias_appid == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ if (appid == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ai = _appinfo_find(uid, appid);
+ if (ai == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = aul_svc_set_alias_appid_for_uid(alias_appid, appid, uid);
+ if (ret < 0) {
+ _E("Failed to set alias appid - alias_appid(%s), appid(%s)",
+ alias_appid, appid);
+ _request_send_result(req, ret);
+ return -1;
+ }
+
+ app_property = _app_property_find(uid);
+ if (app_property == NULL) {
+ _E("Failed to find app property - uid(%d)", uid);
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = _app_property_add_alias_info(app_property, alias_appid, appid);
+ if (ret < 0) {
+ _E("Failed to add alias info - %s:%s", alias_appid, appid);
+ _request_send_result(req, ret);
+ return -1;
+ }
+
+ _request_send_result(req, 0);
+
+ return 0;
+}
+
+static int __dispatch_app_unset_alias_appid(request_h req)
+{
+ int ret;
+ const char *alias_appid;
+ bundle *kb;
+ uid_t uid = _request_get_target_uid(req);
+ app_property_h app_property;
+
+ kb = _request_get_bundle(req);
+ if (kb == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ alias_appid = bundle_get_val(kb, AUL_K_ALIAS_APPID);
+ if (alias_appid == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = aul_svc_unset_alias_appid_for_uid(alias_appid, uid);
+ if (ret < 0) {
+ _E("Failed to unset alias appid - alias_appid(%s)", alias_appid);
+ _request_send_result(req, ret);
+ return -1;
+ }
+
+ app_property = _app_property_find(uid);
+ if (app_property == NULL) {
+ _E("Failed to find app property - uid(%d)", uid);
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = _app_property_remove_alias_info(app_property, alias_appid, NULL);
+ if (ret < 0) {
+ _E("Failed to remove alias info - %s", alias_appid);
+ _request_send_result(req, ret);
+ return -1;
+ }
+
+ _request_send_result(req, 0);
+
+ return 0;
+}
+
+static int __dispatch_app_enable_alias_info(request_h req)
+{
+ int ret;
+ const char *appid;
+ bundle *kb;
+ uid_t uid = _request_get_target_uid(req);
+ app_property_h app_property;
+
+ kb = _request_get_bundle(req);
+ if (kb == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ if (appid == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = aul_svc_enable_alias_info_for_uid(appid, uid);
+ if (ret < 0) {
+ _E("Failed to activate alias info - appid(%s)", appid);
+ _request_send_result(req, ret);
+ return -1;
+ }
+
+ app_property = _app_property_find(uid);
+ if (app_property == NULL) {
+ _E("Failed to find app property - uid(%d)", uid);
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = _app_property_add_alias_info(app_property, NULL, appid);
+ if (ret < 0) {
+ _E("Failed to add alias info - %s", appid);
+ _request_send_result(req, ret);
+ return -1;
+ }
+
+ _request_send_result(req, 0);
+
+ return 0;
+}
+
+static int __dispatch_app_disable_alias_info(request_h req)
+{
+ int ret;
+ const char *appid;
+ bundle *kb;
+ uid_t uid = _request_get_target_uid(req);
+ app_property_h app_property;
+
+ kb = _request_get_bundle(req);
+ if (kb == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ appid = bundle_get_val(kb, AUL_K_APPID);
+ if (appid == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = aul_svc_disable_alias_info_for_uid(appid, uid);
+ if (ret < 0) {
+ _E("Failed to deactivate alias info - appid(%s)", appid);
+ _request_send_result(req, ret);
+ return -1;
+ }
+
+ app_property = _app_property_find(uid);
+ if (app_property == NULL) {
+ _E("Failed to find app property - uid(%d)", uid);
+ _request_send_result(req, -1);
+ }
+
+ ret = _app_property_remove_alias_info(app_property, NULL, appid);
+ if (ret < 0) {
+ _E("Failed to remove alias info - appid(%s)", appid);
+ _request_send_result(req, ret);
+ return -1;
+ }
+
+ _request_send_result(req, 0);
+
+ return 0;
+}
+
+static int __dispatch_add_app_screen(request_h req)
+{
+ uid_t uid = _request_get_target_uid(req);
+ int pid = _request_get_pid(req);
+ bundle *b = _request_get_bundle(req);
+ const char *instance_id;
+ const char *value;
+ unsigned int surf;
+ int ret;
+
+ if (b == NULL)
+ return -1;
+
+ instance_id = bundle_get_val(b, AUL_K_INSTANCE_ID);
+ value = bundle_get_val(b, AUL_K_WID);
+ if (value == NULL)
+ return -1;
+
+ surf = atol(value);
+ ret = _screen_connector_add_app_screen(pid, surf,
+ instance_id, uid);
+ _D("pid(%d), surf(%d), instance_id(%s), result(%d)",
+ pid, surf, instance_id, ret);
+
+ return 0;
+}
+
+static int __dispatch_remove_app_screen(request_h req)
+{
+ uid_t uid = _request_get_target_uid(req);
+ int pid = _request_get_pid(req);
+ bundle *b = _request_get_bundle(req);
+ const char *instance_id;
+ int ret;
+
+ if (b == NULL)
+ return -1;
+
+ instance_id = bundle_get_val(b, AUL_K_INSTANCE_ID);
+ ret = _screen_connector_remove_app_screen(pid,
+ instance_id, uid);
+ _D("pid(%d), instance_id(%s), result(%d)",
+ pid, instance_id, ret);
+
+ return 0;
+}
+
+static int __dispatch_app_update_requested(request_h req)
+{
+ uid_t uid = _request_get_target_uid(req);
+ int caller_pid = _request_get_pid(req);
+ bundle *b = _request_get_bundle(req);
+ const char *appid;
+ const char *instance_id;
+ int ret;
+
+ if (b == NULL)
+ return -1;
+
+ appid = bundle_get_val(b, AUL_K_APPID);
+ if (appid == NULL)
+ return -1;
+
+ instance_id = bundle_get_val(b, AUL_K_INSTANCE_ID);
+ ret = _screen_connector_send_update_request(appid, instance_id, uid);
+ _D("appid(%s), instance_id(%s), caller_pid(%d), result(%d)",
+ appid, instance_id, caller_pid, ret);
+
+ return 0;
+}
+
+static int __dispatch_add_screen_viewer(request_h req)
+{
+ uid_t uid = _request_get_target_uid(req);
+ int pid = _request_get_pid(req);
+ bundle *b = _request_get_bundle(req);
+ const char *value;
+ bool priv;
+ int screen_type;
+ unsigned int ref;
+ int ret;
+
+ if (b == NULL)
+ return -1;
+
+ value = bundle_get_val(b, AUL_K_SCREEN_TYPE);
+ if (value == NULL)
+ return -1;
+ screen_type = atoi(value);
+
+ value = bundle_get_val(b, AUL_K_VIEWER_REF);
+ if (value == NULL)
+ return -1;
+ ref = atol(value);
+
+ value = bundle_get_val(b, AUL_K_PRIVATE);
+ if (value && strcmp(value, "true") == 0)
+ priv = true;
+ else
+ priv = false;
+
+ ret = _screen_connector_add_screen_viewer(pid, screen_type,
+ priv, ref, uid);
+ _D("pid(%d), screen_type(%d), private(%d), result(%d)",
+ pid, screen_type, priv, ret);
+
+ return 0;
+}
+
+static int __dispatch_remove_screen_viewer(request_h req)
+{
+ uid_t uid = _request_get_target_uid(req);
+ int pid = _request_get_pid(req);
+ bundle *b = _request_get_bundle(req);
+ const char *value;
+ bool priv;
+ int screen_type;
+ unsigned int ref;
+ int ret;
+
+ if (b == NULL)
+ return -1;
+
+ value = bundle_get_val(b, AUL_K_SCREEN_TYPE);
+ if (value == NULL)
+ return -1;
+ screen_type = atoi(value);
+
+ value = bundle_get_val(b, AUL_K_VIEWER_REF);
+ if (value == NULL)
+ return -1;
+ ref = atol(value);
+
+ value = bundle_get_val(b, AUL_K_PRIVATE);
+ if (value && strcmp(value, "true") == 0)
+ priv = true;
+ else
+ priv = false;
+
+ ret = _screen_connector_remove_screen_viewer(pid, screen_type,
+ priv, ref, uid);
+ _D("pid(%d), screen_type(%d), private(%d), result(%d)",
+ pid, screen_type, priv, ret);
+
+ return 0;
+}
+
+static int __dispatch_launchpad_launch_signal(request_h req)
+{
+ uid_t target_uid = _request_get_target_uid(req);
+
+ _D("uid(%d)", target_uid);
+ _login_monitor_set_uid_state(target_uid, UID_STATE_ONLINE);
+ close(_request_remove_fd(req));
+
+ return 0;
+}
+
+static int __dispatch_app_running_instance_info(request_h req)
+{
+ int fd = _request_remove_fd(req);
+ int cmd = _request_get_cmd(req);
+ uid_t target_uid = _request_get_target_uid(req);
+
+ return _app_status_send_running_appinfo(fd, cmd, target_uid);
+}
+
+static int __dispatch_app_get_instance_id_by_pid(request_h req)
+{
+ int pid;
+ int ret;
+ const char *pid_str;
+ int fd = _request_remove_fd(req);
+ bundle *b = _request_get_bundle(req);
+
+ if (b == NULL) {
+ _E("Failed to get bundle");
+ aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR,
+ NULL, 0, AUL_SOCK_NOREPLY);
+ return -1;
+ }
+
+ pid_str = bundle_get_val(b, AUL_K_PID);
+ if (pid_str == NULL || !isdigit(pid_str[0])) {
+ _E("Failed to get pid");
+ aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR,
+ NULL, 0, AUL_SOCK_NOREPLY);
+ return -1;
+ }
+
+ pid = atoi(pid_str);
+ ret = _app_status_get_instance_id_bypid(fd, pid);
+ _D("app get instance-id by pid - pid(%d), ret(%d)", pid, ret);
+
+ return ret;
+}
+
+static int __dispatch_app_get_appid_from_cache(request_h req)
+{
+ const char *checksum;
+ const char *appid;
+ bundle *b = _request_get_bundle(req);
+ app_property_h prop = _app_property_find(_request_get_target_uid(req));
+
+ checksum = bundle_get_val(b, AUL_K_CHECKSUM);
+ appid = _app_property_cache_get(prop, checksum);
+
+ if (!appid) {
+ aul_sock_send_raw_with_fd(_request_remove_fd(req),
+ APP_GET_APPID_FROM_CACHE, NULL, 0, AUL_SOCK_NOREPLY);
+ return 0;
+ }
+
+ aul_sock_send_raw_with_fd(_request_remove_fd(req),
+ APP_GET_APPID_FROM_CACHE, (unsigned char *)appid,
+ strlen(appid), AUL_SOCK_NOREPLY);
+
+ return 0;
+}
+
+static int __dispatch_app_set_cache(request_h req)
+{
+ const char *appid;
+ const char *checksum;
+ bundle *b = _request_get_bundle(req);
+ app_property_h prop = _app_property_find(_request_get_target_uid(req));
+
+ appid = bundle_get_val(b, AUL_K_APPID);
+ checksum = bundle_get_val(b, AUL_K_CHECKSUM);
+
+ if (!appid || !checksum) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ _app_property_cache_put(prop, checksum, appid);
+ _request_send_result(req, 0);
+ return 0;
+}
+
+static int __dispatch_app_invalidate_cache(request_h req)
+{
+ app_property_h prop = _app_property_find(_request_get_target_uid(req));
+
+ _app_property_cache_invalidate(prop);
+ _request_send_result(req, 0);
+ return 0;
+}
+
+static int __dispatch_app_startup_signal(request_h req)
+{
+ int pid = _request_get_pid(req);
+ app_status_h app_status;
+ struct pending_item *item;
+ struct reply_info *info;
+ GList *iter;
+
+ _I("[APP_STARTUP_SIGNAL] pid(%d)", pid);
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return -1;
+
+ _app_status_update_is_starting(app_status, true);
+ if (_app_status_get_app_type(app_status) == AT_UI_APP &&
+ _app_status_get_status(app_status) != STATUS_VISIBLE)
+ _launch_add_fgmgr(pid);
+
+ item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
+ if (item == NULL) {
+ _W("pending item doesn't exist - pid(%d)", pid);
+ return -1;
+ }
+
+ item->timer = g_timeout_add(PENDING_REQUEST_TIMEOUT,
+ __timeout_pending_item, item);
+
+ iter = g_list_first(item->reply_list);
+ while (iter) {
+ info = (struct reply_info *)iter->data;
+ if (info && info->rua) {
+ g_timeout_add(1500, __add_history_handler, info->rua);
+ info->rua = NULL;
+ }
+ iter = g_list_next(iter);
+ }
+
+ return 0;
+}
+
+static int __dispatch_app_window_attach(request_h req)
+{
+ bundle *b = _request_get_bundle(req);
+ const char *parent_appid;
+ const char *child_appid;
+ int ret;
+ uid_t uid = _request_get_target_uid(req);
+
+ if (!b) {
+ _E("Invalid bundle");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ parent_appid = bundle_get_val(b, AUL_K_PARENT_APPID);
+ if (!parent_appid) {
+ _E("Invalid parameters");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ child_appid = bundle_get_val(b, AUL_K_CHILD_APPID);
+ if (!child_appid) {
+ _E("Invalid parameters");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = _app_group_attach(parent_appid, child_appid, uid);
+ _request_send_result(req, ret);
+
+ return 0;
+}
+
+static int __dispatch_app_window_detach(request_h req)
+{
+ bundle *b = _request_get_bundle(req);
+ const char *child_appid;
+ int ret;
+ uid_t uid = _request_get_target_uid(req);
+
+ if (!b) {
+ _E("Invalid bundle");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ child_appid = bundle_get_val(b, AUL_K_CHILD_APPID);
+ if (!child_appid) {
+ _E("Invalid parameters");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = _app_group_detach(child_appid, uid);
+ _request_send_result(req, ret);
+
+ return 0;
+}
+
+static int __dispatch_app_notify_exit(request_h req)
+{
+ int pid = _request_get_pid(req);
+ int ret;
+ app_status_h app_status;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ _E("pid %d is not an application", pid);
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret = _app_status_set_is_exit_notified(app_status, true);
+ _D("[APP_NOTIFY_EXIT] result(%d)", ret);
+
+ return 0;
+}
+
+static int __dispatch_app_get_appid_by_surface_id(request_h req)
+{
+ uid_t uid = _request_get_target_uid(req);
+ bundle *b = _request_get_bundle(req);
+ unsigned int *surf = NULL;
+ const char *appid;
+ size_t size;
+ bundle *ret_b;
+
+ if (b == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ bundle_get_byte(b, "__AUL_SC_SURFACE__", (void **)&surf, &size);
+ if (surf == NULL) {
+ _E("Failed to get surface");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ appid = _screen_connector_get_appid_by_surface_id(*surf, uid);
+ if (appid == NULL) {
+ _E("Failed to get appid");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret_b = bundle_create();
+ if (ret_b == NULL) {
+ _E("Out of memory");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ bundle_add_str(ret_b, AUL_K_APPID, appid);
+ aul_sock_send_bundle_with_fd(_request_remove_fd(req),
+ _request_get_cmd(req), ret_b, AUL_SOCK_NOREPLY);
+ bundle_free(ret_b);
+
+ return 0;
+}
+
+static int __dispatch_app_get_instance_id_by_surface_id(request_h req)
+{
+ uid_t uid = _request_get_target_uid(req);
+ bundle *b = _request_get_bundle(req);
+ unsigned int *surf = NULL;
+ const char *instance_id;
+ size_t size;
+ bundle *ret_b;
+
+ if (b == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ bundle_get_byte(b, "__AUL_SC_SURFACE__", (void **)&surf, &size);
+ if (surf == NULL) {
+ _E("Failed to get surface");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ instance_id = _screen_connector_get_instance_id_by_surface_id(*surf,
+ uid);
+ if (instance_id == NULL) {
+ _E("Failed to get instance_id");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ ret_b = bundle_create();
+ if (ret_b == NULL) {
+ _E("Out of memory");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ bundle_add_str(ret_b, AUL_K_INSTANCE_ID, instance_id);
+ aul_sock_send_bundle_with_fd(_request_remove_fd(req),
+ _request_get_cmd(req), ret_b, AUL_SOCK_NOREPLY);
+ bundle_free(ret_b);
+
+ return 0;
+}
+
+static int __dispatch_update_screen_viewer_status(request_h req)
+{
+ uid_t uid = _request_get_target_uid(req);
+ int pid = _request_get_pid(req);
+ bundle *b = _request_get_bundle(req);
+ const char *val;
+ aul_screen_status_e status;
+ unsigned int surf;
+ int r;
+
+ if (b == NULL) {
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ val = bundle_get_val(b, "__AUL_SC_VIEWER_STATUS__");
+ if (val == NULL || !isdigit(*val)) {
+ _E("Failed to get viewer status");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ status = atoi(val);
+
+ val = bundle_get_val(b, AUL_K_WID);
+ if (val == NULL || !isdigit(*val)) {
+ _E("Failed to get surface id");
+ _request_send_result(req, -1);
+ return -1;
+ }
+
+ surf = strtoul(val, NULL, 10);
+
+ r = _screen_connector_update_screen_viewer_status(pid, status,
+ surf, uid);
+ _request_send_result(req, r);
+
+ return 0;
+}
+
+static int __dispatch_widget_running_info(request_h req)
+{
+ return _widget_send_running_info(req);
+}
+
+static app_cmd_dispatch_func dispatch_table[APP_CMD_MAX] = {
+ [APP_GET_DC_SOCKET_PAIR] = __dispatch_get_dc_socket_pair,
+ [APP_GET_MP_SOCKET_PAIR] = __dispatch_get_mp_socket_pair,
+ [APP_START] = __dispatch_app_start,
+ [APP_OPEN] = __dispatch_app_start,
+ [APP_RESUME] = __dispatch_app_start,
+ [APP_RESUME_BY_PID] = __dispatch_app_process_by_pid,
+ [APP_TERM_BY_PID] = __dispatch_app_term,
+ [APP_TERM_BY_PID_WITHOUT_RESTART] = __dispatch_app_term_async,
+ [APP_RESULT] = __dispatch_app_result,
+ [APP_START_RES] = __dispatch_app_start,
+ [APP_CANCEL] = __dispatch_app_result,
+ [APP_KILL_BY_PID] = __dispatch_app_term,
+ [APP_UPDATE_RUA_STAT] = __dispatch_update_rua_stat,
+ [APP_ADD_HISTORY] = __dispatch_add_history,
+ [APP_REMOVE_HISTORY] = __dispatch_remove_history,
+ [APP_RUNNING_INFO] = __dispatch_app_running_info,
+ [APP_RUNNING_INFO_RESULT] = NULL,
+ [APP_IS_RUNNING] = __dispatch_app_is_running,
+ [APP_GET_APPID_BYPID] = __dispatch_app_get_appid_by_pid,
+ [APP_GET_PKGID_BYPID] = __dispatch_app_get_pkgid_by_pid,
+ [APP_GET_INFO_OK] = NULL,
+ [APP_GET_INFO_ERROR] = NULL,
+ [APP_KEY_EVENT] = NULL,
+ [APP_KEY_RESERVE] = __dispatch_legacy_command,
+ [APP_KEY_RELEASE] = __dispatch_legacy_command,
+ [APP_STATUS_UPDATE] = __dispatch_app_status_update,
+ [APP_RUNNING_LIST_UPDATE] = __dispatch_legacy_command,
+ [APP_TERM_REQ_BY_PID] = __dispatch_app_process_by_pid,
+ [APP_TERM_BY_PID_ASYNC] = __dispatch_app_term_async,
+ [APP_TERM_BGAPP_BY_PID] = __dispatch_app_term,
+ [APP_PAUSE] = __dispatch_app_pause,
+ [APP_PAUSE_BY_PID] = __dispatch_app_process_by_pid,
+ [APP_GROUP_GET_WINDOW] = __dispatch_app_group_get_window,
+ [APP_GROUP_SET_WINDOW] = __dispatch_app_group_set_window,
+ [APP_GROUP_GET_FG] = __dispatch_app_group_get_fg_flag,
+ [APP_GROUP_GET_LEADER_PID] = __dispatch_app_group_get_leader_pid,
+ [APP_GROUP_GET_LEADER_PIDS] = __dispatch_app_group_get_leader_pids,
+ [APP_GROUP_GET_GROUP_PIDS] = __dispatch_app_group_get_group_pids,
+ [APP_GROUP_GET_IDLE_PIDS] = __dispatch_app_group_get_idle_pids,
+ [APP_GROUP_LOWER] = __dispatch_app_group_lower,
+ [APP_GROUP_CLEAR_TOP] = __dispatch_app_group_clear_top,
+ [APP_GROUP_ACTIVATE_BELOW] = __dispatch_app_group_activate_below,
+ [APP_GROUP_ACTIVATE_ABOVE] = __dispatch_app_group_activate_above,
+ [APP_GET_STATUS] = __dispatch_app_get_status,
+ [APP_ADD_LOADER] = __dispatch_app_add_loader,
+ [APP_REMOVE_LOADER] = __dispatch_app_remove_loader,
+ [APP_GET_PID] = __dispatch_app_is_running,
+ [AMD_RELOAD_APPINFO] = __dispatch_amd_reload_appinfo,
+ [LAUNCHPAD_DEAD_SIGNAL] = __dispatch_launchpad_dead_signal,
+ [APP_COM_CREATE] = __dispatch_app_com_create,
+ [APP_COM_JOIN] = __dispatch_app_com_join,
+ [APP_COM_SEND] = __dispatch_app_com_send,
+ [APP_COM_LEAVE] = __dispatch_app_com_leave,
+ [WIDGET_ADD] = __dispatch_widget_add_del,
+ [WIDGET_DEL] = __dispatch_widget_add_del,
+ [WIDGET_LIST] = __dispatch_widget_list,
+ [WIDGET_UPDATE] = __dispatch_widget_update,
+ [WIDGET_COUNT] = __dispatch_widget_count,
+ [WIDGET_GET_CONTENT] = __dispatch_widget_get_content,
+ [APP_REGISTER_PID] = __dispatch_app_register_pid,
+ [APP_ALL_RUNNING_INFO] = __dispatch_app_all_running_info,
+ [APP_SET_APP_CONTROL_DEFAULT_APP] =
+ __dispatch_app_set_app_control_default_app,
+ [APP_UNSET_APP_CONTROL_DEFAULT_APP] =
+ __dispatch_app_unset_app_control_default_app,
+ [APP_START_ASYNC] = __dispatch_app_start,
+ [APP_SET_PROCESS_GROUP] = __dispatch_app_set_process_group,
+ [APP_PREPARE_CANDIDATE_PROCESS] =
+ __dispatch_app_prepare_candidate_process,
+ [APP_TERM_BY_PID_SYNC] = __dispatch_app_term_sync,
+ [APP_GET_STATUS_BY_APPID] = __dispatch_app_get_status_by_appid,
+ [APP_GET_LAST_CALLER_PID] = __dispatch_app_get_last_caller_pid,
+ [APP_TERM_BY_PID_SYNC_WITHOUT_RESTART] =
+ __dispatch_app_term_sync_without_restart,
+ [APP_RESUME_BY_PID_ASYNC] = __dispatch_app_process_by_pid,
+ [APP_SET_ALIAS_APPID] = __dispatch_app_set_alias_appid,
+ [APP_UNSET_ALIAS_APPID] = __dispatch_app_unset_alias_appid,
+ [APP_ENABLE_ALIAS_INFO] = __dispatch_app_enable_alias_info,
+ [APP_DISABLE_ALIAS_INFO] = __dispatch_app_disable_alias_info,
+ [ADD_APP_SCREEN] = __dispatch_add_app_screen,
+ [REMOVE_APP_SCREEN] = __dispatch_remove_app_screen,
+ [APP_UPDATE_REQUESTED] = __dispatch_app_update_requested,
+ [ADD_SCREEN_VIEWER] = __dispatch_add_screen_viewer,
+ [REMOVE_SCREEN_VIEWER] = __dispatch_remove_screen_viewer,
+ [LAUNCHPAD_LAUNCH_SIGNAL] = __dispatch_launchpad_launch_signal,
+ [APP_RUNNING_INSTANCE_INFO] = __dispatch_app_running_instance_info,
+ [APP_GET_INSTANCE_ID_BYPID] = __dispatch_app_get_instance_id_by_pid,
+ [APP_GET_APPID_FROM_CACHE] = __dispatch_app_get_appid_from_cache,
+ [APP_SET_CACHE] = __dispatch_app_set_cache,
+ [APP_INVALIDATE_CACHE] = __dispatch_app_invalidate_cache,
+ [APP_STARTUP_SIGNAL] = __dispatch_app_startup_signal,
+ [APP_WINDOW_ATTACH] = __dispatch_app_window_attach,
+ [APP_WINDOW_DETACH] = __dispatch_app_window_detach,
+ [APP_START_RES_ASYNC] = __dispatch_app_start,
+ [APP_NOTIFY_EXIT] = __dispatch_app_notify_exit,
+ [APP_GET_APPID_BY_SURFACE_ID] = __dispatch_app_get_appid_by_surface_id,
+ [APP_GET_INSTANCE_ID_BY_SURFACE_ID] =
+ __dispatch_app_get_instance_id_by_surface_id,
+ [UPDATE_SCREEN_VIEWER_STATUS] = __dispatch_update_screen_viewer_status,
+ [WIDGET_RUNNING_INFO] = __dispatch_widget_running_info,
+};
+
+static void __free_reply_info(gpointer data)
+{
+ struct reply_info *reply = (struct reply_info *)data;
+
+ if (reply == NULL)
+ return;
+
+ if (reply->rua)
+ __free_rua_stat_pkt(reply->rua);
+ if (reply->clifd)
+ close(reply->clifd);
+ if (reply->timer)
+ g_source_remove(reply->timer);
+ free(reply);
+}
+
+static struct reply_info *__create_reply_info(guint interval, pid_t pid,
+ int result, int cmd, int clifd, rua_stat_pkt_t *rua)
+{
+ struct reply_info *reply;
+
+ reply = malloc(sizeof(struct reply_info));
+ if (reply == NULL) {
+ _E("Out of memory");
+ return NULL;
+ }
+
+ reply->pid = pid;
+ reply->result = result;
+ reply->cmd = cmd;
+ reply->clifd = clifd;
+ reply->timer = g_timeout_add(interval, __timeout_reply, reply);
+ reply->rua = rua;
+
+ return reply;
+}
+
+static void __free_request(gpointer data)
+{
+ request_h req = (request_h)data;
+
+ if (req == NULL)
+ return;
+
+ if (req->clifd)
+ close(req->clifd);
+ if (req->timer)
+ g_source_remove(req->timer);
+ if (req->kb)
+ bundle_free(req->kb);
+
+ free(req);
+}
+
+static void __free_pending_item(gpointer user_data)
+{
+ struct pending_item *item = (struct pending_item *)user_data;
+
+ if (item == NULL)
+ return;
+
+ if (item->reply_list)
+ g_list_free_full(item->reply_list, __free_reply_info);
+ if (item->pending_list)
+ g_list_free_full(item->pending_list, __free_request);
+ if (g_main_context_find_source_by_user_data(NULL, item))
+ g_source_remove(item->timer);
+ free(item);
+}
+
+static void __timeout_pending_reply(gpointer data, gpointer user_data)
+{
+ struct reply_info *reply = (struct reply_info *)data;
+
+ if (reply == NULL)
+ return;
+
+ _send_result_to_client(reply->clifd, reply->result);
+ reply->clifd = 0;
+}
+
+static void __timeout_pending_request(gpointer data, gpointer user_data)
+{
+ request_h req = (request_h)data;
+
+ if (req == NULL)
+ return;
+
+ _request_send_result(req, -EAGAIN);
+}
+
+static gboolean __timeout_pending_item(gpointer user_data)
+{
+ struct pending_item *item = (struct pending_item *)user_data;
+
+ if (item == NULL)
+ return FALSE;
+
+ g_list_foreach(item->reply_list, __timeout_pending_reply, NULL);
+ g_list_foreach(item->pending_list, __timeout_pending_request, NULL);
+ g_hash_table_remove(pending_table, GINT_TO_POINTER(item->pid));
+
+ return FALSE;
+}
+
+static void __flush_pending_reply_list(GList **reply_list, bool is_dead)
+{
+ GList *iter;
+ struct reply_info *reply;
+
+ if (reply_list == NULL)
+ return;
+
+ iter = g_list_first(*reply_list);
+ while (iter) {
+ reply = (struct reply_info *)iter->data;
+ iter = g_list_next(iter);
+ if (reply == NULL)
+ continue;
+
+ if (reply->cmd == APP_TERM_BY_PID_SYNC_WITHOUT_RESTART ||
+ reply->cmd == APP_TERM_BY_PID_SYNC) {
+ if (!is_dead)
+ continue;
+
+ reply->result = 0;
+ }
+
+ *reply_list = g_list_remove(*reply_list, reply);
+ _send_result_to_client(reply->clifd, reply->result);
+ reply->clifd = 0;
+ __free_reply_info(reply);
+ }
+}
+
+static void __flush_pending_request_list(GList **pending_list)
+{
+ GList *iter;
+ request_h req;
+
+ if (pending_list == NULL)
+ return;
+
+ iter = g_list_first(*pending_list);
+ while (iter) {
+ req = (request_h)iter->data;
+ iter = g_list_next(iter);
+ if (req == NULL)
+ continue;
+
+ *pending_list = g_list_remove(*pending_list, req);
+ if (req->timer) {
+ g_source_remove(req->timer);
+ req->timer = 0;
+ }
+ g_idle_add(__dispatch_request, req);
+ }
+}
+
+int _request_flush_pending_request(int pid)
+{
+ struct pending_item *item;
+
+ item = (struct pending_item *)g_hash_table_lookup(pending_table,
+ GINT_TO_POINTER(pid));
+ if (item == NULL)
+ return -1;
+
+ __flush_pending_reply_list(&item->reply_list, true);
+ __timeout_pending_item((gpointer)item);
+
+ return 0;
+}
+
+int _request_reply_for_pending_request(int pid)
+{
+ struct pending_item *item;
+
+ _app_status_publish_status(pid, STATUS_LAUNCHING);
+
+ item = (struct pending_item *)g_hash_table_lookup(pending_table,
+ GINT_TO_POINTER(pid));
+ if (item == NULL)
+ return -1;
+
+ __flush_pending_reply_list(&item->reply_list, false);
+ __flush_pending_request_list(&item->pending_list);
+
+ return 0;
+}
+
+static request_h __get_request(int clifd, app_pkt_t *pkt,
+ struct ucred cr)
+{
+ request_h req;
+ const char *target_uid;
+
+ req = (request_h)malloc(sizeof(struct request_s) + pkt->len);
+ if (req == NULL)
+ return NULL;
+
+ g_get_current_time(&req->start);
+ req->timer = 0;
+ req->clifd = clifd;
+ req->pid = cr.pid;
+ req->t_pid = 0;
+ req->uid = cr.uid;
+ req->cmd = pkt->cmd;
+ req->len = pkt->len;
+ req->opt = pkt->opt;
+ memcpy(req->data, pkt->data, pkt->len + 1);
+
+ if (pkt->opt & AUL_SOCK_BUNDLE) {
+ req->kb = bundle_decode(pkt->data, pkt->len);
+ if (req->kb == NULL) {
+ free(req);
+ return NULL;
+ }
+
+ target_uid = bundle_get_val(req->kb, AUL_K_TARGET_UID);
+ if (target_uid && isdigit(target_uid[0]))
+ req->t_uid = atoi(target_uid);
+ else
+ req->t_uid = cr.uid;
+ } else {
+ req->kb = NULL;
+ req->t_uid = cr.uid;
+ }
+
+ return req;
+}
+
+static gboolean __timeout_reply(gpointer data)
+{
+ struct reply_info *reply = (struct reply_info *)data;
+ struct pending_item *item;
+
+ if (reply == NULL)
+ return FALSE;
+
+ item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(reply->pid));
+ if (item)
+ item->reply_list = g_list_remove(item->reply_list, reply);
+
+ _send_result_to_client(reply->clifd, reply->result);
+ reply->clifd = 0;
+ reply->timer = 0;
+ __free_reply_info(reply);
+
+ return FALSE;
+}
+
+static gboolean __timeout_request(gpointer data)
+{
+ request_h req = (request_h)data;
+ struct pending_item *item;
+
+ if (req == NULL)
+ return FALSE;
+
+ item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(req->t_pid));
+ if (item)
+ item->pending_list = g_list_remove(item->pending_list, req);
+
+ if (req->clifd)
+ _request_send_result(req, -EAGAIN);
+ req->timer = 0;
+ __free_request(req);
+
+ return FALSE;
+}
+
+static app_status_h __get_app_status(request_h req, const char *appid)
+{
+ int pid;
+ app_status_h app_status;
+ int status;
+ struct appinfo *ai;
+ const char *comp_type;
+
+ switch (req->cmd) {
+ case APP_RESUME_BY_PID:
+ case APP_TERM_BY_PID:
+ case APP_TERM_BY_PID_WITHOUT_RESTART:
+ case APP_KILL_BY_PID:
+ case APP_TERM_REQ_BY_PID:
+ case APP_TERM_BY_PID_ASYNC:
+ case APP_TERM_BGAPP_BY_PID:
+ case APP_PAUSE_BY_PID:
+ case APP_TERM_BY_PID_SYNC:
+ case APP_TERM_BY_PID_SYNC_WITHOUT_RESTART:
+ /* get pid */
+ pid = atoi(appid);
+ app_status = _app_status_find(pid);
+ break;
+ case APP_START_ASYNC:
+ case APP_START_RES_ASYNC:
+ ai = _appinfo_find(_request_get_target_uid(req), appid);
+ comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (comp_type && (strcmp(comp_type, APP_TYPE_WIDGET) == 0 ||
+ strcmp(comp_type, APP_TYPE_WATCH) == 0)) {
+ app_status = _app_status_find_with_org_caller(appid,
+ _request_get_target_uid(req),
+ _request_get_pid(req));
+ } else {
+ app_status = _app_status_find_by_appid(appid,
+ _request_get_target_uid(req));
+ }
+ break;
+ default:
+ app_status = _app_status_find_by_appid(appid,
+ _request_get_target_uid(req));
+ break;
+ }
+
+ if (app_status == NULL)
+ return NULL;
+
+ status = _app_status_get_status(app_status);
+ if (status == STATUS_DYING)
+ return NULL;
+
+ return app_status;
+}
+
+static int __check_request(request_h req)
+{
+ int pid;
+ struct pending_item *item;
+ app_status_h app_status;
+ const char *appid;
+
+ if (req->opt & AUL_SOCK_NOREPLY)
+ close(_request_remove_fd(req));
+
+ if ((req->opt & AUL_SOCK_QUEUE) == 0)
+ return 0;
+
+ if (req->kb == NULL)
+ return -1;
+
+ appid = bundle_get_val(req->kb, AUL_K_APPID);
+ if (appid == NULL)
+ return -1;
+
+ app_status = __get_app_status(req, appid);
+ if (app_status == NULL)
+ return 0;
+
+ if (_app_status_socket_exists(app_status))
+ return 0;
+
+ pid = _app_status_get_pid(app_status);
+ item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
+ if (item == NULL)
+ return 0;
+
+ if (!_app_status_is_starting(app_status)) {
+ req->t_pid = pid;
+ _W("%s(%d) is waiting to be started.", appid, pid);
+ req->timer = g_timeout_add(PENDING_REQUEST_TIMEOUT,
+ __timeout_request, req);
+ }
+
+ item->pending_list = g_list_append(item->pending_list, req);
+
+ return 1;
+}
+
+static int __check_target_user(request_h req)
+{
+ int r;
+ uid_t *uids;
+ int i;
+ uid_state state;
+
+ if (req->t_uid >= REGULAR_UID_MIN) {
+ state = _login_monitor_get_uid_state(req->t_uid);
+ if (state == UID_STATE_ONLINE || state == UID_STATE_ACTIVE)
+ return 0;
+
+ return -1;
+ }
+
+ r = _login_monitor_get_uids(&uids);
+ if (r <= 0)
+ return -1;
+
+ for (i = 0; i < r; i++) {
+ state = _login_monitor_get_uid_state(uids[i]);
+ if (state == UID_STATE_ONLINE || state == UID_STATE_ACTIVE) {
+ req->t_uid = uids[i];
+ break;
+ }
+ }
+ free(uids);
+
+ if (req->t_uid < REGULAR_UID_MIN)
+ return -1;
+
+ return 0;
+}
+
+static gboolean __dispatch_request(gpointer data)
+{
+ request_h req = (request_h)data;
+
+ if (req == NULL)
+ return FALSE;
+
+ if (req->cmd < 0 || req->cmd >= APP_CMD_MAX) {
+ __free_request(req);
+ return FALSE;
+ }
+
+ if (dispatch_table[req->cmd]) {
+ if (dispatch_table[req->cmd](req) != 0)
+ _E("callback returns FALSE : %d", req->cmd);
+ } else {
+ _E("Invalid request or not supported command");
+ }
+
+ __free_request(req);
+
+ return FALSE;
+}
+
+int _request_usr_init(uid_t uid)
+{
+ GList *iter;
+ request_h req;
+ int r;
+ struct pending_item *item;
+
+ item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(getpid()));
+ if (item == NULL || item->pending_list == NULL)
+ return 0;
+
+ iter = g_list_first(item->pending_list);
+ while (iter) {
+ req = (request_h)iter->data;
+ iter = g_list_next(iter);
+ if (req == NULL)
+ continue;
+
+ req->t_pid = 0;
+ if (req->t_uid < REGULAR_UID_MIN)
+ req->t_uid = uid;
+
+ if (req->t_uid == uid) {
+ g_source_remove(req->timer);
+ req->timer = 0;
+ item->pending_list = g_list_remove(item->pending_list,
+ req);
+
+ r = __check_request(req);
+ if (r == 0)
+ g_idle_add(__dispatch_request, (gpointer)req);
+ else if (r < 0)
+ __free_request(req);
+ }
+ }
+
+ return 0;
+}
+
+static gboolean __request_handler(GIOChannel *io, GIOCondition cond,
+ gpointer data)
+{
+ int fd = g_io_channel_unix_get_fd(io);
+ app_pkt_t *pkt;
+ int ret;
+ int clifd;
+ struct ucred cr;
+ request_h req;
+ int len;
+ struct pending_item *item;
+
+ pkt = aul_sock_recv_pkt(fd, &clifd, &cr);
+ if (pkt == NULL) {
+ _E("recv error");
+ return TRUE;
+ }
+
+ req = __get_request(clifd, pkt, cr);
+ if (req == NULL) {
+ close(clifd);
+ free(pkt);
+ return TRUE;
+ }
+ free(pkt);
+
+ if (req->uid >= REGULAR_UID_MIN) {
+ if (req->uid != req->t_uid) {
+ _E("request has been deined - uid(%d), target_uid(%d)",
+ req->uid, req->t_uid);
+ ret = -EILLEGALACCESS;
+ _request_send_result(req, ret);
+ __free_request(req);
+ return TRUE;
+ }
+
+ ret = _cynara_check_privilege(req);
+ if (ret < 0) {
+ _E("request has been denied by cynara");
+ ret = -EILLEGALACCESS;
+ _request_send_result(req, ret);
+ __free_request(req);
+ return TRUE;
+ }
+ } else {
+ ret = __check_target_user(req);
+ if (ret < 0 && (req->cmd == APP_START_ASYNC ||
+ req->cmd == APP_START_RES_ASYNC)) {
+ item = g_hash_table_lookup(pending_table,
+ GINT_TO_POINTER(getpid()));
+ if (item == NULL) {
+ item = calloc(1, sizeof(struct pending_item));
+ if (item == NULL) {
+ _E("Out of memory");
+ _request_send_result(req, ret);
+ __free_request(req);
+ return TRUE;
+ }
+ item->pid = getpid();
+ g_hash_table_insert(pending_table,
+ GINT_TO_POINTER(getpid()),
+ item);
+ }
+
+ len = g_list_length(item->pending_list);
+ if (len <= PENDING_MESSAGE_MAX_CNT) {
+ _D("user not logged");
+ _request_send_result(req, 0);
+ req->t_pid = getpid();
+ req->timer = g_timeout_add(
+ SYSTEM_REQUEST_TIMEOUT,
+ __timeout_request, req);
+ item->pending_list = g_list_append(
+ item->pending_list, req);
+ return TRUE;
+ }
+ }
+ }
+
+ ret = __check_request(req);
+ if (ret < 0) {
+ _request_send_result(req, ret);
+ __free_request(req);
+ return TRUE;
+ } else if (ret > 0) {
+ return TRUE;
+ }
+
+ __dispatch_request((gpointer)req);
+
+ return TRUE;
+}
+
+int _request_get_fd(request_h req)
+{
+ return req->clifd;
+}
+
+int _request_get_pid(request_h req)
+{
+ return req->pid;
+}
+
+pid_t _request_get_target_pid(request_h req)
+{
+ return req->t_pid;
+}
+
+bundle *_request_get_bundle(request_h req)
+{
+ return req->kb;
+}
+
+request_h _request_create_local(int cmd, uid_t uid, int pid, bundle *kb)
+{
+ request_h req;
+
+ req = (request_h)malloc(sizeof(struct request_s));
+ if (req == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ g_get_current_time(&req->start);
+ req->timer = 0;
+ req->clifd = -1;
+ req->pid = pid;
+ req->t_pid = 0;
+ req->uid = getuid();
+ req->t_uid = uid;
+ req->cmd = cmd;
+ req->len = 0;
+ req->opt = AUL_SOCK_NONE;
+ req->kb = bundle_dup(kb);
+
+ return req;
+}
+
+void _request_free_local(request_h req)
+{
+ if (req == NULL)
+ return;
+
+ if (req->kb)
+ bundle_free(req->kb);
+
+ free(req);
+}
+
+int _request_get_cmd(request_h req)
+{
+ return req->cmd;
+}
+
+int _request_remove_fd(request_h req)
+{
+ int r = req->clifd;
+
+ req->clifd = 0;
+
+ return r;
+}
+
+uid_t _request_get_target_uid(request_h req)
+{
+ return req->t_uid;
+}
+
+uid_t _request_get_uid(request_h req)
+{
+ return req->uid;
+}
+
+int _request_send_raw(request_h req, int cmd, unsigned char *data, int len)
+{
+ return aul_sock_send_raw_with_fd(_request_remove_fd(req), cmd, data,
+ len, AUL_SOCK_NOREPLY);
+}
+
+int _request_send_result(request_h req, int res)
+{
+ if (req->clifd && (req->opt & AUL_SOCK_NOREPLY))
+ close(_request_remove_fd(req));
+ else if (req->clifd)
+ _send_result_to_client(_request_remove_fd(req), res);
+
+ return 0;
+}
+
+static void __free_socket_pair(gpointer data)
+{
+ int *handles = (int *)data;
+
+ if (handles[0] > 0)
+ close(handles[0]);
+ if (handles[1] > 0)
+ close(handles[1]);
+ free(handles);
+}
+
+int _request_init(void)
+{
+ _D("request init");
+ __dc_socket_pair_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ free, __free_socket_pair);
+ if (__dc_socket_pair_hash == NULL) {
+ _E("Failed to create socket pair table");
+ _request_fini();
+ return -1;
+ }
+
+ pending_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, __free_pending_item);
+ if (pending_table == NULL) {
+ _E("Failed to create pending table");
+ _request_fini();
+ return -1;
+ }
+
+ amd_fd = _create_sock_activation();
+ if (amd_fd == -1) {
+ _D("Create server socket without socket activation");
+ amd_fd = _create_server_sock();
+ if (amd_fd == -1) {
+ _E("Create server socket failed.");
+ _request_fini();
+ return -1;
+ }
+ }
+
+ amd_io = g_io_channel_unix_new(amd_fd);
+ if (amd_io == NULL) {
+ _E("Failed to create gio channel");
+ _request_fini();
+ return -1;
+ }
+
+ amd_wid = g_io_add_watch(amd_io, G_IO_IN, __request_handler, NULL);
+ if (amd_wid == 0) {
+ _E("Failed to add gio watch");
+ _request_fini();
+ return -1;
+ }
+
+ return 0;
+}
+
+void _request_fini(void)
+{
+ _D("request fini");
+ if (amd_wid) {
+ g_source_remove(amd_wid);
+ amd_wid = 0;
+ }
+
+ if (amd_io) {
+ g_io_channel_unref(amd_io);
+ amd_io = NULL;
+ }
+
+ if (amd_fd > 0) {
+ close(amd_fd);
+ amd_fd = 0;
+ }
+
+ if (pending_table) {
+ g_hash_table_destroy(pending_table);
+ pending_table = NULL;
+ }
+
+ if (__dc_socket_pair_hash) {
+ g_hash_table_destroy(__dc_socket_pair_hash);
+ __dc_socket_pair_hash = NULL;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <aul.h>
+#include <rua_internal.h>
+
+#include "amd_util.h"
+#include "amd_rua.h"
+#include "amd_app_status.h"
+#include "amd_app_group.h"
+#include "amd_inotify.h"
+
+#define PATH_RUN "/run"
+#define FILE_E_IMG ".e-img"
+#define PATH_RUN_E_IMG PATH_RUN "/" FILE_E_IMG
+
+struct rua_info_s {
+ uid_t uid;
+ char *appid;
+ char *app_path;
+ char *instance_id;
+ char *image_path;
+ unsigned int surf;
+};
+
+static int __dir_wd;
+static int __img_wd;
+static GHashTable *__rua_tbl;
+
+static void __destroy_rua_info(gpointer data)
+{
+ struct rua_info_s *info = (struct rua_info_s *)data;
+
+ if (info == NULL)
+ return;
+
+ if (info->image_path) {
+ unlink(info->image_path); /* Delete image file */
+ free(info->image_path);
+ }
+
+ if (info->instance_id)
+ free(info->instance_id);
+
+ if (info->app_path)
+ free(info->app_path);
+
+ if (info->appid)
+ free(info->appid);
+
+ free(info);
+}
+
+static struct rua_info_s *__create_rua_info(const char *appid,
+ const char *app_path, const char *instance_id,
+ uid_t uid)
+{
+ struct rua_info_s *info;
+
+ info = calloc(1, sizeof(struct rua_info_s));
+ if (info == NULL) {
+ _E("Out of memory");
+ return NULL;
+ }
+
+ info->appid = strdup(appid);
+ if (info->appid == NULL) {
+ _E("Out of memory");
+ __destroy_rua_info(info);
+ return NULL;
+ }
+
+ info->app_path = strdup(app_path);
+ if (info->app_path == NULL) {
+ _E("Out of memory");
+ __destroy_rua_info(info);
+ return NULL;
+ }
+
+ if (instance_id) {
+ info->instance_id = strdup(instance_id);
+ if (info->instance_id == NULL) {
+ _E("Out of memory");
+ __destroy_rua_info(info);
+ return NULL;
+ }
+ }
+
+ info->uid = uid;
+
+ return info;
+}
+
+int _rua_update_screen_info(int pid, unsigned int surf)
+{
+ struct rua_info_s *info;
+ int leader_pid;
+
+ if (__rua_tbl == NULL)
+ return -1;
+
+ leader_pid = _app_group_get_leader_pid(pid);
+ if (leader_pid > 0)
+ pid = leader_pid;
+
+ info = (struct rua_info_s *)g_hash_table_lookup(__rua_tbl,
+ GINT_TO_POINTER(pid));
+ if (info == NULL)
+ return -1;
+
+ info->surf = surf;
+
+ return 0;
+}
+
+int _rua_add_info(int pid, bool new_instance)
+{
+ struct rua_info_s *info;
+ app_status_h app_status;
+ const char *appid;
+ const char *app_path;
+ const char *instance_id;
+ uid_t uid;
+
+ if (__rua_tbl == NULL)
+ return 0;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return -1;
+
+ appid = _app_status_get_appid(app_status);
+ app_path = _app_status_get_app_path(app_status);
+ uid = _app_status_get_uid(app_status);
+
+ if (new_instance)
+ instance_id = _app_status_get_instance_id(app_status);
+ else
+ instance_id = NULL;
+
+ info = __create_rua_info(appid, app_path, instance_id, uid);
+ if (info == NULL)
+ return -1;
+
+ if (g_hash_table_contains(__rua_tbl, GINT_TO_POINTER(pid)))
+ g_hash_table_replace(__rua_tbl, GINT_TO_POINTER(pid), info);
+ else
+ g_hash_table_insert(__rua_tbl, GINT_TO_POINTER(pid), info);
+
+ return 0;
+}
+
+static gboolean __foreach_remove_by_uid(gpointer key, gpointer value,
+ gpointer data)
+{
+ struct rua_info_s *info = (struct rua_info_s *)value;
+ uid_t uid = GPOINTER_TO_UINT(data);
+
+ if (info->uid == uid)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean __foreach_remove_by_appid(gpointer key, gpointer value,
+ gpointer data)
+{
+ struct rua_info_s *info = (struct rua_info_s *)value;
+ const char *appid = (const char *)data;
+
+ if (strcmp(info->appid, appid) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean __foreach_remove_by_app_path(gpointer key, gpointer value,
+ gpointer data)
+{
+ struct rua_info_s *info = (struct rua_info_s *)value;
+ const char *app_path = (const char *)data;
+
+ if (strcmp(info->app_path, app_path) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean __foreach_remove_by_instance_id(gpointer key, gpointer value,
+ gpointer data)
+{
+ struct rua_info_s *info = (struct rua_info_s *)value;
+ const char *instance_id = (const char *)data;
+
+ if (info->instance_id && strcmp(info->instance_id, instance_id) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+const char *_rua_get_image_path(int pid)
+{
+ struct rua_info_s *info;
+
+ if (__rua_tbl == NULL)
+ return NULL;
+
+ info = (struct rua_info_s *)g_hash_table_lookup(__rua_tbl,
+ GINT_TO_POINTER(pid));
+ if (info == NULL)
+ return NULL;
+
+ return info->image_path;
+}
+
+int _rua_delete_info(bundle *b, uid_t uid)
+{
+ char *appid = NULL;
+ char *app_path = NULL;
+ char *instance_id = NULL;
+
+ if (b) {
+ bundle_get_str(b, AUL_K_RUA_PKGNAME, &appid);
+ bundle_get_str(b, AUL_K_RUA_APPPATH, &app_path);
+ bundle_get_str(b, AUL_K_RUA_INSTANCE_ID, &instance_id);
+ }
+
+ if (appid) {
+ g_hash_table_foreach_remove(__rua_tbl,
+ __foreach_remove_by_appid, appid);
+ } else if (app_path) {
+ g_hash_table_foreach_remove(__rua_tbl,
+ __foreach_remove_by_app_path, app_path);
+ } else if (instance_id) {
+ g_hash_table_foreach_remove(__rua_tbl,
+ __foreach_remove_by_instance_id, instance_id);
+ } else {
+ g_hash_table_foreach_remove(__rua_tbl,
+ __foreach_remove_by_uid, GUINT_TO_POINTER(uid));
+ }
+
+ return 0;
+}
+
+static void __update_img_file(const char *img)
+{
+ int r;
+ int pid = -1;
+ unsigned int surf = 0;
+ int num = -1;
+ char buf[PATH_MAX];
+ struct rua_info_s *info;
+ int leader_pid;
+
+ sscanf(img, "win_%d_%u-%d.png", &pid, &surf, &num);
+ if (pid <= 0)
+ return;
+
+ snprintf(buf, sizeof(buf), "%s/%s", PATH_RUN_E_IMG, img);
+
+ leader_pid = _app_group_get_leader_pid(pid);
+ if (leader_pid > 0)
+ pid = leader_pid;
+
+ info = (struct rua_info_s *)g_hash_table_lookup(__rua_tbl,
+ GINT_TO_POINTER(pid));
+ if (info == NULL || (info->surf != 0 && info->surf != surf)) {
+ unlink(buf);
+ return;
+ }
+
+ if (info->image_path) {
+ if (strcmp(info->image_path, buf) == 0)
+ return;
+
+ unlink(info->image_path);
+ free(info->image_path);
+ }
+
+ r = rua_usr_db_update_image(info->appid, info->instance_id,
+ buf, info->uid);
+ if (r < 0)
+ _W("Failed to update image path - appid(%s)", info->appid);
+
+ info->image_path = strdup(buf);
+ if (info->image_path == NULL)
+ _E("Out of memory");
+
+ if (info->surf == 0)
+ info->surf = surf;
+}
+
+static void __find_imgs(void)
+{
+ DIR *dp;
+ struct dirent *dentry = NULL;
+ char buf[PATH_MAX];
+ struct stat statbuf;
+ int r;
+
+ dp = opendir(PATH_RUN_E_IMG);
+ if (dp == NULL)
+ return;
+
+ while ((dentry = readdir(dp))) {
+ if (!strcmp(dentry->d_name, ".") ||
+ !strcmp(dentry->d_name, ".."))
+ continue;
+
+ snprintf(buf, sizeof(buf), "%s/%s",
+ PATH_RUN_E_IMG, dentry->d_name);
+ r = stat(buf, &statbuf);
+ if (r == 0) {
+ if (S_ISREG(statbuf.st_mode))
+ __update_img_file(buf);
+ }
+ }
+ closedir(dp);
+}
+
+static bool __img_monitor_cb(const char *event_name, void *data)
+{
+ if (event_name) {
+ __update_img_file(event_name);
+ _D("%s is created", event_name);
+ }
+
+ return true;
+}
+
+static bool __dir_monitor_cb(const char *event_name, void *data)
+{
+ if (event_name == NULL)
+ return true;
+
+ if (strcmp(event_name, FILE_E_IMG) == 0) {
+ __img_wd = _inotify_add_watch(PATH_RUN_E_IMG, IN_CREATE,
+ __img_monitor_cb, NULL);
+ if (__img_wd < 0)
+ _E("Failed to add inotify watch");
+ else
+ __find_imgs();
+
+ __dir_wd = 0;
+ return false;
+ }
+
+ return true;
+}
+
+int _rua_usr_init(uid_t uid)
+{
+ int r;
+
+ r = rua_usr_db_delete_history(NULL, uid);
+ if (r < 0) {
+ _E("Failed to delete rua history - uid(%u)", uid);
+ return -1;
+ }
+
+ return 0;
+}
+
+void _rua_usr_fini(uid_t uid)
+{
+ if (__rua_tbl == NULL)
+ return;
+
+ g_hash_table_foreach_remove(__rua_tbl,
+ __foreach_remove_by_uid, GUINT_TO_POINTER(uid));
+}
+
+int _rua_init(void)
+{
+ _D("[RUA] init");
+
+ if (access(PATH_RUN_E_IMG, F_OK) == 0) {
+ __img_wd = _inotify_add_watch(PATH_RUN_E_IMG, IN_CREATE,
+ __img_monitor_cb, NULL);
+ if (__img_wd < 0)
+ return -1;
+
+ __find_imgs();
+ } else {
+ __dir_wd = _inotify_add_watch(PATH_RUN, IN_CREATE,
+ __dir_monitor_cb, NULL);
+ if (__dir_wd < 0)
+ return -1;
+ }
+
+ __rua_tbl = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, __destroy_rua_info);
+ if (__rua_tbl == NULL) {
+ _E("Failed to create rua table");
+ return -1;
+ }
+
+ return 0;
+}
+
+void _rua_fini(void)
+{
+ _D("[RUA] finish");
+
+ if (__rua_tbl) {
+ g_hash_table_destroy(__rua_tbl);
+ __rua_tbl = NULL;
+ }
+
+ if (__dir_wd > 0)
+ _inotify_rm_watch(__dir_wd);
+ if (__img_wd > 0)
+ _inotify_rm_watch(__img_wd);
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+#include <bundle_internal.h>
+#include <aul.h>
+#include <aul_sock.h>
+#include <aul_screen_connector.h>
+
+#include "amd_util.h"
+#include "amd_app_group.h"
+#include "amd_app_status.h"
+#include "amd_app_com.h"
+#include "amd_suspend.h"
+#include "amd_screen_connector.h"
+
+#define SUSPEND_INTERVAL 5 /* sec */
+
+struct app_screen_s {
+ char *appid;
+ char *instance_id;
+ int pid;
+ uid_t uid;
+ unsigned int surf;
+ int screen_type;
+ int caller_pid;
+ GList *viewer_list;
+};
+
+struct viewer_info_s {
+ int pid;
+ int screen_type;
+ bool priv;
+ unsigned int ref;
+ aul_screen_status_e status;
+ GList *watch_list;
+};
+
+struct user_info_s {
+ uid_t uid;
+ GList *screen_viewer_list;
+ GList *app_screen_list;
+};
+
+static GHashTable *user_table;
+
+static struct app_screen_s *__create_app_screen(int pid, uid_t uid,
+ const char *appid, unsigned int surf, const char *instance_id,
+ int screen_type, int caller_pid)
+{
+ struct app_screen_s *app_screen;
+
+ app_screen = calloc(1, sizeof(struct app_screen_s));
+ if (app_screen == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ app_screen->appid = strdup(appid);
+ if (app_screen->appid == NULL) {
+ _E("out of memory");
+ free(app_screen);
+ return NULL;
+ }
+
+ app_screen->instance_id = strdup(instance_id);
+ if (app_screen->instance_id == NULL) {
+ _E("out of memory");
+ free(app_screen->appid);
+ free(app_screen);
+ return NULL;
+ }
+
+ app_screen->pid = pid;
+ app_screen->uid = uid;
+ app_screen->surf = surf;
+ app_screen->screen_type = screen_type;
+ app_screen->caller_pid = caller_pid;
+
+ return app_screen;
+}
+
+static void __destroy_app_screen(gpointer data)
+{
+ struct app_screen_s *app_screen = (struct app_screen_s *)data;
+ struct viewer_info_s *viewer_info;
+ GList *iter;
+
+ if (app_screen == NULL)
+ return;
+
+ if (app_screen->viewer_list) {
+ iter = app_screen->viewer_list;
+ while (iter) {
+ viewer_info = (struct viewer_info_s *)iter->data;
+ viewer_info->watch_list = g_list_remove(
+ viewer_info->watch_list, app_screen);
+ iter = g_list_next(iter);
+ }
+ g_list_free(app_screen->viewer_list);
+ }
+
+ if (app_screen->instance_id)
+ free(app_screen->instance_id);
+ if (app_screen->appid)
+ free(app_screen->appid);
+ free(app_screen);
+}
+
+static gint __compare_instance_id(gconstpointer a, gconstpointer b)
+{
+ struct app_screen_s *app_screen = (struct app_screen_s *)a;
+ const char *instance_id = (const char *)b;
+
+ if (app_screen == NULL || instance_id == NULL)
+ return -1;
+
+ if (!strcmp(app_screen->instance_id, instance_id))
+ return 0;
+
+ return -1;
+}
+
+static void __destroy_viewer_info(struct viewer_info_s *viewer_info)
+{
+ struct app_screen_s *app_screen;
+ GList *iter;
+
+ if (viewer_info == NULL)
+ return;
+
+ if (viewer_info->watch_list) {
+ iter = viewer_info->watch_list;
+ while (iter) {
+ app_screen = (struct app_screen_s *)iter->data;
+ app_screen->viewer_list = g_list_remove(
+ app_screen->viewer_list, viewer_info);
+ iter = g_list_next(iter);
+ }
+ g_list_free(viewer_info->watch_list);
+ }
+
+ free(viewer_info);
+}
+
+static struct viewer_info_s *__create_viewer_info(int pid, int screen_type,
+ bool priv, unsigned int ref)
+{
+ struct viewer_info_s *viewer_info;
+
+ viewer_info = calloc(1, sizeof(struct viewer_info_s));
+ if (viewer_info == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ viewer_info->pid = pid;
+ viewer_info->screen_type = screen_type;
+ viewer_info->priv = priv;
+ viewer_info->ref = ref;
+
+ return viewer_info;
+}
+
+static void __destroy_user_info(gpointer data)
+{
+ struct user_info_s *user_info = (struct user_info_s *)data;
+
+ if (user_info == NULL)
+ return;
+
+ if (user_info->app_screen_list) {
+ g_list_free_full(user_info->app_screen_list,
+ __destroy_app_screen);
+ }
+ if (user_info->screen_viewer_list)
+ g_list_free_full(user_info->screen_viewer_list, free);
+ free(user_info);
+}
+
+static struct user_info_s *__create_user_info(uid_t uid)
+{
+ struct user_info_s *user_info;
+
+ user_info = malloc(sizeof(struct user_info_s));
+ if (user_info == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ user_info->uid = uid;
+ user_info->screen_viewer_list = NULL;
+ user_info->app_screen_list = NULL;
+
+ return user_info;
+}
+
+static bundle *__create_bundle(struct app_screen_s *app_screen,
+ const char *event)
+{
+ bundle *b;
+
+ b = bundle_create();
+ if (b == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ bundle_add_str(b, "__AUL_SC_EVENT__", event);
+ bundle_add_str(b, "__AUL_SC_APPID__", app_screen->appid);
+ bundle_add_byte(b, "__AUL_SC_PID__", &app_screen->pid, sizeof(int));
+ bundle_add_byte(b, "__AUL_SC_SURFACE__",
+ &app_screen->surf, sizeof(unsigned int));
+ bundle_add_str(b, "__AUL_SC_INSTANCE_ID__", app_screen->instance_id);
+
+ return b;
+}
+
+static void __send_app_screen_event(struct viewer_info_s *viewer_info,
+ struct app_screen_s *app_screen, const char *event)
+{
+ bundle *b;
+ char endpoint[128];
+
+ b = __create_bundle(app_screen, event);
+ if (b == NULL) {
+ _E("out of memory");
+ return;
+ }
+
+ snprintf(endpoint, sizeof(endpoint), "app_screen_event:%u:%d",
+ viewer_info->ref, viewer_info->pid);
+ _app_com_send(endpoint, app_screen->pid, b, app_screen->uid);
+ bundle_free(b);
+}
+
+static void __send_app_screen_added(gpointer data, gpointer user_data)
+{
+ struct viewer_info_s *viewer_info = (struct viewer_info_s *)data;
+ struct app_screen_s *app_screen = (struct app_screen_s *)user_data;
+
+ if (viewer_info->pid == app_screen->pid)
+ return;
+ if (viewer_info->priv && viewer_info->pid != app_screen->caller_pid)
+ return;
+ if (!(viewer_info->screen_type & app_screen->screen_type))
+ return;
+ __send_app_screen_event(viewer_info, app_screen, "add_screen");
+}
+
+static void __send_app_screen_removed(gpointer data, gpointer user_data)
+{
+ struct viewer_info_s *viewer_info = (struct viewer_info_s *)data;
+ struct app_screen_s *app_screen = (struct app_screen_s *)user_data;
+
+ if (viewer_info->pid == app_screen->pid)
+ return;
+ if (viewer_info->priv && viewer_info->pid != app_screen->caller_pid)
+ return;
+ if (!(viewer_info->screen_type & app_screen->screen_type))
+ return;
+ __send_app_screen_event(viewer_info, app_screen, "remove_screen");
+}
+
+static void __send_app_screen_updated(gpointer data, gpointer user_data)
+{
+ struct viewer_info_s *viewer_info = (struct viewer_info_s *)data;
+ struct app_screen_s *app_screen = (struct app_screen_s *)user_data;
+
+ if (viewer_info->pid == app_screen->pid)
+ return;
+ if (viewer_info->priv && viewer_info->pid != app_screen->caller_pid)
+ return;
+ if (!(viewer_info->screen_type & app_screen->screen_type))
+ return;
+ __send_app_screen_event(viewer_info, app_screen, "update_screen");
+}
+
+static gint __compare_app_screen_instance_id(gconstpointer a, gconstpointer b)
+{
+ struct app_screen_s *app_screen = (struct app_screen_s *)a;
+ const char *instance_id = (const char *)b;
+
+ if (strcmp(app_screen->instance_id, instance_id) == 0)
+ return 0;
+
+ return -1;
+}
+
+unsigned int _screen_connector_get_surface_id(const char *instance_id,
+ uid_t uid)
+{
+ struct user_info_s *user_info;
+ struct app_screen_s *app_screen;
+ GList *found;
+
+ if (instance_id == NULL)
+ return 0;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL)
+ return 0;
+
+ found = g_list_find_custom(user_info->app_screen_list,
+ instance_id, __compare_app_screen_instance_id);
+ if (found) {
+ app_screen = (struct app_screen_s *)found->data;
+ return app_screen->surf;
+ }
+
+ return 0;
+}
+
+static int __get_screen_type(int app_type)
+{
+ switch (app_type) {
+ case AT_UI_APP:
+ return AUL_SCREEN_TYPE_UI;
+ case AT_WIDGET_APP:
+ return AUL_SCREEN_TYPE_WIDGET;
+ case AT_WATCH_APP:
+ return AUL_SCREEN_TYPE_WATCH;
+ default:
+ return -1;
+ }
+}
+
+static int __get_pid_by_surf(int pid, unsigned int surf)
+{
+ int *pids = NULL;
+ int cnt = 0;
+ int i;
+ unsigned int wid;
+
+ _app_group_get_group_pids(pid, &cnt, &pids);
+ for (i = 0; i < cnt; ++i) {
+ wid = (unsigned int)_app_group_get_window(pids[i]);
+ if (wid == surf) {
+ _D("pid(%d), surf(%u)", pids[i], surf);
+ pid = pids[i];
+ }
+ }
+ free(pids);
+
+ return pid;
+}
+
+static gboolean __suspend_timer(gpointer data)
+{
+ int pid = GPOINTER_TO_INT(data);
+ int ret;
+
+ if (pid < 1)
+ return FALSE;
+
+ ret = _suspend_update_status(pid, SUSPEND_STATUS_INCLUDE);
+ _D("pid(%d), result(%d)", pid, ret);
+
+ return FALSE;
+}
+
+static gint __compare_app_screen_surf(gconstpointer a, gconstpointer b)
+{
+ struct app_screen_s *app_screen = (struct app_screen_s *)a;
+ unsigned int surf = GPOINTER_TO_UINT(b);
+
+ if (app_screen->surf == surf)
+ return 0;
+
+ return -1;
+}
+
+const char *_screen_connector_get_appid_by_surface_id(unsigned int surf,
+ uid_t uid)
+{
+ struct user_info_s *user_info;
+ struct app_screen_s *app_screen;
+ GList *found;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL)
+ return NULL;
+
+ found = g_list_find_custom(user_info->app_screen_list,
+ GUINT_TO_POINTER(surf), __compare_app_screen_surf);
+ if (found) {
+ app_screen = (struct app_screen_s *)found->data;
+ return app_screen->appid;
+ }
+
+ return NULL;
+}
+
+const char *_screen_connector_get_instance_id_by_surface_id(unsigned int surf,
+ uid_t uid)
+{
+ struct user_info_s *user_info;
+ struct app_screen_s *app_screen;
+ GList *found;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL)
+ return NULL;
+
+ found = g_list_find_custom(user_info->app_screen_list,
+ GUINT_TO_POINTER(surf), __compare_app_screen_surf);
+ if (found) {
+ app_screen = (struct app_screen_s *)found->data;
+ return app_screen->instance_id;
+ }
+
+ return NULL;
+}
+
+/* TODO: The provider_appid should be provider_instance_id. */
+static int __send_viewer_visibility_to_provider(const char *provider_appid,
+ aul_screen_status_e status, int viewer_pid, uid_t viewer_uid)
+{
+ bundle *b;
+
+ b = bundle_create();
+ if (b == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ bundle_add_byte(b, "__AUL_SC_VIEWER_STATUS__",
+ &status, sizeof(aul_screen_status_e));
+ _app_com_send(provider_appid, viewer_pid, b, viewer_uid);
+ bundle_free(b);
+ _D("send viewer status to %s(%d)", provider_appid, status);
+
+ return 0;
+}
+
+static gint __compare_viewer_pid(gconstpointer a, gconstpointer b)
+{
+ struct viewer_info_s *viewer_info = (struct viewer_info_s *)a;
+ int pid = GPOINTER_TO_INT(b);
+
+ if (viewer_info->pid == pid)
+ return 0;
+
+ return -1;
+}
+
+int _screen_connector_update_screen_viewer_status(int pid, int status,
+ unsigned int surf, uid_t uid)
+{
+ struct user_info_s *user_info;
+ struct app_screen_s *app_screen;
+ struct viewer_info_s *viewer_info;
+ bool send_pause = true;
+ GList *found;
+ GList *iter;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL)
+ return -1;
+
+ found = g_list_find_custom(user_info->screen_viewer_list,
+ GINT_TO_POINTER(pid), __compare_viewer_pid);
+ if (found == NULL)
+ return -1;
+
+ viewer_info = (struct viewer_info_s *)found->data;
+ viewer_info->status = status;
+
+ found = g_list_find_custom(user_info->app_screen_list,
+ GUINT_TO_POINTER(surf), __compare_app_screen_surf);
+ if (found == NULL)
+ return -1;
+
+ app_screen = (struct app_screen_s *)found->data;
+ found = g_list_find(app_screen->viewer_list, viewer_info);
+ if (!found) {
+ app_screen->viewer_list = g_list_append(app_screen->viewer_list,
+ viewer_info);
+ }
+
+ found = g_list_find(viewer_info->watch_list, app_screen);
+ if (!found) {
+ viewer_info->watch_list = g_list_append(viewer_info->watch_list,
+ app_screen);
+ }
+
+ if (status == AUL_SCREEN_STATUS_PAUSE) {
+ iter = app_screen->viewer_list;
+ while (iter) {
+ viewer_info = (struct viewer_info_s *)iter->data;
+ if (viewer_info->status != AUL_SCREEN_STATUS_PAUSE) {
+ /*
+ * Every veiwer must be paused to send
+ * viewer pause event to provider
+ */
+ send_pause = false;
+ break;
+ }
+ iter = g_list_next(iter);
+ }
+ if (send_pause) {
+ __send_viewer_visibility_to_provider(app_screen->appid,
+ status, pid, uid);
+ }
+ } else if (status == AUL_SCREEN_STATUS_RESUME) {
+ __send_viewer_visibility_to_provider(app_screen->appid, status,
+ pid, uid);
+ } else {
+ _W("Unknown status(%d)", status);
+ }
+
+ return 0;
+}
+
+int _screen_connector_send_update_request(const char *appid,
+ const char *instance_id, uid_t uid)
+{
+ app_status_h app_status;
+ struct user_info_s *user_info;
+ struct app_screen_s *app_screen;
+ int dummy = 0;
+ int pid;
+ int ret;
+ GList *found;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL)
+ return -1;
+
+ if (instance_id) {
+ app_status = _app_status_find_by_instance_id(appid,
+ instance_id, uid);
+ } else {
+ app_status = _app_status_find_by_appid(appid, uid);
+ }
+ if (app_status == NULL)
+ return -1;
+ if (_app_status_get_status(app_status) == STATUS_DYING)
+ return -1;
+ if (_app_status_get_app_type(app_status) != AT_UI_APP)
+ return -1;
+ if (_app_status_is_home_app(app_status))
+ return -1;
+ if (instance_id == NULL) {
+ instance_id = _app_status_get_instance_id(app_status);
+ if (instance_id == NULL)
+ return -1;
+ }
+
+ found = g_list_find_custom(user_info->app_screen_list, instance_id,
+ __compare_instance_id);
+ if (found == NULL)
+ return -1;
+
+ app_screen = (struct app_screen_s *)found->data;
+ pid = __get_pid_by_surf(app_screen->pid, app_screen->surf);
+ ret = _suspend_update_status(pid, SUSPEND_STATUS_EXCLUDE);
+ if (ret < 0)
+ return -1;
+
+ ret = aul_sock_send_raw(pid, uid, APP_UPDATE_REQUESTED,
+ (unsigned char *)&dummy, 0, AUL_SOCK_NOREPLY);
+ if (ret < 0) {
+ _E("Failed to send the update request");
+ _suspend_update_status(pid, SUSPEND_STATUS_INCLUDE);
+ return -1;
+ }
+ g_timeout_add_seconds(SUSPEND_INTERVAL, __suspend_timer,
+ GINT_TO_POINTER(pid));
+ _D("pid(%d), uid(%d)", pid, uid);
+
+ return 0;
+}
+
+int _screen_connector_add_app_screen(int pid, unsigned int surf,
+ const char *instance_id, uid_t uid)
+{
+ app_status_h app_status;
+ const char *appid;
+ struct user_info_s *user_info;
+ struct app_screen_s *app_screen;
+ int caller_pid;
+ int leader_pid;
+ int app_type;
+ int screen_type;
+ GList *found;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL)
+ return -1;
+
+ leader_pid = _app_group_get_leader_pid(pid);
+ if (leader_pid > 0)
+ pid = leader_pid;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ _W("Failed to find app status info - pid(%d), uid(%d)",
+ pid, uid);
+ return -1;
+ }
+
+ if (_app_status_is_home_app(app_status))
+ return 0;
+
+ appid = _app_status_get_appid(app_status);
+ if (instance_id == NULL) {
+ instance_id = _app_status_get_instance_id(app_status);
+ if (instance_id == NULL)
+ return -1;
+ }
+
+ found = g_list_find_custom(user_info->app_screen_list, instance_id,
+ __compare_instance_id);
+ if (found) {
+ app_screen = (struct app_screen_s *)found->data;
+ if (app_screen->surf == surf) {
+ _D("Already exists");
+ return 0;
+ }
+
+ app_screen->surf = surf;
+ g_list_foreach(user_info->screen_viewer_list,
+ __send_app_screen_updated, app_screen);
+ return 0;
+ }
+
+ caller_pid = _app_status_get_org_caller_pid(app_status);
+ app_type = _app_status_get_app_type(app_status);
+ screen_type = __get_screen_type(app_type);
+ app_screen = __create_app_screen(pid, uid, appid, surf, instance_id,
+ screen_type, caller_pid);
+ if (app_screen == NULL)
+ return -1;
+
+ user_info->app_screen_list = g_list_append(user_info->app_screen_list,
+ app_screen);
+ g_list_foreach(user_info->screen_viewer_list,
+ __send_app_screen_added, app_screen);
+ _D("pid(%d), appid(%s), surf(%d), uid(%d)", pid, appid, surf, uid);
+
+ return 0;
+}
+
+int _screen_connector_remove_app_screen(int pid, const char *instance_id,
+ uid_t uid)
+{
+ struct user_info_s *user_info;
+ struct app_screen_s *app_screen;
+ app_status_h app_status;
+ int leader_pid;
+ GList *found;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL)
+ return -1;
+
+ leader_pid = _app_group_get_leader_pid(pid);
+ if (leader_pid > 0)
+ pid = leader_pid;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ _W("Failed to find app status info - pid(%d), uid(%d)",
+ pid, uid);
+ return -1;
+ }
+
+ if (_app_status_is_home_app(app_status))
+ return 0;
+
+ if (instance_id == NULL) {
+ instance_id = _app_status_get_instance_id(app_status);
+ if (instance_id == NULL)
+ return -1;
+ }
+
+ found = g_list_find_custom(user_info->app_screen_list, instance_id,
+ __compare_instance_id);
+ if (found == NULL)
+ return -1;
+
+ app_screen = (struct app_screen_s *)found->data;
+ g_list_foreach(user_info->screen_viewer_list,
+ __send_app_screen_removed, app_screen);
+ user_info->app_screen_list = g_list_remove(user_info->app_screen_list,
+ app_screen);
+ __destroy_app_screen(app_screen);
+ _D("pid(%d), instance_id(%s)", pid, instance_id);
+
+ return 0;
+}
+
+static gint __compare_viewers(gconstpointer a, gconstpointer b)
+{
+ struct viewer_info_s *viewer_a = (struct viewer_info_s *)a;
+ struct viewer_info_s *viewer_b = (struct viewer_info_s *)b;
+
+ if (viewer_a->pid == viewer_b->pid &&
+ viewer_a->screen_type == viewer_b->screen_type &&
+ viewer_a->priv == viewer_b->priv &&
+ viewer_a->ref == viewer_b->ref)
+ return 0;
+
+ return -1;
+}
+
+int _screen_connector_update_app_screen(int pid, unsigned int surf, uid_t uid)
+{
+ app_status_h app_status;
+ struct user_info_s *user_info;
+ struct app_screen_s *app_screen;
+ const char *appid;
+ const char *instance_id;
+ int leader_pid;
+ GList *found;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL)
+ return -1;
+
+ leader_pid = _app_group_get_leader_pid(pid);
+ if (leader_pid > 0)
+ pid = leader_pid;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ _W("Failed to find app status info - pid(%d), uid(%d)",
+ pid, uid);
+ return -1;
+ }
+
+ if (_app_status_is_home_app(app_status))
+ return 0;
+
+ appid = _app_status_get_appid(app_status);
+ instance_id = _app_status_get_instance_id(app_status);
+ if (instance_id == NULL)
+ return -1;
+
+ found = g_list_find_custom(user_info->app_screen_list, instance_id,
+ __compare_instance_id);
+ if (found == NULL)
+ return -1;
+
+ app_screen = (struct app_screen_s *)found->data;
+ if (app_screen->surf == surf)
+ return 0;
+
+ app_screen->surf = surf;
+ g_list_foreach(user_info->screen_viewer_list,
+ __send_app_screen_updated, app_screen);
+ _D("pid(%d), appid(%s), surf(%d), uid(%d)", pid, appid, surf, uid);
+
+ return 0;
+}
+
+int _screen_connector_remove_app_screen_v2(int pid, uid_t uid)
+{
+ struct user_info_s *user_info;
+ struct app_screen_s *app_screen;
+ GList *iter;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL)
+ return -1;
+
+ iter = g_list_first(user_info->app_screen_list);
+ while (iter) {
+ app_screen = (struct app_screen_s *)iter->data;
+ iter = g_list_next(iter);
+ if (app_screen && app_screen->pid == pid) {
+ _D("pid(%d), surf(%d)", pid, app_screen->surf);
+ g_list_foreach(user_info->screen_viewer_list,
+ __send_app_screen_removed, app_screen);
+ user_info->app_screen_list = g_list_remove(
+ user_info->app_screen_list,
+ app_screen);
+ __destroy_app_screen(app_screen);
+ }
+ }
+
+ return 0;
+}
+
+static void __foreach_app_screen_list(gpointer data, gpointer user_data)
+{
+ __send_app_screen_added(user_data, data);
+}
+
+int _screen_connector_add_screen_viewer(int pid, int screen_type,
+ bool priv, unsigned int ref, uid_t uid)
+{
+ app_status_h app_status;
+ struct user_info_s *user_info;
+ struct viewer_info_s *viewer_info;
+ GList *list;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL) {
+ _W("Failed to find app status info - pid(%d)", pid);
+ return -1;
+ }
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL) {
+ _W("user info is empty");
+ return -1;
+ }
+
+ viewer_info = __create_viewer_info(pid, screen_type, priv, ref);
+ if (viewer_info == NULL)
+ return -1;
+
+ list = g_list_find_custom(user_info->screen_viewer_list, viewer_info,
+ __compare_viewers);
+ if (list) {
+ _D("Already exists");
+ __destroy_viewer_info(viewer_info);
+ return 0;
+ }
+
+ user_info->screen_viewer_list = g_list_append(
+ user_info->screen_viewer_list, viewer_info);
+
+ g_list_foreach(user_info->app_screen_list,
+ __foreach_app_screen_list, viewer_info);
+ _D("pid(%d), screen_type(%d), private(%d), ref(%u), uid(%d)",
+ pid, screen_type, priv, ref, uid);
+
+ return 0;
+}
+
+int _screen_connector_remove_screen_viewer(int pid, int screen_type,
+ bool priv, unsigned int ref, uid_t uid)
+{
+ struct user_info_s *user_info;
+ struct viewer_info_s *viewer_info;
+ GList *iter;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL) {
+ _W("user info is empty");
+ return -1;
+ }
+
+ iter = g_list_first(user_info->screen_viewer_list);
+ while (iter) {
+ viewer_info = (struct viewer_info_s *)iter->data;
+ iter = g_list_next(iter);
+ if (viewer_info->pid == pid &&
+ viewer_info->screen_type == screen_type &&
+ viewer_info->priv == priv &&
+ viewer_info->ref == ref) {
+ user_info->screen_viewer_list = g_list_remove(
+ user_info->screen_viewer_list,
+ viewer_info);
+ __destroy_viewer_info(viewer_info);
+ }
+ }
+
+ _D("pid(%d), screen_type(%d), private(%d), ref(%u) uid(%d)",
+ pid, screen_type, priv, ref, uid);
+
+ return 0;
+}
+
+int _screen_connector_remove_screen_viewer_v2(int pid, uid_t uid)
+{
+ struct user_info_s *user_info;
+ struct viewer_info_s *viewer_info;
+ GList *iter;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info == NULL) {
+ _W("user info is empty");
+ return -1;
+ }
+
+ iter = g_list_first(user_info->screen_viewer_list);
+ while (iter) {
+ viewer_info = (struct viewer_info_s *)iter->data;
+ iter = g_list_next(iter);
+ if (viewer_info->pid == pid) {
+ user_info->screen_viewer_list = g_list_remove(
+ user_info->screen_viewer_list,
+ viewer_info);
+ __destroy_viewer_info(viewer_info);
+ }
+ }
+
+ return 0;
+}
+
+int _screen_connector_usr_init(uid_t uid)
+{
+ struct user_info_s *user_info;
+
+ user_info = g_hash_table_lookup(user_table, GUINT_TO_POINTER(uid));
+ if (user_info) {
+ _E("Already exists");
+ return 0;
+ }
+
+ user_info = __create_user_info(uid);
+ if (user_info == NULL)
+ return -1;
+
+ g_hash_table_insert(user_table, GUINT_TO_POINTER(uid), user_info);
+
+ return 0;
+}
+
+void _screen_connector_usr_fini(uid_t uid)
+{
+ g_hash_table_remove(user_table, GUINT_TO_POINTER(uid));
+}
+
+int _screen_connector_init(void)
+{
+ _D("screen connector init");
+
+ user_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, __destroy_user_info);
+ if (user_table == NULL) {
+ _E("Failed to create user table");
+ return -1;
+ }
+
+ return 0;
+}
+
+void _screen_connector_fini(void)
+{
+ _D("screen connector fini");
+
+ if (user_table)
+ g_hash_table_destroy(user_table);
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <linux/limits.h>
+
+#include <glib.h>
+#include <aul.h>
+#include <aul_svc.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <tzplatform_config.h>
+#include <security-manager.h>
+
+#include "amd_util.h"
+#include "amd_appinfo.h"
+#include "amd_app_status.h"
+#include "amd_share.h"
+#include "aul_svc_priv_key.h"
+
+#define LEGACY_APP_PATH "/opt/usr/apps/"
+
+struct shared_info_main_s {
+ char *appid;
+ uid_t uid;
+ shared_info_t *shared_info;
+};
+
+static int __can_share(const char *path, const char *pkgid, uid_t uid)
+{
+ struct stat path_stat;
+ char buf[PATH_MAX];
+
+ if (stat(path, &path_stat) != 0) {
+ _E("failed to stat file to share (%s, %d)", path, errno);
+ return -1;
+ }
+
+ if (!S_ISREG(path_stat.st_mode)) {
+ _E("file is not a regular file (%s)", path);
+ return -1;
+ }
+
+ tzplatform_set_user(uid);
+ snprintf(buf, sizeof(buf), "%s/%s/data/",
+ tzplatform_getenv(TZ_USER_APP), pkgid);
+ tzplatform_reset_user();
+
+ if (strncmp(path, buf, strlen(buf)) != 0) {
+ SECURE_LOGD("file is not in app's data directory (%s)", path);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __get_owner_pid(int caller_pid, bundle *kb)
+{
+ char *org_caller = NULL;
+ const char *appid;
+ int org_caller_pid;
+ app_status_h app_status;
+ int ret;
+
+ ret = bundle_get_str(kb, AUL_K_ORG_CALLER_PID, &org_caller);
+ if (ret != BUNDLE_ERROR_NONE)
+ return caller_pid;
+
+ org_caller_pid = atoi(org_caller);
+ app_status = _app_status_find(caller_pid);
+ appid = _app_status_get_appid(app_status);
+ if (appid && (strcmp(APP_SELECTOR, appid) == 0 ||
+ strcmp(SHARE_PANEL, appid) == 0))
+ caller_pid = org_caller_pid;
+
+ return caller_pid;
+}
+
+static const char *__get_owner_appid(int caller_pid, bundle *kb)
+{
+ const char *owner_appid;
+ int owner_pid = -1;
+ app_status_h app_status;
+
+ owner_pid = __get_owner_pid(caller_pid, kb);
+ owner_pid = getpgid(owner_pid); /* for webapp */
+ app_status = _app_status_find(owner_pid);
+ owner_appid = _app_status_get_appid(app_status);
+
+ return owner_appid;
+}
+
+static shared_info_h __new_shared_info_handle(const char *appid, uid_t uid,
+ const char *owner_appid)
+{
+ shared_info_h h;
+ int ret;
+
+ h = malloc(sizeof(struct shared_info_main_s));
+ if (h == NULL)
+ return NULL;
+
+ h->shared_info = malloc(sizeof(shared_info_t));
+ if (h->shared_info == NULL) {
+ free(h);
+ return NULL;
+ }
+
+ ret = security_manager_private_sharing_req_new(&h->shared_info->handle);
+ if (ret != SECURITY_MANAGER_SUCCESS) {
+ free(h->shared_info);
+ free(h);
+ return NULL;
+ }
+
+ h->shared_info->owner_appid = strdup(owner_appid);
+ h->appid = strdup(appid);
+ h->uid = uid;
+
+ return h;
+}
+
+static char *__convert_legacy_path(const char *path, uid_t uid)
+{
+ char buf[PATH_MAX];
+ int len = strlen(LEGACY_APP_PATH);
+
+ if (strncmp(LEGACY_APP_PATH, path, len) == 0) {
+ tzplatform_set_user(uid);
+ snprintf(buf, sizeof(buf), "%s/%s",
+ tzplatform_getenv(TZ_USER_APP), &path[len]);
+ tzplatform_reset_user();
+
+ return strdup(buf);
+ }
+
+ return strdup(path);
+}
+
+static GList *__add_valid_uri(GList *paths, int caller_pid, const char *appid,
+ const char *owner_appid, bundle *kb, uid_t uid)
+{
+ char *path = NULL;
+ const char *pkgid;
+ const struct appinfo *ai;
+ int ret;
+
+ ret = bundle_get_str(kb, AUL_SVC_K_URI, &path);
+ if (ret != BUNDLE_ERROR_NONE)
+ return paths;
+
+ if (!path) {
+ _D("path was null");
+ return paths;
+ }
+
+ if (strncmp(path, "file://", 7) == 0) {
+ path = &path[7];
+ } else {
+ _E("file wasn't started with file://");
+ return paths;
+ }
+
+ ai = _appinfo_find(uid, owner_appid);
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+
+ path = __convert_legacy_path(path, uid);
+ if (__can_share(path, pkgid, uid) != 0) {
+ _E("__can_share() returned an error");
+ free(path);
+ return paths;
+ }
+ paths = g_list_append(paths, path);
+
+ return paths;
+}
+
+static GList *__add_valid_key_for_data_selected(GList *paths, int caller_pid,
+ const char *appid, const char *owner_appid, bundle *kb,
+ uid_t uid)
+{
+ int i;
+ int len = 0;
+ const char **path_array = NULL;
+ char *path_str;
+ int type = bundle_get_type(kb, AUL_SVC_DATA_SELECTED);
+ const char *pkgid = NULL;
+ const struct appinfo *ai = NULL;
+
+ if (type != BUNDLE_TYPE_STR_ARRAY)
+ return paths;
+
+ path_array = bundle_get_str_array(kb, AUL_SVC_DATA_SELECTED, &len);
+ if (!path_array || len <= 0) {
+ _E("path_array was null");
+ return paths;
+ }
+
+ ai = _appinfo_find(uid, owner_appid);
+ if (ai == NULL) {
+ _E("appinfo is NULL");
+ return paths;
+ }
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ if (pkgid == NULL) {
+ _E("pkgid was null");
+ return paths;
+ }
+
+ for (i = 0; i < len; i++) {
+ path_str = __convert_legacy_path(path_array[i], uid);
+ if (__can_share(path_str, pkgid, uid) == 0)
+ paths = g_list_append(paths, path_str);
+ else
+ free(path_str);
+ }
+
+ return paths;
+}
+
+static GList *__add_valid_key_for_data_path(GList *paths, int caller_pid,
+ const char *appid, const char *owner_appid, bundle *kb,
+ uid_t uid)
+{
+ int type = bundle_get_type(kb, AUL_SVC_DATA_PATH);
+ char *path = NULL;
+ const char **path_array = NULL;
+ int len;
+ int i;
+ const char *pkgid = NULL;
+ const struct appinfo *ai = NULL;
+ char *path_str;
+
+ switch (type) {
+ case BUNDLE_TYPE_STR:
+ bundle_get_str(kb, AUL_SVC_DATA_PATH, &path);
+ if (!path) {
+ _E("path was null");
+ break;
+ }
+
+ ai = _appinfo_find(uid, owner_appid);
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ if (pkgid == NULL) {
+ _E("pkgid was null");
+ break;
+ }
+
+ path = __convert_legacy_path(path, uid);
+ if (__can_share(path, pkgid, uid) != 0) {
+ _E("__can_share() returned an error");
+ free(path);
+ break;
+ }
+
+ paths = g_list_append(paths, path);
+ break;
+ case BUNDLE_TYPE_STR_ARRAY:
+ path_array = bundle_get_str_array(kb, AUL_SVC_DATA_PATH, &len);
+ if (!path_array || len <= 0) {
+ _E("path_array was null");
+ break;
+ }
+
+ ai = _appinfo_find(uid, owner_appid);
+ pkgid = _appinfo_get_value(ai, AIT_PKGID);
+ if (pkgid == NULL) {
+ _E("pkgid was null");
+ break;
+ }
+
+ for (i = 0; i < len; i++) {
+ path_str = __convert_legacy_path(path_array[i], uid);
+ if (__can_share(path_str, pkgid, uid) == 0)
+ paths = g_list_append(paths, path_str);
+ else
+ free(path_str);
+ }
+
+ break;
+ }
+
+ return paths;
+}
+
+static char **__convert_list_to_array(GList *list)
+{
+ int len;
+ int i = 0;
+ char **array;
+
+ if (list == NULL)
+ return NULL;
+
+ len = g_list_length(list);
+ if (len == 0)
+ return NULL;
+
+ array = (char **)g_malloc(sizeof(char *) * (len + 1));
+ if (array == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ while (list) {
+ array[i] = g_strdup(list->data);
+ list = g_list_next(list);
+ i++;
+ }
+ array[len] = NULL;
+
+ return array;
+}
+
+shared_info_h _temporary_permission_create(int caller_pid, const char *appid,
+ bundle *kb, uid_t uid)
+{
+ char **path_array = NULL;
+ int len;
+ const char *owner_appid = NULL;
+ GList *paths = NULL;
+ shared_info_h h = NULL;
+ int r;
+
+ owner_appid = __get_owner_appid(caller_pid, kb);
+ paths = __add_valid_key_for_data_path(paths, caller_pid, appid,
+ owner_appid, kb, uid);
+ paths = __add_valid_key_for_data_selected(paths, caller_pid, appid,
+ owner_appid, kb, uid);
+ paths = __add_valid_uri(paths, caller_pid, appid, owner_appid, kb, uid);
+ if (!paths || !owner_appid)
+ goto clear;
+
+ _D("grant permission %s : %s", owner_appid, appid);
+
+ h = __new_shared_info_handle(appid, uid, owner_appid);
+ if (h == NULL)
+ goto clear;
+
+ len = g_list_length(paths);
+ path_array = __convert_list_to_array(paths);
+ if (path_array == NULL)
+ goto clear;
+
+ r = security_manager_private_sharing_req_set_owner_appid(
+ h->shared_info->handle, owner_appid);
+ if (r != SECURITY_MANAGER_SUCCESS)
+ _E("Failed to set owner appid(%s) %d", owner_appid, r);
+
+ r = security_manager_private_sharing_req_set_target_appid(
+ h->shared_info->handle, appid);
+ if (r != SECURITY_MANAGER_SUCCESS)
+ _E("Failed to set target appid(%s) %d", appid, r);
+
+ r = security_manager_private_sharing_req_add_paths(
+ h->shared_info->handle, (const char **)path_array, len);
+ if (r != SECURITY_MANAGER_SUCCESS)
+ _E("Failed to add paths %d", r);
+
+ _D("security_manager_private_sharing_apply ++");
+ r = security_manager_private_sharing_apply(h->shared_info->handle);
+ _D("security_manager_private_sharing_apply --");
+ if (r != SECURITY_MANAGER_SUCCESS) {
+ _E("Failed to apply private sharing %d", r);
+ _temporary_permission_destroy(h);
+ h = NULL;
+ }
+
+clear:
+ if (paths)
+ g_list_free_full(paths, free);
+
+ if (path_array)
+ g_strfreev(path_array);
+
+ return h;
+}
+
+int _temporary_permission_apply(int pid, uid_t uid, shared_info_h handle)
+{
+ int ret;
+ app_status_h app_status;
+
+ if (handle == NULL)
+ return -1;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return -1;
+
+ ret = _app_status_add_shared_info(app_status, handle->shared_info);
+ if (ret != 0)
+ return ret;
+
+ handle->shared_info = NULL;
+
+ return 0;
+}
+
+int _temporary_permission_destroy(shared_info_h handle)
+{
+ int r;
+
+ if (handle == NULL)
+ return -1;
+
+ if (handle->shared_info) { /* back out */
+ _D("revoke permission %s : %s",
+ handle->shared_info->owner_appid,
+ handle->appid);
+ r = security_manager_private_sharing_drop(
+ handle->shared_info->handle);
+ if (r != SECURITY_MANAGER_SUCCESS)
+ _E("revoke error %d", r);
+
+ security_manager_private_sharing_req_free(
+ handle->shared_info->handle);
+ free(handle->shared_info->owner_appid);
+ }
+
+ free(handle->appid);
+ free(handle);
+
+ return 0;
+}
+
+int _temporary_permission_drop(int pid, uid_t uid)
+{
+ int r;
+ shared_info_t *sit;
+ app_status_h app_status;
+ GList *list;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return -1;
+
+ list = _app_status_get_shared_info_list(app_status);
+ if (!list) {
+ _D("list was null");
+ return -1;
+ }
+
+ while (list) {
+ sit = (shared_info_t *)list->data;
+ _D("revoke permission %s : %d", sit->owner_appid, pid);
+ r = security_manager_private_sharing_drop(sit->handle);
+ if (r != SECURITY_MANAGER_SUCCESS)
+ _E("revoke error %d", r);
+ security_manager_private_sharing_req_free(sit->handle);
+ list = g_list_next(list);
+ }
+
+ return _app_status_clear_shared_info_list(app_status);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+
+#include <gio/gio.h>
+#include <glib.h>
+
+#include "app_signal.h"
+#include "amd_util.h"
+#include "amd_signal.h"
+#include "amd_cooldown.h"
+
+#define MAX_LABEL_BUFSZ 1024
+#define SIGNAL_INIT_INTERVAL 3
+
+struct signal_initializer {
+ int (*callback)(void *data);
+ void *data;
+};
+
+static GDBusConnection *system_conn;
+static GList *signal_init_list;
+static guint startup_finished_sid;
+static guint user_session_startup_finished_sid;
+static int (*startup_finished_callback)(uid_t, void *);
+static void *startup_finished_data;
+static uid_t startup_finished_uid;
+static bool system_boot_completed;
+static bool user_boot_completed;
+
+static GDBusConnection *__get_system_conn(void)
+{
+ GError *err = NULL;
+
+ if (system_conn)
+ return system_conn;
+
+ system_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+ if (system_conn == NULL) {
+ _E("g_bus_get_sync() is failed: %s", err->message);
+ g_error_free(err);
+ return NULL;
+ }
+
+ return system_conn;
+}
+
+int _signal_send_watchdog(int pid, int signal_num)
+{
+ GError *err = NULL;
+ GDBusConnection *conn;
+
+ if (_cooldown_get_status() == COOLDOWN_LIMIT) {
+ _E("cooldown status:LimitAction");
+ _E("watchdog signal already sent for pid %d", pid);
+ return -1;
+ }
+
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ if (g_dbus_connection_emit_signal(conn,
+ NULL,
+ RESOURCED_PROC_OBJECT,
+ RESOURCED_PROC_INTERFACE,
+ RESOURCED_PROC_WATCHDOG_SIGNAL,
+ g_variant_new("(ii)", pid, signal_num),
+ &err) == FALSE) {
+ _E("g_dbus_connection_emit_signal() is failed: %s",
+ err->message);
+ g_error_free(err);
+ return -1;
+ }
+
+ if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
+ _E("g_dbus_connection_flush_sync() is failed: %s",
+ err->message);
+ g_error_free(err);
+ return -1;
+ }
+
+ _W("send a watchdog signal done: %d", pid);
+
+ return 0;
+}
+
+int _signal_send_proc_prelaunch(const char *appid, const char *pkgid,
+ int attribute, int category)
+{
+ GError *err = NULL;
+ GVariant *param;
+ GDBusConnection *conn;
+
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ param = g_variant_new("(ssii)", appid, pkgid, attribute, category);
+ if (g_dbus_connection_emit_signal(conn,
+ NULL,
+ RESOURCED_PROC_OBJECT,
+ RESOURCED_PROC_INTERFACE,
+ RESOURCED_PROC_PRELAUNCH_SIGNAL,
+ param,
+ &err) == FALSE) {
+ _E("g_dbus_connection_emit_signal() is failed: %s",
+ err->message);
+ g_error_free(err);
+ return -1;
+ }
+
+ if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
+ _E("g_dbus_connection_flush_sync() is failed: %s",
+ err->message);
+ g_error_free(err);
+ return -1;
+ }
+
+ _W("send a prelaunch signal done: " \
+ "appid(%s) pkgid(%s) attribute(%x) category(%x)",
+ appid, pkgid, attribute, category);
+
+ return 0;
+}
+
+int _signal_send_tep_mount(char *mnt_path[], const char *pkgid)
+{
+ GError *err = NULL;
+ GDBusMessage *msg;
+ GDBusConnection *conn;
+ int ret = 0;
+ int rv = 0;
+ struct stat link_buf = {0,};
+ GVariant *param;
+ char buf[MAX_LABEL_BUFSZ];
+
+ if (pkgid == NULL) {
+ _E("Invalid parameter");
+ return -1;
+ }
+
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ rv = lstat(mnt_path[0], &link_buf);
+ if (rv == 0) {
+ rv = unlink(mnt_path[0]);
+ if (rv)
+ _E("Unable tp remove link file %s", mnt_path[0]);
+ }
+
+ msg = g_dbus_message_new_method_call(TEP_BUS_NAME,
+ TEP_OBJECT_PATH,
+ TEP_INTERFACE_NAME,
+ TEP_MOUNT_METHOD);
+ if (msg == NULL) {
+ _E("g_dbus_message_new_method_call() is failed.");
+ return -1;
+ }
+
+ snprintf(buf, sizeof(buf), "User::Pkg::%s::RO", pkgid);
+ param = g_variant_new("(sss)", mnt_path[0], mnt_path[1], buf);
+ g_dbus_message_set_body(msg, param);
+
+ if (g_dbus_connection_send_message(conn,
+ msg,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ NULL,
+ &err) == FALSE) {
+ _E("g_dbus_connection_send_message() is failed: %s",
+ err->message);
+ ret = -1;
+ }
+
+ if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
+ _E("g_dbus_connection_flush_sync() is failed: %s",
+ err->message);
+ ret = -1;
+ }
+
+ g_object_unref(msg);
+ g_clear_error(&err);
+
+ return ret;
+}
+
+int _signal_send_tep_unmount(const char *mnt_path)
+{
+ GError *err = NULL;
+ GDBusMessage *msg;
+ GDBusConnection *conn;
+
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ msg = g_dbus_message_new_method_call(TEP_BUS_NAME,
+ TEP_OBJECT_PATH,
+ TEP_INTERFACE_NAME,
+ TEP_UNMOUNT_METHOD);
+ if (msg == NULL) {
+ _E("g_dbus_message_new_method_call() is failed.");
+ return -1;
+ }
+
+ g_dbus_message_set_body(msg, g_variant_new("(s)", mnt_path));
+ if (g_dbus_connection_send_message(conn,
+ msg,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ NULL,
+ &err) == FALSE) {
+ _E("g_dbus_connection_send_message() is failed: %s",
+ err->message);
+ g_object_unref(msg);
+ g_clear_error(&err);
+ return -1;
+ }
+
+ g_dbus_connection_flush(conn, NULL, NULL, NULL);
+ g_object_unref(msg);
+ g_clear_error(&err);
+
+ return 0;
+}
+
+int _signal_send_proc_suspend(int pid)
+{
+ GError *err = NULL;
+ GDBusConnection *conn;
+
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ if (g_dbus_connection_emit_signal(conn,
+ NULL,
+ APPFW_SUSPEND_HINT_PATH,
+ APPFW_SUSPEND_HINT_INTERFACE,
+ APPFW_SUSPEND_HINT_SIGNAL,
+ g_variant_new("(i)", pid),
+ &err) == FALSE) {
+ _E("g_dbus_connection_emit_signal() is failed: %s",
+ err->message);
+ g_error_free(err);
+ return -1;
+ }
+
+ if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
+ _E("g_dbus_connection_flush_sync() is failed: %s",
+ err->message);
+ g_error_free(err);
+ return -1;
+ }
+
+ _D("[__SUSPEND__] Send suspend hint, pid: %d", pid);
+
+ return 0;
+}
+
+int _signal_get_proc_status(const int pid, int *status, int *focused)
+{
+ GError *err = NULL;
+ GDBusMessage *message;
+ GDBusMessage *reply;
+ GVariant *var;
+ GDBusConnection *conn;
+ int proc_status = -1;
+ int proc_focus = -1;
+
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ message = g_dbus_message_new_method_call(WM_PROC_NAME,
+ WM_PROC_PATH,
+ WM_PROC_INTERFACE,
+ WM_PROC_METHOD);
+ if (message == NULL) {
+ _E("g_bus_message_new_method_call() is failed.");
+ return -1;
+ }
+
+ g_dbus_message_set_body(message, g_variant_new("(i)", pid));
+ reply = g_dbus_connection_send_message_with_reply_sync(conn,
+ message,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ &err);
+ g_dbus_connection_flush(conn, NULL, NULL, NULL);
+ g_object_unref(message);
+ if (reply == NULL) {
+ _E("g_dbus_connection_send_message_with_reply_sync failed: %s",
+ err->message);
+ g_clear_error(&err);
+ return -1;
+ }
+
+ var = g_dbus_message_get_body(reply);
+ if (var == NULL) {
+ _E("g_dbus_message_get_body() is failed");
+ g_object_unref(reply);
+ return -1;
+ }
+ g_variant_get(var, "(ii)", &proc_status, &proc_focus);
+
+ g_object_unref(reply);
+
+ if (proc_status == -1 || proc_focus == -1) {
+ _E("Failed to get proc status info");
+ return -1;
+ }
+
+ *status = proc_status;
+ *focused = proc_focus;
+ _D("pid(%d), status(%d), focused(%d)", pid, proc_status, proc_focus);
+
+ return 0;
+}
+
+static void __system_bus_signal_handler(GDBusConnection *connection,
+ const gchar *sender_name, const gchar *object_path,
+ const gchar *interface_name, const char *signal_name,
+ GVariant *parameters, gpointer user_data)
+{
+ guint64 uid = 0;
+
+ _W("[SIGNAL_HANDLER] signal(%s)", signal_name);
+ if (g_strcmp0(signal_name, SD_STARTUP_FINISHED_SIGNAL) == 0) {
+ system_boot_completed = true;
+ _D("[SIGNAL_HANDLER] system boot completed");
+ } else if (g_strcmp0(signal_name,
+ SD_USER_SESSION_STARTUP_FINISHED_SIGNAL) == 0) {
+ user_boot_completed = true;
+ g_variant_get(parameters, "(t)", &uid);
+ startup_finished_uid = (uid_t)uid;
+ _D("[SIGNAL_HANDLER] user boot completed");
+ }
+
+ if (system_boot_completed && user_boot_completed) {
+ if (startup_finished_callback) {
+ startup_finished_callback(startup_finished_uid,
+ startup_finished_data);
+ }
+
+ user_boot_completed = false;
+ }
+}
+
+static guint __subscribe_system_bus(const char *object_path,
+ const char *interface_name, const char *signal_name)
+{
+ guint sid;
+ GError *err = NULL;
+ GDBusConnection *conn;
+
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return 0;
+
+ sid = g_dbus_connection_signal_subscribe(conn,
+ NULL,
+ interface_name,
+ signal_name,
+ object_path,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ __system_bus_signal_handler,
+ NULL,
+ NULL);
+ if (sid == 0)
+ _E("g_bus_connection_signal_subscribe() is failed");
+
+ g_clear_error(&err);
+
+ return sid;
+}
+
+int _signal_subscribe_startup_finished(int (*callback)(uid_t uid, void *data),
+ void *user_data)
+{
+ if (callback == NULL)
+ return -1;
+
+ startup_finished_sid = __subscribe_system_bus(SD_OBJECT_PATH,
+ SD_MANAGER_INTERFACE,
+ SD_STARTUP_FINISHED_SIGNAL);
+ if (startup_finished_sid == 0) {
+ _E("Failed to subscribe systemd signal");
+ return -1;
+ }
+
+ user_session_startup_finished_sid = __subscribe_system_bus(
+ SD_OBJECT_PATH,
+ SD_MANAGER_INTERFACE,
+ SD_USER_SESSION_STARTUP_FINISHED_SIGNAL);
+ if (user_session_startup_finished_sid == 0) {
+ _E("Failed to subscribe systemd signal");
+ _signal_unsubscribe_startup_finished();
+ return -1;
+ }
+
+ startup_finished_callback = callback;
+ startup_finished_data = user_data;
+ _D("[SIGNAL] subscribe startup finished");
+
+ return 0;
+}
+
+int _signal_unsubscribe_startup_finished(void)
+{
+ GDBusConnection *conn;
+
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ if (!startup_finished_sid && !user_session_startup_finished_sid)
+ return 0;
+
+ if (startup_finished_sid) {
+ g_dbus_connection_signal_unsubscribe(conn,
+ startup_finished_sid);
+ startup_finished_sid = 0;
+ }
+
+ if (user_session_startup_finished_sid) {
+ g_dbus_connection_signal_unsubscribe(conn,
+ user_session_startup_finished_sid);
+ user_session_startup_finished_sid = 0;
+ }
+
+ startup_finished_callback = NULL;
+ startup_finished_data = NULL;
+ _D("[SIGNAL] unsubscribe startup finished");
+
+ return 0;
+}
+
+int _signal_send_cpu_boost(int req)
+{
+ GError *err = NULL;
+ GDBusMessage *msg;
+ GDBusConnection *conn;
+ int res = 0;
+
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ msg = g_dbus_message_new_method_call(SYSTEM_BUS_NAME,
+ SYSTEM_OBJECT_PATH,
+ SYSTEM_INTERFACE_NAME,
+ SYSTEM_METHOD_NAME);
+ if (msg == NULL) {
+ _E("g_dbus_message_new_method_call() is failed.");
+ return -1;
+ }
+
+ g_dbus_message_set_body(msg, g_variant_new("(i)", req));
+ if (g_dbus_connection_send_message(conn,
+ msg,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+ NULL,
+ &err) == FALSE) {
+ _E("g_dbus_connection_send_message() is failed(%s)",
+ err->message);
+ res = -1;
+ }
+
+ g_dbus_connection_flush(conn, NULL, NULL, NULL);
+ g_object_unref(msg);
+ g_clear_error(&err);
+
+ _D("send cpu boost req(%d)", req);
+
+ return res;
+}
+
+int _signal_send_display_lock_state(const char *state, char *flag, unsigned int timeout)
+{
+ GError *err = NULL;
+ GDBusConnection *conn;
+ GDBusMessage *msg;
+ const char *holdkeyblock_string = "holdkeyblock";
+ int ret = 0;
+
+ _D("Acquring display lock");
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ msg = g_dbus_message_new_method_call(SYSTEM_BUS_NAME,
+ SYSTEM_PATH_DISPLAY,
+ SYSTEM_INTERFACE_DISPLAY,
+ SYSTEM_LOCK_STATE);
+ if (msg == NULL) {
+ _E("g_dbus_message_new_method_call() is failed");
+ return -1;
+ }
+
+ g_dbus_message_set_body(msg, g_variant_new("(sssi)", state,
+ flag, holdkeyblock_string, timeout));
+ if (!g_dbus_connection_send_message(conn, msg,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &err)) {
+ ret = -1;
+ _E("Unable to send dbus message for acquring lock as %s",
+ err->message);
+ }
+
+ _D("Display lock acquired");
+ g_object_unref(msg);
+ g_dbus_connection_flush_sync(conn, NULL, NULL);
+ g_clear_error(&err);
+ return ret;
+}
+
+int _signal_send_display_unlock_state(const char *state, char *flag)
+{
+ GError *err = NULL;
+ GDBusConnection *conn;
+ GDBusMessage *msg;
+ int ret = 0;
+
+ _D("releasing display lock");
+ conn = __get_system_conn();
+ if (conn == NULL)
+ return -1;
+
+ msg = g_dbus_message_new_method_call(SYSTEM_BUS_NAME,
+ SYSTEM_PATH_DISPLAY,
+ SYSTEM_INTERFACE_DISPLAY,
+ SYSTEM_UNLOCK_STATE);
+ if (msg == NULL) {
+ _E("g_dbus_message_new_method_call() is failed");
+ return -1;
+ }
+
+ g_dbus_message_set_body(msg, g_variant_new("(ss)", state, flag));
+ if (!g_dbus_connection_send_message(conn, msg,
+ G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, &err)) {
+ _E("Unable to send dbus message for releasing lock as %s",
+ err->message);
+ ret = -1;
+ }
+
+ _D("Display lock released");
+ g_object_unref(msg);
+ g_dbus_connection_flush_sync(conn, NULL, NULL);
+ g_clear_error(&err);
+ return ret;
+}
+
+int _signal_add_initializer(int (*callback)(void *data), void *user_data)
+{
+ struct signal_initializer *initializer;
+
+ if (callback == NULL) {
+ _E("Invalid parameter");
+ return -1;
+ }
+
+ initializer = (struct signal_initializer *)malloc(
+ sizeof(struct signal_initializer));
+ if (initializer == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ initializer->callback = callback;
+ initializer->data = user_data;
+
+ signal_init_list = g_list_append(signal_init_list, initializer);
+
+ return 0;
+}
+
+static gboolean __dispatch_initializer_list(gpointer user_data)
+{
+ struct signal_initializer *initializer;
+ GList *list;
+ int ret;
+
+ list = g_list_first(signal_init_list);
+ while (list) {
+ initializer = (struct signal_initializer *)list->data;
+ list = g_list_next(list);
+ if (initializer) {
+ ret = initializer->callback(initializer->data);
+ if (ret == 0) {
+ signal_init_list =
+ g_list_remove(signal_init_list,
+ initializer);
+ free(initializer);
+ }
+ }
+ }
+
+ if (signal_init_list == NULL) {
+ _D("init list is NULL");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+int _signal_init(void)
+{
+ if (signal_init_list) {
+ g_timeout_add_seconds(SIGNAL_INIT_INTERVAL,
+ __dispatch_initializer_list, NULL);
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+
+#include <bundle.h>
+#include <systemd/sd-daemon.h>
+#include <aul_sock.h>
+
+#include "amd_util.h"
+#include "amd_socket.h"
+
+#define PATH_AMD_SOCK "/run/aul/daemons/.amd-sock"
+
+int _create_sock_activation(void)
+{
+ int fds;
+
+ fds = sd_listen_fds(0);
+ if (fds == 1) {
+ if (chmod(PATH_AMD_SOCK, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
+ _E("change mode error: %d", errno);
+ return SD_LISTEN_FDS_START;
+ }
+
+ if (fds > 1)
+ _E("Too many file descriptors received.\n");
+ else
+ _D("There is no socket stream");
+
+ return -1;
+}
+
+int _create_server_sock(void)
+{
+ int fd;
+ struct sockaddr_un addr;
+
+ fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ _E("create socket error: %d", errno);
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", PATH_AMD_SOCK);
+ unlink(addr.sun_path);
+
+ if (bind(fd, (struct sockaddr *)&addr, sizeof(addr))) {
+ _E("bind error: %d", errno);
+ close(fd);
+ return -1;
+ }
+
+ if (chmod(addr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
+ _E("change mode error: %d", errno);
+ close(fd);
+ return -1;
+ }
+
+ aul_sock_set_sock_option(fd, 0);
+
+ if (listen(fd, 128) == -1) {
+ _E("listen error: %d", errno);
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static int __connect_client_sock(int fd, const struct sockaddr *saptr,
+ socklen_t salen, int nsec)
+{
+ int flags;
+ int ret;
+ int error;
+ socklen_t len;
+ fd_set readfds;
+ fd_set writefds;
+ struct timeval timeout;
+
+ flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ error = 0;
+ ret = connect(fd, (struct sockaddr *)saptr, salen);
+ if (ret < 0) {
+ if (errno != EAGAIN && errno != EINPROGRESS) {
+ fcntl(fd, F_SETFL, flags);
+ return -2;
+ }
+ }
+
+ /* Do whatever we want while the connect is taking place. */
+ if (ret == 0)
+ goto done; /* connect completed immediately */
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+ writefds = readfds;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = nsec;
+
+ ret = select(fd + 1, &readfds, &writefds, NULL,
+ nsec ? &timeout : NULL);
+ if (ret == 0) {
+ close(fd); /* timeout */
+ errno = ETIMEDOUT;
+ return -1;
+ }
+
+ if (FD_ISSET(fd, &readfds) || FD_ISSET(fd, &writefds)) {
+ len = sizeof(error);
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+ return -1; /* Solaris pending error */
+ } else {
+ return -1; /* select error: sockfd not set*/
+ }
+
+done:
+ (void)fcntl(fd, F_SETFL, flags);
+ if (error) {
+ close(fd);
+ errno = error;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __create_launchpad_client_sock(const char *pad_type, uid_t uid)
+{
+ int fd = -1;
+ struct sockaddr_un saddr = { 0, };
+ int retry = 1;
+ int ret = -1;
+
+ fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ /* support above version 2.6.27*/
+ if (fd < 0) {
+ if (errno == EINVAL) {
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ _E("second chance - socket create error");
+ return -1;
+ }
+ } else {
+ _E("socket error");
+ return -1;
+ }
+ }
+
+ saddr.sun_family = AF_UNIX;
+ snprintf(saddr.sun_path, sizeof(saddr.sun_path),
+ "/run/aul/daemons/%d/%s", uid, pad_type);
+ retry_con:
+ ret = __connect_client_sock(fd, (struct sockaddr *)&saddr,
+ sizeof(saddr), 100 * 1000);
+ if (ret < -1) {
+ _E("maybe peer not launched or peer daed\n");
+ if (retry > 0) {
+ usleep(100 * 1000);
+ retry--;
+ goto retry_con;
+ }
+ }
+ if (ret < 0) {
+ close(fd);
+ return -1;
+ }
+
+ aul_sock_set_sock_option(fd, 1);
+
+ return fd;
+}
+
+int _send_cmd_to_launchpad(const char *pad_type, uid_t uid, int cmd, bundle *kb)
+{
+ int fd;
+ int len;
+ int res;
+ char err_buf[1024];
+
+ fd = __create_launchpad_client_sock(pad_type, uid);
+ if (fd < 0)
+ return -1;
+
+ res = aul_sock_send_bundle_with_fd(fd, cmd, kb, AUL_SOCK_ASYNC);
+ if (res < 0) {
+ close(fd);
+ return res;
+ }
+
+retry_recv:
+ len = recv(fd, &res, sizeof(int), 0);
+ if (len == -1) {
+ if (errno == EAGAIN) {
+ _E("recv timeout : %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ res = -EAGAIN;
+ } else if (errno == EINTR) {
+ _D("recv : %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ goto retry_recv;
+ } else {
+ _E("recv error : %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ res = -ECOMM;
+ }
+ }
+
+ close(fd);
+
+ return res;
+}
+
+void _send_result_to_client(int fd, int res)
+{
+ if (fd < 3)
+ return;
+
+ if (send(fd, &res, sizeof(int), MSG_NOSIGNAL) < 0) {
+ if (errno == EPIPE)
+ _E("send failed due to EPIPE.");
+ _E("send fail to client");
+ }
+
+ close(fd);
+}
+
+void _send_result_to_client_v2(int fd, int res)
+{
+ if (fd < 3)
+ return;
+
+ if (send(fd, &res, sizeof(int), MSG_NOSIGNAL) < 0) {
+ if (errno == EPIPE)
+ _E("send failed due to EPIPE.");
+ _E("send fail to client");
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <glib.h>
+#include <aul.h>
+#include <aul_cmd.h>
+#include <aul_svc.h>
+#include <aul_svc_priv_key.h>
+#include <wayland-client.h>
+#include <wayland-tbm-client.h>
+#include <tizen-launch-client-protocol.h>
+#include <vconf.h>
+#include <sensor_internal.h>
+
+#include "amd_appinfo.h"
+#include "amd_util.h"
+#include "amd_splash_screen.h"
+#include "amd_wayland.h"
+#include "amd_app_status.h"
+
+#define K_FAKE_EFFECT "__FAKE_EFFECT__"
+#define APP_CONTROL_OPERATION_MAIN "http://tizen.org/appcontrol/operation/main"
+#define SPLASH_SCREEN_INFO_PATH "/usr/share/aul"
+#define TAG_SPLASH_IMAGE "[SplashImage]"
+#define TAG_NAME "Name"
+#define TAG_FILE "File"
+#define TAG_TYPE "Type"
+#define TAG_ORIENTATION "Orientation"
+#define TAG_INDICATOR_DISPLAY "Indicator-display"
+#define TAG_COLOR_DEPTH "Color-depth"
+#define TIMEOUT_INTERVAL 10000 /* 10 sec */
+
+struct splash_image_s {
+ struct tizen_launch_splash *image;
+ char *appid;
+ char *src;
+ int type;
+ int rotation;
+ int indicator;
+ int color_depth;
+ int pid;
+ char *effect_type;
+ char *theme_type;
+ guint timer;
+};
+
+struct rotation_s {
+ int handle;
+ int angle;
+ int auto_rotate;
+};
+
+struct image_info_s {
+ char *name;
+ char *file;
+ char *type;
+ char *orientation;
+ char *indicator_display;
+ char *color_depth;
+};
+
+static struct wl_display *display;
+static struct tizen_launch_effect *tz_launch_effect;
+static int splash_screen_initialized;
+static struct rotation_s rotation;
+static int rotation_initialized;
+static GList *default_image_list;
+static splash_image_h splash_image;
+
+static int __init_splash_screen(void);
+static int __init_rotation(void);
+
+splash_image_h _splash_screen_get_image(int pid)
+{
+ if (splash_image == NULL)
+ return NULL;
+
+ if (splash_image->pid == pid)
+ return splash_image;
+
+ return NULL;
+}
+
+static void __set_splash_image(splash_image_h si)
+{
+ splash_image = si;
+}
+
+void _splash_screen_destroy_image(splash_image_h si)
+{
+ if (si == NULL)
+ return;
+
+ if (si->timer)
+ g_source_remove(si->timer);
+ if (si->theme_type)
+ free(si->theme_type);
+ if (si->effect_type)
+ free(si->effect_type);
+ if (si->appid)
+ free(si->appid);
+ if (si->src)
+ free(si->src);
+ if (si->image) {
+ tizen_launch_splash_destroy(si->image);
+ wl_display_flush(display);
+ }
+ free(si);
+ __set_splash_image(NULL);
+}
+
+static gboolean __timeout_handler(gpointer data)
+{
+ splash_image_h si = (splash_image_h)data;
+ app_status_h app_status;
+
+ if (si == NULL)
+ return FALSE;
+
+ app_status = _app_status_find(si->pid);
+ if (app_status) {
+ if (_app_status_is_starting(app_status) == false) {
+ _W("% is not starting", si->pid);
+ return TRUE;
+ }
+ }
+
+ si->timer = 0;
+ _splash_screen_destroy_image(si);
+
+ return FALSE;
+}
+
+static int __app_can_launch_splash_image(const struct appinfo *ai,
+ bundle *kb)
+{
+ const char *comp_type;
+ const char *fake_effect;
+ int display;
+
+ comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (comp_type == NULL || strcmp(comp_type, APP_TYPE_UI) != 0) {
+ _D("component_type: %s", comp_type);
+ return -1;
+ }
+
+ fake_effect = bundle_get_val(kb, K_FAKE_EFFECT);
+ if (fake_effect && strncmp(fake_effect, "OFF", strlen("OFF")) == 0)
+ return -1;
+
+ _appinfo_get_int_value(ai, AIT_SPLASH_SCREEN_DISPLAY, &display);
+ if (!(display & APP_ENABLEMENT_MASK_ACTIVE))
+ return -1;
+
+ return 0;
+}
+
+static struct appinfo_splash_image *__get_splash_image_info(
+ const struct appinfo *ai, bundle *kb, int cmd)
+{
+ struct appinfo_splash_image *ai_si;
+ const struct appinfo_splash_screen *ai_ss;
+ const char *operation;
+ GHashTable *tbl;
+ const struct appinfo *caller_ai;
+ const char *uid_str;
+ const char *caller_appid;
+ const char *comp_type;
+ uid_t uid = 0;
+
+ ai_ss = _appinfo_get_ptr_value(ai, AIT_SPLASH_SCREEN);
+ if (ai_ss == NULL)
+ return NULL;
+
+ if ((rotation.angle == 90 || rotation.angle == 270)
+ && rotation.auto_rotate == true)
+ tbl = ai_ss->landscape;
+ else
+ tbl = ai_ss->portrait;
+
+ if (tbl == NULL)
+ return NULL;
+
+ operation = bundle_get_val(kb, AUL_SVC_K_OPERATION);
+ if (cmd == APP_OPEN || (operation &&
+ (!strcmp(operation, APP_CONTROL_OPERATION_MAIN) ||
+ !strcmp(operation, AUL_SVC_OPERATION_DEFAULT))))
+ return g_hash_table_lookup(tbl, "launch-effect");
+
+ if (operation) {
+ ai_si = g_hash_table_lookup(tbl, operation);
+ if (ai_si)
+ return ai_si;
+ }
+
+ caller_appid = bundle_get_val(kb, AUL_K_CALLER_APPID);
+ if (caller_appid == NULL)
+ return NULL;
+
+ uid_str = bundle_get_val(kb, AUL_K_TARGET_UID);
+ if (uid_str == NULL)
+ return NULL;
+
+ uid = atol(uid_str);
+ caller_ai = _appinfo_find(uid, caller_appid);
+ if (caller_ai == NULL)
+ return NULL;
+
+ comp_type = _appinfo_get_value(caller_ai, AIT_COMPTYPE);
+ if (comp_type == NULL)
+ return NULL;
+
+ if (!strcmp(comp_type, APP_TYPE_WATCH) ||
+ !strcmp(comp_type, APP_TYPE_WIDGET))
+ return g_hash_table_lookup(tbl, "launch-effect");
+
+ return NULL;
+}
+
+static struct image_info_s *__get_default_image_info(bundle *kb)
+{
+ struct image_info_s *info = NULL;
+ const char *orientation = "portrait";
+ const char *str;
+ GList *list;
+
+ if (default_image_list == NULL)
+ return NULL;
+
+ if ((rotation.angle == 90 || rotation.angle == 270) &&
+ rotation.auto_rotate == true)
+ orientation = "landscape";
+
+ str = bundle_get_val(kb, AUL_SVC_K_SPLASH_SCREEN);
+ if (str == NULL)
+ str = "default";
+
+ list = default_image_list;
+ while (list) {
+ info = (struct image_info_s *)list->data;
+ if (info && strcmp(str, info->name) == 0) {
+ if (!strcasecmp(info->orientation, orientation))
+ return info;
+ }
+
+ list = g_list_next(list);
+ }
+
+ return NULL;
+}
+
+splash_image_h _splash_screen_create_image(const struct appinfo *ai,
+ bundle *kb, int cmd, bool is_subapp)
+{
+ struct splash_image_s *si;
+ struct appinfo_splash_image *ai_si;
+ struct image_info_s *info;
+ const char *appid;
+ const char *src = NULL;
+ int file_type = 0;
+ int indicator = 1;
+ int color_depth = 24; /* default */
+
+ if (!splash_screen_initialized) {
+ if (__init_splash_screen() < 0)
+ return NULL;
+ }
+
+ if (__app_can_launch_splash_image(ai, kb) < 0)
+ return NULL;
+
+ if (!rotation_initialized) {
+ if (__init_rotation() < 0)
+ _W("Failed to initialize rotation");
+ }
+ _D("angle: %d", rotation.angle);
+
+ ai_si = __get_splash_image_info(ai, kb, cmd);
+ if (ai_si) {
+ src = ai_si->src;
+ if (access(src, F_OK) != 0)
+ return NULL;
+ if (strcasecmp(ai_si->type, "edj") == 0)
+ file_type = 1;
+ if (strcmp(ai_si->indicatordisplay, "false") == 0)
+ indicator = 0;
+ if (strcmp(ai_si->color_depth, "32") == 0)
+ color_depth = 32;
+ } else {
+ info = __get_default_image_info(kb);
+ if (info == NULL)
+ return NULL;
+ src = info->file;
+ if (access(src, F_OK) != 0)
+ return NULL;
+ if (strcasecmp(info->type, "edj") == 0)
+ file_type = 1;
+ if (strcmp(info->indicator_display, "false") == 0)
+ indicator = 0;
+ if (strcmp(info->color_depth, "32") == 0)
+ color_depth = 32;
+ }
+
+ si = (struct splash_image_s *)calloc(1, sizeof(struct splash_image_s));
+ if (si == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ si->image = tizen_launch_effect_create_splash_img(
+ tz_launch_effect);
+ if (si->image == NULL) {
+ _E("Failed to get launch image");
+ free(si);
+ return NULL;
+ }
+ wl_display_flush(display);
+
+ si->src = strdup(src);
+ if (si->src == NULL) {
+ _E("out of memory");
+ _splash_screen_destroy_image(si);
+ return NULL;
+ }
+
+ if (is_subapp)
+ si->effect_type = strdup("depth-in");
+ else
+ si->effect_type = strdup("launch");
+ if (si->effect_type == NULL) {
+ _E("Out of memory");
+ _splash_screen_destroy_image(si);
+ return NULL;
+ }
+
+ si->theme_type = strdup("default");
+ if (si->theme_type == NULL) {
+ _E("Out of memory");
+ _splash_screen_destroy_image(si);
+ return NULL;
+ }
+
+ appid = _appinfo_get_value(ai, AIT_NAME);
+ si->appid = strdup(appid);
+ if (si->appid == NULL) {
+ _E("out of memory");
+ _splash_screen_destroy_image(si);
+ return NULL;
+ }
+
+ si->type = file_type;
+ si->rotation = rotation.angle;
+ si->indicator = indicator;
+ si->color_depth = color_depth;
+
+ si->timer = g_timeout_add(TIMEOUT_INTERVAL, __timeout_handler, si);
+ __set_splash_image(si);
+
+ return si;
+}
+
+void _splash_screen_send_image(splash_image_h si)
+{
+ struct wl_array options;
+ bundle *b;
+ bundle_raw *raw_data = NULL;
+ int len = 0;
+ int ret;
+ size_t size;
+ void *data;
+
+ if (si == NULL || si->image == NULL)
+ return;
+
+ wl_array_init(&options);
+
+ b = bundle_create();
+ if (b == NULL) {
+ _E("out of memory");
+ return;
+ }
+
+ bundle_add(b, AUL_K_APPID, si->appid);
+ ret = bundle_encode(b, &raw_data, &len);
+ if (ret != BUNDLE_ERROR_NONE) {
+ _E("Failed to encode bundle");
+ bundle_free(b);
+ return;
+ }
+ bundle_free(b);
+
+ size = strlen((const char *)raw_data);
+ data = wl_array_add(&options, size + 1);
+ memcpy(data, raw_data, size + 1);
+ free(raw_data);
+
+ _D("src(%s), type(%d), color-depth(%d), rotation(%d), " \
+ "indicator(%d), effect_type(%s)",
+ si->src, si->type, si->color_depth, si->rotation,
+ si->indicator, si->effect_type);
+ tizen_launch_splash_launch(si->image, si->src, si->type,
+ si->color_depth, si->rotation, si->indicator,
+ si->effect_type, si->theme_type, &options);
+ wl_display_flush(display);
+
+ wl_array_release(&options);
+}
+
+void _splash_screen_send_pid(splash_image_h si, int pid)
+{
+ if (si == NULL)
+ return;
+
+ si->pid = pid;
+ tizen_launch_splash_owner(si->image, pid);
+ wl_display_flush(display);
+}
+
+void _splash_screen_set_effect_type(int pid, const char *appid, bool is_subapp)
+{
+ struct wl_array options;
+ bundle *b;
+ bundle_raw *raw_data = NULL;
+ int len = 0;
+ int ret;
+ size_t size;
+ void *data;
+ const char *effect_type;
+
+ if (!splash_screen_initialized)
+ return;
+
+ wl_array_init(&options);
+
+ if (is_subapp)
+ effect_type = "depth-in";
+ else
+ effect_type = "launch";
+
+ b = bundle_create();
+ if (b == NULL) {
+ _E("out of memory");
+ return;
+ }
+
+ bundle_add(b, AUL_K_APPID, appid);
+ ret = bundle_encode(b, &raw_data, &len);
+ if (ret != BUNDLE_ERROR_NONE) {
+ _E("Failed to encode bundle");
+ bundle_free(b);
+ return;
+ }
+ bundle_free(b);
+
+ size = strlen((const char *)raw_data);
+ data = wl_array_add(&options, size + 1);
+ memcpy(data, raw_data, size + 1);
+ free(raw_data);
+
+ _D("effect_type(%s), pid(%d)", effect_type, pid);
+ tizen_launch_effect_type_set(tz_launch_effect, effect_type,
+ pid, &options);
+ wl_display_flush(display);
+
+ wl_array_release(&options);
+}
+
+static void __wl_listener_cb(void *data, struct wl_registry *registry,
+ unsigned int id, const char *interface, unsigned int version)
+{
+ if (interface && strcmp(interface, "tizen_launch_effect") == 0) {
+ _D("interface: %s", interface);
+ if (!tz_launch_effect) {
+ tz_launch_effect = wl_registry_bind(registry, id,
+ &tizen_launch_effect_interface, 1);
+ }
+ }
+}
+
+static void __wl_listener_remove_cb(void *data, struct wl_registry *registry,
+ unsigned int id)
+{
+ if (tz_launch_effect) {
+ tizen_launch_effect_destroy(tz_launch_effect);
+ tz_launch_effect = NULL;
+ }
+}
+
+static struct wl_registry_listener registry_listener = {
+ __wl_listener_cb,
+ __wl_listener_remove_cb
+};
+
+static int __init_splash_screen(void)
+{
+ if (!display) {
+ display = _wayland_get_display();
+ if (!display) {
+ _E("Failed to get display");
+ return -1;
+ }
+ }
+
+ if (!tz_launch_effect) {
+ _E("Failed to bind tizen launch screen");
+ return -1;
+ }
+
+ splash_screen_initialized = 1;
+
+ return 0;
+}
+
+#ifdef TIZEN_FEATURE_AUTO_ROTATION
+static void __rotation_changed_cb(sensor_t sensor, unsigned int event_type,
+ sensor_data_t *data, void *user_data)
+{
+ int event;
+
+ if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
+ return;
+
+ event = (int)data->values[0];
+ switch (event) {
+ case AUTO_ROTATION_DEGREE_0:
+ rotation.angle = 0;
+ break;
+ case AUTO_ROTATION_DEGREE_90:
+ rotation.angle = 90;
+ break;
+ case AUTO_ROTATION_DEGREE_180:
+ rotation.angle = 180;
+ break;
+ case AUTO_ROTATION_DEGREE_270:
+ rotation.angle = 270;
+ break;
+ default:
+ break;
+ }
+
+ _D("angle: %d", rotation.angle);
+}
+
+static void __auto_rotate_screen_cb(keynode_t *key, void *data)
+{
+ rotation.auto_rotate = vconf_keynode_get_bool(key);
+ if (!rotation.auto_rotate) {
+ _D("auto_rotate: %d, angle: %d",
+ rotation.auto_rotate, rotation.angle);
+ }
+}
+#endif /* TIZEN_FEATURE_AUTO_ROTATION */
+
+static int __init_rotation(void)
+{
+#ifdef TIZEN_FEATURE_AUTO_ROTATION
+ int ret;
+ bool r;
+ sensor_t sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
+
+ rotation.angle = 0;
+ rotation.handle = sensord_connect(sensor);
+ if (rotation.handle < 0) {
+ _W("Failed to connect sensord");
+ return -1;
+ }
+
+ r = sensord_register_event(rotation.handle,
+ AUTO_ROTATION_CHANGE_STATE_EVENT,
+ SENSOR_INTERVAL_NORMAL,
+ 0,
+ __rotation_changed_cb,
+ NULL);
+ if (!r) {
+ _W("Failed to register event");
+ sensord_disconnect(rotation.handle);
+ return -1;
+ }
+
+ r = sensord_start(rotation.handle, 0);
+ if (!r) {
+ _W("Failed to start sensord");
+ sensord_unregister_event(rotation.handle,
+ AUTO_ROTATION_CHANGE_STATE_EVENT);
+ sensord_disconnect(rotation.handle);
+ return -1;
+ }
+
+ ret = vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL,
+ &rotation.auto_rotate);
+ if (ret != VCONF_OK)
+ rotation.auto_rotate = false;
+
+ ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL,
+ __auto_rotate_screen_cb, NULL);
+ if (ret != 0) {
+ _W("Failed to register callback for %s",
+ VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL);
+ }
+#endif /* TIZEN_FEATURE_AUTO_ROTATION */
+ rotation_initialized = 1;
+
+ return 0;
+}
+
+static void __destroy_image_info(struct image_info_s *info)
+{
+ if (info == NULL)
+ return;
+
+ if (info->color_depth)
+ free(info->color_depth);
+ if (info->indicator_display)
+ free(info->indicator_display);
+ if (info->type)
+ free(info->type);
+ if (info->orientation)
+ free(info->orientation);
+ if (info->file)
+ free(info->file);
+ if (info->name)
+ free(info->name);
+ free(info);
+}
+
+struct image_info_s *__create_image_info(void)
+{
+ struct image_info_s *info;
+
+ info = (struct image_info_s *)calloc(1, sizeof(struct image_info_s));
+ if (info == NULL) {
+ _E("out of memory");
+ return NULL;
+ }
+
+ return info;
+}
+
+static int __validate_image_info(struct image_info_s *info)
+{
+ if (info == NULL)
+ return -1;
+
+ if (info->name == NULL ||
+ info->file == NULL ||
+ info->orientation == NULL)
+ return -1;
+
+ if (info->type == NULL) {
+ if (strstr(info->file, "edj"))
+ info->type = strdup("edj");
+ else
+ info->type = strdup("img");
+ }
+
+ if (info->indicator_display == NULL)
+ info->indicator_display = strdup("true");
+
+ if (info->color_depth == NULL)
+ info->color_depth = strdup("24");
+
+ return 0;
+}
+
+static void __parse_file(const char *file)
+{
+ FILE *fp;
+ char buf[LINE_MAX];
+ char tok1[LINE_MAX];
+ char tok2[LINE_MAX];
+ struct image_info_s *info = NULL;
+
+ fp = fopen(file, "rt");
+ if (fp == NULL)
+ return;
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ tok1[0] = '\0';
+ tok2[0] = '\0';
+ sscanf(buf, "%s %s", tok1, tok2);
+
+ if (strcasecmp(TAG_SPLASH_IMAGE, tok1) == 0) {
+ if (info) {
+ if (__validate_image_info(info) < 0) {
+ __destroy_image_info(info);
+ } else {
+ default_image_list = g_list_append(
+ default_image_list,
+ info);
+ }
+ }
+ info = __create_image_info();
+ continue;
+ }
+
+ if (tok1[0] == '\0' || tok2[0] == '\0' || info == NULL)
+ continue;
+
+ if (strcasecmp(TAG_NAME, tok1) == 0)
+ info->name = strdup(tok2);
+ else if (strcasecmp(TAG_FILE, tok1) == 0)
+ info->file = strdup(tok2);
+ else if (strcasecmp(TAG_TYPE, tok1) == 0)
+ info->type = strdup(tok2);
+ else if (strcasecmp(TAG_ORIENTATION, tok1) == 0)
+ info->orientation = strdup(tok2);
+ else if (strcasecmp(TAG_INDICATOR_DISPLAY, tok1) == 0)
+ info->indicator_display = strdup(tok2);
+ else if (strcasecmp(TAG_COLOR_DEPTH, tok1) == 0)
+ info->color_depth = strdup(tok2);
+ }
+
+ if (info) {
+ if (__validate_image_info(info) < 0) {
+ __destroy_image_info(info);
+ } else {
+ default_image_list = g_list_append(default_image_list,
+ info);
+ }
+ }
+
+ fclose(fp);
+}
+
+static int __load_splash_screen_info(const char *path)
+{
+ DIR *dp;
+ struct dirent entry;
+ struct dirent *result = NULL;
+ char *ext;
+ char buf[PATH_MAX];
+
+ dp = opendir(path);
+ if (dp == NULL)
+ return -1;
+
+ while (readdir_r(dp, &entry, &result) == 0 && result != NULL) {
+ if (entry.d_name[0] == '.')
+ continue;
+
+ ext = strrchr(entry.d_name, '.');
+ if (ext && !strcmp(ext, ".conf")) {
+ snprintf(buf, sizeof(buf), "%s/%s", path, entry.d_name);
+ __parse_file(buf);
+ }
+ }
+
+ closedir(dp);
+
+ return 0;
+}
+
+int _splash_screen_init(void)
+{
+ _D("init splash screen");
+
+ __load_splash_screen_info(SPLASH_SCREEN_INFO_PATH);
+ _wayland_add_registry_listener(®istry_listener, NULL);
+
+ if (__init_rotation() < 0)
+ _W("Failed to initialize rotation");
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <aul.h>
+#include <aul_sock.h>
+#include <bundle_internal.h>
+
+#include "amd_signal.h"
+#include "amd_util.h"
+#include "amd_suspend.h"
+#include "amd_app_status.h"
+
+typedef struct proc_info {
+ pid_t pid;
+ guint timer_id;
+} proc_info_t;
+
+static GHashTable *proc_info_tbl;
+
+static void __destroy_proc_info_value(gpointer data)
+{
+ proc_info_t *proc = (proc_info_t *)data;
+
+ if (proc)
+ free(proc);
+}
+
+static void __prepare_to_suspend(int pid, uid_t uid)
+{
+ int ret;
+ int dummy;
+
+ _D("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+ ret = aul_sock_send_raw(pid, uid, APP_SUSPEND, (unsigned char *)&dummy,
+ sizeof(int), AUL_SOCK_NOREPLY);
+ if (ret < 0)
+ _E("Failed to send APP_SUSPEND %d", pid);
+}
+
+static void __prepare_to_wake(int pid, uid_t uid)
+{
+ int ret;
+ bundle *kb;
+
+ kb = bundle_create();
+ if (kb == NULL) {
+ _E("out of memory");
+ return;
+ }
+
+ bundle_add(kb, AUL_K_ALLOWED_BG, "ALLOWED_BG");
+
+ _D("[__SUSPEND__] pid: %d, uid: %d", pid, uid);
+ ret = aul_sock_send_bundle(pid, uid, APP_WAKE, kb, AUL_SOCK_NOREPLY);
+ if (ret != AUL_R_OK)
+ _E("Failed to send APP_WAKE %d", pid);
+
+ bundle_free(kb);
+}
+
+static void __wake_bg_apps(app_status_h app_status, void *data)
+{
+ const char *appid;
+ int status;
+ uid_t uid;
+ const struct appinfo *ai;
+ int target_category;
+ int bg_category;
+ bool bg_allowed;
+ int pid;
+
+ if (app_status == NULL)
+ return;
+
+ status = _app_status_get_status(app_status);
+ if (status != STATUS_BG && status != STATUS_SERVICE)
+ return;
+
+ appid = _app_status_get_appid(app_status);
+ uid = _app_status_get_uid(app_status);
+ pid = _app_status_get_pid(app_status);
+
+ ai = _appinfo_find(uid, appid);
+ if (ai == NULL)
+ return;
+
+ if (data) {
+ target_category = GPOINTER_TO_INT(data);
+ bg_category = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY);
+ if (bg_category != target_category)
+ return;
+ } else {
+ bg_allowed = _suspend_is_allowed_background(ai);
+ if (bg_allowed == true)
+ return;
+ }
+
+ _D("[__SUSPEND__] Wake %s %d", appid, pid);
+ _suspend_remove_timer(pid);
+ __prepare_to_wake(pid, uid);
+ _app_status_find_service_apps(app_status, status,
+ __prepare_to_wake, false);
+ aul_update_freezer_status(pid, "exclude");
+}
+
+static void __suspend_bg_apps(app_status_h app_status, void *data)
+{
+ const char *appid;
+ int status;
+ uid_t uid;
+ const struct appinfo *ai;
+ int target_category;
+ int bg_category;
+ bool bg_allowed;
+ int pid;
+
+ if (app_status == NULL)
+ return;
+
+ status = _app_status_get_status(app_status);
+ if (status != STATUS_BG && status != STATUS_SERVICE)
+ return;
+
+ appid = _app_status_get_appid(app_status);
+ uid = _app_status_get_uid(app_status);
+ pid = _app_status_get_pid(app_status);
+
+ ai = _appinfo_find(uid, appid);
+ if (ai == NULL)
+ return;
+
+ if (data) {
+ target_category = GPOINTER_TO_INT(data);
+ bg_category = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY);
+ if (bg_category != target_category)
+ return;
+ } else {
+ bg_allowed = _suspend_is_allowed_background(ai);
+ if (bg_allowed == true)
+ return;
+ }
+
+ _D("[__SUSPEND__] Suspend %s %d", appid, pid);
+ _app_status_find_service_apps(app_status, status,
+ __prepare_to_suspend, true);
+ __prepare_to_suspend(pid, uid);
+ _suspend_add_timer(pid, ai);
+ aul_update_freezer_status(pid, "include");
+}
+
+void _suspend_init(void)
+{
+ if (!proc_info_tbl) {
+ proc_info_tbl = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL,
+ __destroy_proc_info_value);
+ }
+
+ _D("_amd_proc_init done");
+}
+
+void _suspend_fini(void)
+{
+ g_hash_table_destroy(proc_info_tbl);
+ _D("_amd_proc_fini done");
+}
+
+proc_info_t *__create_proc_info(int pid)
+{
+ proc_info_t *proc;
+
+ if (pid < 1) {
+ _E("invalid pid");
+ return NULL;
+ }
+
+ proc = (proc_info_t *)malloc(sizeof(proc_info_t));
+ if (proc == NULL) {
+ _E("insufficient memory");
+ return NULL;
+ }
+
+ proc->pid = pid;
+ proc->timer_id = 0;
+
+ return proc;
+}
+
+proc_info_t *__find_proc_info(int pid)
+{
+ proc_info_t *proc;
+
+ if (pid < 1) {
+ _E("invalid pid");
+ return NULL;
+ }
+
+ proc = (proc_info_t *)g_hash_table_lookup(proc_info_tbl,
+ GINT_TO_POINTER(pid));
+ if (proc == NULL) {
+ _E("proc info not found");
+ return NULL;
+ }
+
+ return proc;
+}
+
+int __add_proc_info(proc_info_t *proc)
+{
+ if (proc == NULL) {
+ _E("invalid proc info");
+ return -1;
+ }
+
+ if (proc->pid < 1) {
+ _E("invalid pid");
+ return -1;
+ }
+
+ g_hash_table_insert(proc_info_tbl, GINT_TO_POINTER(proc->pid), proc);
+
+ return 0;
+}
+
+int _suspend_add_proc(int pid)
+{
+ proc_info_t *proc;
+
+ proc = __create_proc_info(pid);
+ if (proc)
+ return __add_proc_info(proc);
+
+ return -1;
+}
+
+int _suspend_remove_proc(int pid)
+{
+ proc_info_t *proc;
+
+ if (pid < 1) {
+ _E("invalid pid");
+ return -1;
+ }
+
+ proc = (proc_info_t *)g_hash_table_lookup(proc_info_tbl,
+ GINT_TO_POINTER(pid));
+ if (proc == NULL) {
+ _E("proc info not found");
+ return -1;
+ }
+
+ g_hash_table_remove(proc_info_tbl, GINT_TO_POINTER(pid));
+
+ return 0;
+}
+
+static gboolean __send_suspend_hint(gpointer data)
+{
+ proc_info_t *proc;
+ int pid = GPOINTER_TO_INT(data);
+
+ proc = __find_proc_info(pid);
+ if (proc && proc->timer_id > 0) {
+ _signal_send_proc_suspend(pid);
+ proc->timer_id = 0;
+ }
+
+ return FALSE;
+}
+
+bool _suspend_is_allowed_background(const struct appinfo *ai)
+{
+ int bg_category;
+ const char *comp_type;
+
+ comp_type = _appinfo_get_value(ai, AIT_COMPTYPE);
+ if (comp_type == NULL)
+ return false;
+
+ if (strcmp(comp_type, APP_TYPE_UI) != 0 &&
+ strcmp(comp_type, APP_TYPE_SERVICE) != 0)
+ return true;
+
+ /*
+ * 2.4 bg-categorized (uiapp || svcapp) || watch || widget -> bg allowed
+ * 2.3 uiapp -> not allowed, 2.3 svcapp -> bg allowed
+ */
+ bg_category = (intptr_t)_appinfo_get_value(ai, AIT_BG_CATEGORY);
+ if (bg_category)
+ return true;
+
+ return false;
+}
+
+void _suspend_add_timer(int pid, const struct appinfo *ai)
+{
+ bool bg_allowed;
+ proc_info_t *proc;
+
+ bg_allowed = _suspend_is_allowed_background(ai);
+ if (bg_allowed)
+ return;
+
+ proc = __find_proc_info(pid);
+ if (proc == NULL) {
+ proc = __create_proc_info(pid);
+ if (proc)
+ __add_proc_info(proc);
+ }
+
+ if (proc) {
+ proc->timer_id = g_timeout_add_seconds(10, __send_suspend_hint,
+ GINT_TO_POINTER(pid));
+ }
+}
+
+void _suspend_remove_timer(int pid)
+{
+ proc_info_t *proc;
+
+ proc = __find_proc_info(pid);
+ if (proc && proc->timer_id > 0) {
+ g_source_remove(proc->timer_id);
+ proc->timer_id = 0;
+ }
+}
+
+int _suspend_update_status(int pid, int status)
+{
+ app_status_h app_status;
+
+ if (pid < 0)
+ return -1;
+
+ app_status = _app_status_find(pid);
+ if (app_status == NULL)
+ return -1;
+
+ if (status == SUSPEND_STATUS_EXCLUDE) {
+ __wake_bg_apps(app_status, NULL);
+ } else if (status == SUSPEND_STATUS_INCLUDE) {
+ __suspend_bg_apps(app_status, NULL);
+ } else {
+ _E("Unknown status(%d)", status);
+ return -1;
+ }
+ _D("[__SUSPEND__] pid(%d), status(%d)", pid, status);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <vconf.h>
+#include <aul.h>
+
+#include "amd_util.h"
+#include "amd_widget.h"
+#include "amd_app_status.h"
+
+#define AMD_LOG_BUFFER_SIZE 10000
+#define AMD_LOG_BUFFER_STRING_SIZE 128
+#define AMD_LOG_FILE "/run/aul/log/amd.log"
+
+static int log_index;
+static int log_fd;
+
+int _util_save_log(const char *tag, const char *message)
+{
+ int ret;
+ int offset;
+ time_t now;
+ char time_buf[32] = {0,};
+ char buffer[AMD_LOG_BUFFER_STRING_SIZE];
+ char err_buf[1024];
+
+ if (log_fd < 0) {
+ _E("error in opening the file: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return -1;
+ }
+
+ time(&now);
+ ctime_r(&now, time_buf);
+ if (log_index != 0)
+ offset = lseek(log_fd, 0, SEEK_CUR);
+ else
+ offset = lseek(log_fd, 0, SEEK_SET);
+
+ if (offset == -1)
+ _E("error in lseek: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+
+ snprintf(buffer, sizeof(buffer), "[%-6d] %-15s %-50s %s",
+ log_index, tag, message, time_buf);
+
+ ret = write(log_fd, buffer, strlen(buffer));
+ if (ret < 0) {
+ _E("Cannot write the amd log: %d", ret);
+ return -1;
+ }
+
+ if (++log_index >= AMD_LOG_BUFFER_SIZE)
+ log_index = 0;
+
+ return 0;
+}
+
+static void __low_mem_key_changed_cb(keynode_t *node, void *data)
+{
+ int status;
+
+ if (vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status) < 0)
+ return;
+
+ _D("mem status changed %d(normal:%d)",
+ status, VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
+ if (status == VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
+ _widget_restart_faulted();
+ _app_status_send_fault_dead_for_oom_apps();
+ }
+}
+
+bool _util_check_oom(void)
+{
+ int ret;
+ int status;
+
+ ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
+ if (ret == 0 && status >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
+ _W("low memory");
+ return true;
+ }
+
+ return false;
+}
+
+static int __init_log(void)
+{
+ int offset;
+ char err_buf[1024];
+
+ log_fd = open(AMD_LOG_FILE, O_CREAT | O_WRONLY, 0644);
+ if (log_fd < 0) {
+ _E("error in opening the file: %s",
+ strerror_r(errno, err_buf, sizeof(err_buf)));
+ return -1;
+ }
+
+ offset = lseek(log_fd, 0, SEEK_END);
+ if (offset != 0) {
+ log_index = (int)(offset / AMD_LOG_BUFFER_STRING_SIZE);
+ if (log_index >= AMD_LOG_BUFFER_SIZE) {
+ log_index = 0;
+ lseek(log_fd, 0, SEEK_SET);
+ }
+ }
+
+ return 0;
+}
+
+int _util_init(void)
+{
+ if (__init_log() < 0)
+ return -1;
+
+ if (vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY,
+ __low_mem_key_changed_cb, NULL) < 0) {
+ _E("vconf initialize failed.");
+ return -1;
+ }
+
+ return 0;
+}
+
+void _util_fini(void)
+{
+ if (log_fd > 0)
+ close(log_fd);
+
+ vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY,
+ (vconf_callback_fn) __low_mem_key_changed_cb);
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <wayland-client.h>
+#include <wayland-tbm-client.h>
+#include <tizen-extension-client-protocol.h>
+
+#include "amd_util.h"
+#include "amd_wayland.h"
+#include "amd_inotify.h"
+
+#define PATH_RUN_WAYLAND "/run/wayland-0"
+#define PATH_RUN_WMREADY "/run/.wm_ready"
+#define PATH_RUN "/run"
+
+struct wl_listener {
+ struct wl_registry_listener *registry_listener;
+ void *data;
+};
+
+static bool wl_ready;
+static bool wm_ready;
+static bool wl_initialized;
+static struct wl_display *display;
+static struct wl_registry *registry;
+static GList *wl_list;
+static int __wd;
+
+static void __init_wl(void);
+
+int _wayland_add_registry_listener(
+ struct wl_registry_listener *registry_listener,
+ void *data)
+{
+ struct wl_listener *listener;
+
+ if (registry_listener == NULL)
+ return -1;
+
+ listener = (struct wl_listener *)calloc(1, sizeof(struct wl_listener));
+ if (listener == NULL) {
+ _E("out of memory");
+ return -1;
+ }
+
+ listener->registry_listener = registry_listener;
+ listener->data = data;
+
+ wl_list = g_list_append(wl_list, listener);
+
+ return 0;
+}
+
+struct wl_display *_wayland_get_display(void)
+{
+ if (!display && wl_initialized)
+ __init_wl();
+
+ return display;
+}
+
+static void __wl_listener_cb(void *data, struct wl_registry *reg,
+ unsigned int id, const char *interface, unsigned int version)
+{
+ GList *iter;
+ struct wl_listener *listener;
+
+ for (iter = g_list_first(wl_list); iter; iter = g_list_next(iter)) {
+ listener = (struct wl_listener *)iter->data;
+ if (listener && listener->registry_listener &&
+ listener->registry_listener->global) {
+ listener->registry_listener->global(listener->data,
+ reg, id, interface, version);
+ }
+ }
+}
+
+static void __wl_listener_remove_cb(void *data, struct wl_registry *reg,
+ unsigned int id)
+{
+ GList *iter;
+ struct wl_listener *listener;
+
+ iter = g_list_first(wl_list);
+ while (iter) {
+ listener = (struct wl_listener *)iter->data;
+ if (listener && listener->registry_listener &&
+ listener->registry_listener->global_remove) {
+ listener->registry_listener->global_remove(
+ listener->data, reg, id);
+ }
+
+ iter = g_list_next(iter);
+ wl_list = g_list_remove(wl_list, listener);
+ free(listener);
+ }
+}
+
+
+static const struct wl_registry_listener registry_listener = {
+ __wl_listener_cb,
+ __wl_listener_remove_cb
+};
+
+static void __init_wl(void)
+{
+ display = wl_display_connect(NULL);
+ if (display == NULL) {
+ _E("Failed to connect wayland display");
+ return;
+ }
+
+ registry = wl_display_get_registry(display);
+ if (registry == NULL) {
+ _E("Failed to get wayland registry");
+ wl_display_disconnect(display);
+ display = NULL;
+ return;
+ }
+
+ wl_registry_add_listener(registry, ®istry_listener, NULL);
+ wl_display_flush(display);
+ wl_display_roundtrip(display);
+}
+
+static bool __wayland_monitor_cb(const char *event_name, void *data)
+{
+ if (event_name == NULL)
+ return true;
+
+ if (strcmp(event_name, "wayland-0") == 0) {
+ _D("%s is created", event_name);
+ wl_ready = true;
+ } else if (strcmp(event_name, ".wm_ready") == 0) {
+ _D("%s is created", event_name);
+ wm_ready = true;
+ }
+
+ if (wm_ready && wl_ready) {
+ wl_initialized = true;
+ __init_wl();
+ __wd = 0;
+ return false;
+ }
+
+ return true;
+}
+
+int _wayland_init(void)
+{
+ _D("wayland init");
+
+ if (access(PATH_RUN_WAYLAND, F_OK) == 0) {
+ _D("%s exists", PATH_RUN_WAYLAND);
+ wl_ready = true;
+ }
+
+ if (access(PATH_RUN_WMREADY, F_OK) == 0) {
+ _D("%s exists", PATH_RUN_WMREADY);
+ wm_ready = true;
+ }
+
+ if (wl_ready && wm_ready) {
+ wl_initialized = true;
+ __init_wl();
+ return 0;
+ }
+
+ __wd = _inotify_add_watch(PATH_RUN, IN_CREATE,
+ __wayland_monitor_cb, NULL);
+ if (__wd < 0) {
+ _E("Failed to add inotify watch");
+ return -1;
+ }
+
+ return 0;
+}
+
+void _wayland_finish(void)
+{
+ _D("wayland finish");
+
+ if (__wd > 0)
+ _inotify_rm_watch(__wd);
+
+ if (registry) {
+ wl_registry_destroy(registry);
+ registry = NULL;
+ }
+
+ if (display) {
+ wl_display_disconnect(display);
+ display = NULL;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <aul.h>
+#include <aul_sock.h>
+#include <bundle.h>
+#include <bundle_internal.h>
+
+#include "amd_app_com.h"
+#include "amd_request.h"
+#include "amd_util.h"
+#include "amd_launch.h"
+#include "amd_widget.h"
+#include "amd_app_status.h"
+#include "amd_screen_connector.h"
+#include "amd_socket.h"
+
+#ifndef AUL_K_WIDGET_OPERATION
+#define AUL_K_WIDGET_OPERATION "__WIDGET_OP__"
+#endif
+
+#ifndef AUL_K_WIDGET_FORCE
+#define AUL_K_WIDGET_FORCE "__WIDGET_FORCE__"
+#endif
+
+typedef struct _widget_t {
+ char *pkg_id;
+ char *widget_id;
+ int pid;
+ uid_t uid;
+ GList *instances;
+} widget_t;
+
+typedef struct _restart_widget_info{
+ int pid;
+ int uid;
+ char *widget_id;
+ int caller_pid;
+ char *pkgid;
+ guint timer;
+} restart_widget_info;
+
+struct widget_status_info {
+ const char *endpoint;
+ const char *widget_id;
+ const char *instance_id;
+ const char *pkg_id;
+ const char *is_fault;
+ int status;
+ int pid;
+ uid_t uid;
+};
+
+static GList *__widgets;
+static GList *__update_widgets;
+static GHashTable *__restart_widget_tbl;
+
+static int __send_status_info(struct widget_status_info *info)
+{
+ char buf[MAX_PID_STR_BUFSZ];
+ bundle *kb;
+ int r;
+
+ kb = bundle_create();
+ if (kb == NULL) {
+ _E("Out of memory");
+ return -1;
+ }
+
+ snprintf(buf, sizeof(buf), "%d", info->pid);
+ bundle_add(kb, AUL_K_COM_SENDER_PID, buf);
+ bundle_add(kb, AUL_K_WIDGET_ID, info->widget_id);
+ bundle_add_byte(kb, AUL_K_WIDGET_STATUS, &info->status, sizeof(int));
+
+ if (info->instance_id)
+ bundle_add(kb, AUL_K_WIDGET_INSTANCE_ID, info->instance_id);
+ if (info->pkg_id)
+ bundle_add(kb, AUL_K_PKGID, info->pkg_id);
+ if (info->is_fault)
+ bundle_add(kb, AUL_K_IS_FAULT, info->is_fault);
+
+ r = _app_com_send(info->endpoint, getpgid(info->pid), kb, info->uid);
+ bundle_free(kb);
+
+ return r;
+}
+
+static void __restart_faulted_widget(int pid, int uid, const char *appid,
+ const char *pkgid, int caller_pid)
+{
+ _W("restart widget pid %d uid %d appid %s caller_pid %d pkgid %s",
+ pid, uid, appid, caller_pid, pkgid);
+ _widget_send_status_to_viewer(
+ pid,
+ uid,
+ appid,
+ caller_pid,
+ AUL_WIDGET_INSTANCE_EVENT_APP_RESTART_REQUEST);
+
+ _widget_send_dead_signal_for_faulted(
+ pid,
+ uid,
+ pkgid,
+ appid);
+}
+
+void _widget_restart_faulted()
+{
+ GHashTableIter iter;
+ gpointer key, value;
+ restart_widget_info *info;
+
+ g_hash_table_iter_init(&iter, __restart_widget_tbl);
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+ info = (restart_widget_info *)value;
+ __restart_faulted_widget(info->pid, info->uid, info->widget_id,
+ info->pkgid, info->caller_pid);
+ }
+ g_hash_table_remove_all(__restart_widget_tbl);
+}
+
+static void __destroy_widget_info(gpointer data)
+{
+ restart_widget_info *info =
+ (restart_widget_info *)data;
+
+ if (info == NULL)
+ return;
+ if (info->widget_id)
+ free(info->widget_id);
+ if (info->pkgid)
+ free(info->pkgid);
+ free(info);
+}
+
+static widget_t *__find_widget_by_pid(int pid, uid_t uid)
+{
+ GList *widget_list = __widgets;
+ widget_t *widget;
+
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ if (widget->pid == pid && widget->uid == uid)
+ return widget;
+
+ widget_list = widget_list->next;
+ }
+
+ return NULL;
+}
+
+static char *__get_id_by_pid(int pid, uid_t uid)
+{
+ widget_t *widget;
+
+ widget = __find_widget_by_pid(pid, uid);
+ if (!widget)
+ return NULL;
+
+ return widget->widget_id;
+}
+
+void _widget_dead_handler(int pid, int uid,
+ const char *pkgid, int caller_pid, bool is_exit_notified,
+ bool can_restart)
+{
+ bool is_widget = false;
+ restart_widget_info *widget_info;
+ char *widget_id;
+
+ is_widget = _widget_exist(pid, uid);
+ if (!is_widget)
+ return;
+
+ widget_id = __get_id_by_pid(pid, uid);
+ _W("restart process start %s", widget_id);
+ if (!can_restart) {
+ if(!is_exit_notified) {
+ _widget_send_dead_signal_for_faulted(
+ pid,
+ uid,
+ pkgid,
+ widget_id);
+ } else {
+ _widget_send_dead_signal(pid, uid, pkgid);
+ }
+ return;
+ }
+
+ /* Restart fault widget logic start */
+ if (!is_exit_notified) {
+ /*
+ * Screen info should be removed before send dead signal
+ * If not, _app_status_cleanup will send
+ * AUL_SCREEN_CONNECTOR_EVENT_TYPE_REMOVE
+ * event to the viewer and recreated instance with same
+ * instance id info will be removed by
+ * AUL_SCREEN_CONNECTOR_EVENT_TYPE_REMOVE event.
+ */
+ _screen_connector_remove_app_screen_v2(pid, uid);
+ if (_util_check_oom()) {
+ widget_info =
+ g_hash_table_lookup(
+ __restart_widget_tbl,
+ widget_id);
+ if (widget_info == NULL) {
+ widget_info = (restart_widget_info *)
+ calloc(1, sizeof(restart_widget_info));
+ widget_info->widget_id = strdup(widget_id);
+ widget_info->pkgid = strdup(pkgid);
+ widget_info->pid = pid;
+ widget_info->uid = uid;
+ widget_info->caller_pid = caller_pid;
+ g_hash_table_insert(
+ __restart_widget_tbl,
+ widget_info->widget_id,
+ widget_info);
+ }
+ } else {
+ __restart_faulted_widget(pid, uid, widget_id,
+ pkgid,
+ caller_pid);
+ }
+ } else {
+ /*
+ * If widget package is in update process
+ * widget dead signal will be sent after
+ * update process is completed so that
+ * viewer can restart widget at that time.
+ */
+ if (_appinfo_is_pkg_updating(pkgid)) {
+ _widget_send_status_to_viewer(pid, uid, widget_id,
+ caller_pid,
+ AUL_WIDGET_INSTANCE_EVENT_APP_RESTART_REQUEST);
+ _widget_add_update_info(pkgid, pid, uid);
+ } else {
+ /* Normal exit */
+ _widget_send_dead_signal(pid, uid, pkgid);
+ }
+ }
+}
+
+static void __free_widget(gpointer data)
+{
+ widget_t *widget = (widget_t *)data;
+
+ free(widget->widget_id);
+ g_list_free_full(widget->instances, free);
+ free(widget);
+}
+
+static widget_t *__find_widget(const char *widget_id, int pid, uid_t uid)
+{
+ GList *widget_list = __widgets;
+ widget_t *widget;
+
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ if (strcmp(widget->widget_id, widget_id) == 0) {
+ if (widget->pid == pid && widget->uid == uid)
+ return widget;
+ }
+
+ widget_list = widget_list->next;
+ }
+
+ return NULL;
+}
+
+static widget_t *__find_instance(const char *widget_id, const char *instance_id)
+{
+ GList *widget_list = __widgets;
+ GList *instance_list;
+ widget_t *widget;
+
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ if (strcmp(widget->widget_id, widget_id) == 0
+ && widget->instances) {
+ instance_list = g_list_find_custom(widget->instances,
+ instance_id, (GCompareFunc)g_strcmp0);
+
+ if (instance_list)
+ return widget;
+ }
+
+ widget_list = widget_list->next;
+ }
+
+ return NULL;
+}
+
+bool _widget_exist(int pid, uid_t uid)
+{
+ GList *widget_list = __widgets;
+ widget_t *widget;
+
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ if (widget->pid == pid && widget->uid == uid)
+ return true;
+
+ widget_list = widget_list->next;
+ }
+ return false;
+}
+
+int _widget_send_status_to_viewer(int pid, uid_t uid, const char *widget_id,
+ int viewer_pid, aul_widget_instance_event_e status)
+{
+ app_status_h viewer_app_status;
+ struct widget_status_info info;
+
+ viewer_app_status = _app_status_find(viewer_pid);
+ if (viewer_app_status == NULL)
+ return -1;
+
+ info.endpoint = _app_status_get_appid(viewer_app_status);
+ info.widget_id = widget_id;
+ info.instance_id = NULL;
+ info.pkg_id = NULL;
+ info.is_fault = NULL;
+ info.status = status;
+ info.pid = pid;
+ info.uid = _app_status_get_uid(viewer_app_status);
+
+ return __send_status_info(&info);
+}
+
+int _widget_send_dead_signal(int pid, uid_t uid, const char *pkgid)
+{
+ widget_t *widget = NULL;
+ GList *widget_list = __widgets;
+ struct widget_status_info info;
+
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ if (widget->pid == pid && widget->uid == uid)
+ break;
+ widget_list = widget_list->next;
+ }
+
+ if (!widget) {
+ _E("cannot find widget pid : %d, uid %d", pid, uid);
+ return -1;
+ }
+
+ info.endpoint = "widget.status";
+ info.widget_id = widget->widget_id;
+ info.instance_id = NULL;
+ info.pkg_id = pkgid;
+ info.is_fault = "false";
+ info.status = AUL_WIDGET_LIFE_CYCLE_EVENT_APP_DEAD;
+ info.pid = pid;
+ info.uid = uid;
+
+ return __send_status_info(&info);
+}
+
+int _widget_send_dead_signal_for_faulted(int pid, uid_t uid,
+ const char *pkgid, const char *widget_id)
+{
+ struct widget_status_info info = {
+ .endpoint = "widget.status",
+ .widget_id = widget_id,
+ .instance_id = NULL,
+ .pkg_id = pkgid,
+ .is_fault = "true",
+ .status = AUL_WIDGET_LIFE_CYCLE_EVENT_APP_DEAD,
+ .pid = pid,
+ .uid = uid
+ };
+
+ return __send_status_info(&info);
+}
+
+int _widget_send_dead_signal_for_update_widget(const char *pkgid)
+{
+ widget_t *widget = NULL;
+ GList *widget_list = __update_widgets;
+ struct widget_status_info info;
+ int r;
+
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ if (strcmp(pkgid, widget->pkg_id) == 0)
+ break;
+ widget_list = widget_list->next;
+ }
+
+ if (!widget) {
+ _E("cannot find update widget pkgid : %s", pkgid);
+ return -1;
+ }
+
+ __update_widgets = g_list_remove(__update_widgets, widget);
+
+ info.endpoint = "widget.status";
+ info.widget_id = widget->widget_id;
+ info.instance_id = NULL;
+ info.pkg_id = pkgid;
+ info.is_fault = "true";
+ info.status = AUL_WIDGET_LIFE_CYCLE_EVENT_APP_DEAD;
+ info.pid = widget->pid;
+ info.uid = widget->uid;
+
+ r = __send_status_info(&info);
+
+ if (widget->widget_id)
+ free(widget->widget_id);
+ if (widget->pkg_id)
+ free(widget->pkg_id);
+ free(widget);
+
+ return r;
+}
+
+int _widget_add_update_info(const char *pkg_id, int pid, uid_t uid)
+{
+ widget_t *widget;
+ widget_t *target_widget = NULL;
+ GList *widget_list = __widgets;
+
+ if (!pkg_id)
+ return -1;
+
+ while (widget_list) {
+ target_widget = (widget_t *)widget_list->data;
+ if (target_widget->pid == pid && target_widget->uid == uid)
+ break;
+ widget_list = widget_list->next;
+ }
+ if (!target_widget) {
+ _E("cannot find target_widget pid : %d, uid %d", pid, uid);
+ return -1;
+ }
+
+ widget = (widget_t *)calloc(1, sizeof(widget_t));
+ if (!widget) {
+ _E("out of memory");
+ return -1;
+ }
+
+ widget->widget_id = strdup(target_widget->widget_id);
+ widget->uid = uid;
+ widget->pid = pid;
+ widget->pkg_id = strdup(pkg_id);
+ __update_widgets = g_list_append(__update_widgets, widget);
+
+ _D("update widget instance added: %s - %s (%d:%d)", widget->widget_id, pkg_id,
+ uid, pid);
+ return 0;
+}
+
+
+int _widget_add(const char *widget_id, const char *instance_id,
+ int pid, uid_t uid)
+{
+ widget_t *widget;
+ char *id;
+
+ if (!widget_id || !instance_id)
+ return -1;
+
+ id = strdup(instance_id);
+ if (!id) {
+ _E("out of memory");
+ return -1;
+ }
+
+ widget = __find_widget(widget_id, pid, uid);
+ if (!widget) {
+ widget = __find_instance(widget_id, instance_id);
+ if (!widget) {
+ widget = (widget_t *)calloc(1, sizeof(widget_t));
+ if (!widget) {
+ _E("out of memory");
+ free(id);
+ return -1;
+ }
+ widget->widget_id = strdup(widget_id);
+ widget->uid = uid;
+ __widgets = g_list_append(__widgets, widget);
+ }
+ widget->pid = pid;
+ }
+ if (__find_instance(widget_id, instance_id) == NULL)
+ widget->instances = g_list_append(widget->instances, id);
+ else
+ free(id);
+
+ _D("widget instance added: %s - %s (%d:%d)", widget_id, instance_id,
+ uid, pid);
+ return 0;
+}
+
+int _widget_del(const char *widget_id, const char *instance_id)
+{
+ widget_t *widget;
+ GList *stored_list;
+
+ if (!widget_id || !instance_id)
+ return -1;
+
+ widget = __find_instance(widget_id, instance_id);
+ if (!widget)
+ return -1;
+ stored_list = g_list_find_custom(widget->instances, instance_id,
+ (GCompareFunc)g_strcmp0);
+
+ if (stored_list) {
+ widget->instances = g_list_remove_link(widget->instances,
+ stored_list);
+ free(stored_list->data);
+ g_list_free(stored_list);
+ _D("widget instace deleted: %s - %s (%d:%d)", widget->widget_id,
+ instance_id, widget->uid, widget->pid);
+ return 0;
+ }
+
+ return -1;
+}
+
+int _widget_list(const char *widget_id, request_h req)
+{
+ bundle *rvalue;
+ widget_t *widget;
+ GList *widget_list = __widgets;
+ GList *instance_list;
+ char pid_buf[10];
+ int fd;
+
+ if (!widget_id)
+ return -1;
+
+ rvalue = bundle_create();
+ if (!rvalue) {
+ _E("out of memory");
+ return -1;
+ }
+
+ _D("start instance list");
+
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ if (strcmp(widget->widget_id, widget_id) == 0) {
+ instance_list = widget->instances;
+ snprintf(pid_buf, sizeof(pid_buf), "%d", widget->pid);
+ while (instance_list) {
+ _D("%s - %s", widget_id, instance_list->data);
+ bundle_add_str(rvalue, instance_list->data,
+ pid_buf);
+ instance_list = instance_list->next;
+ }
+ }
+ widget_list = widget_list->next;
+ }
+
+ _D("end instance list");
+
+ fd = _request_remove_fd(req);
+ aul_sock_send_bundle_with_fd(fd, 0, rvalue, AUL_SOCK_NOREPLY);
+
+ bundle_free(rvalue);
+
+ return 0;
+}
+
+static int __can_update_widget(bundle *kb, int pid)
+{
+ app_status_h widget_app_status;
+ const char *force;
+ int viewer_pid;
+ int focused_pid;
+
+ force = bundle_get_val(kb, AUL_K_WIDGET_FORCE);
+ if (force && strcmp(force, "true") == 0)
+ return 0;
+
+ widget_app_status = _app_status_find(pid);
+ if (widget_app_status == NULL)
+ return -EINVAL;
+
+ viewer_pid = _app_status_get_org_caller_pid(widget_app_status);
+ focused_pid = _launch_get_focused_pid();
+ if (viewer_pid != focused_pid) {
+ _D("The viewer app(%d) doesn't have focus", viewer_pid);
+ return -ECANCELED;
+ }
+
+ return 0;
+}
+
+int _widget_update(const char *widget_id, request_h req)
+{
+ char *instance_id = NULL;
+ char *appid = NULL;
+ bundle *kb = _request_get_bundle(req);
+ int ret = -1;
+ widget_t *widget;
+ GList *widget_list = __widgets;
+ bool dummy;
+ bool dummy_mode;
+ const char *operation;
+ bool update;
+ uid_t target_uid = _request_get_target_uid(req);
+
+ if (!kb || !widget_id) {
+ _request_send_result(req, -EINVAL);
+ return -1;
+ }
+
+ bundle_get_str(kb, AUL_K_APPID, &appid);
+ if (!appid) {
+ _E("missing appid:%s", widget_id);
+ _request_send_result(req, -EINVAL);
+ return -1;
+ }
+
+ operation = bundle_get_val(kb, AUL_K_WIDGET_OPERATION);
+ if (operation && strcmp(operation, "update") == 0)
+ update = true;
+ else
+ update = false;
+
+ bundle_get_str(kb, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
+ if (!instance_id) { /* all instances */
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ widget_list = widget_list->next;
+ if (strcmp(widget->widget_id, widget_id) == 0 &&
+ widget->uid == target_uid) {
+ bundle_del(kb, AUL_K_TARGET_PID);
+ bundle_add_byte(kb, AUL_K_TARGET_PID,
+ (void *)&widget->pid,
+ sizeof(widget->pid));
+
+ if (update) {
+ ret = __can_update_widget(kb,
+ widget->pid);
+ if (ret != 0) {
+ _W("Cannot update widget(%d)",
+ widget->pid);
+ _request_send_result(req, ret);
+ continue;
+ }
+ }
+
+ ret = _launch_start_app(appid, req, &dummy,
+ &dummy_mode, false);
+ _D("update widget: %s(%d)", widget->widget_id,
+ widget->pid);
+ }
+ }
+ } else {
+ widget = __find_instance(widget_id, instance_id);
+ if (widget) {
+ bundle_del(kb, AUL_K_TARGET_PID);
+ bundle_add_byte(kb, AUL_K_TARGET_PID,
+ (void *)&widget->pid, sizeof(widget->pid));
+
+ if (update) {
+ ret = __can_update_widget(kb, widget->pid);
+ if (ret != 0) {
+ _E("Cannot update widget");
+ _request_send_result(req, ret);
+ return ret;
+ }
+ }
+ }
+
+ ret = _launch_start_app(appid, req, &dummy, &dummy_mode, false);
+ _D("update widget: %s", widget_id);
+ }
+
+ return ret;
+}
+
+int _widget_cleanup(int pid, uid_t uid)
+{
+ GList *widget_list = __widgets;
+ widget_t *widget;
+
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ widget_list = widget_list->next;
+ if (widget->pid == pid && widget->uid == uid) {
+ if (widget->instances)
+ g_list_free_full(widget->instances, free);
+ __widgets = g_list_remove(__widgets, widget);
+ }
+ }
+
+ _D("cleanup widget %d:%d", pid, uid);
+
+ return 0;
+}
+
+int _widget_get_pid(const char *widget_id, const char *instance_id)
+{
+ widget_t *widget;
+
+ widget = __find_instance(widget_id, instance_id);
+ if (!widget)
+ return -1;
+
+ return widget->pid;
+}
+
+int _widget_count(const char *widget_id, uid_t uid)
+{
+ widget_t *widget;
+ GList *widget_list = __widgets;
+ GList *instance_list;
+ int count = 0;
+
+ if (!widget_id)
+ return -1;
+
+ while (widget_list) {
+ widget = (widget_t *)widget_list->data;
+ _D("widget %s", widget->widget_id);
+ if (strcmp(widget->widget_id, widget_id) == 0 &&
+ widget->uid == uid) {
+ instance_list = widget->instances;
+ if (instance_list)
+ count += g_list_length(instance_list);
+ _D("widget count %d", count);
+ }
+ widget_list = widget_list->next;
+ }
+
+ return count;
+}
+
+int _widget_verify_cmd(request_h req)
+{
+ bundle *kb = _request_get_bundle(req);
+ const char *command;
+ const char *instance_id;
+ const char *widget_id;
+ widget_t *widget;
+
+ if (!kb) {
+ _E("invalid argument");
+ return -1;
+ }
+
+ widget_id = bundle_get_val(kb, AUL_K_WIDGET_ID);
+ if (!widget_id)
+ return 0;
+
+ instance_id = bundle_get_val(kb, AUL_K_WIDGET_INSTANCE_ID);
+ if (!instance_id)
+ return 0;
+
+ command = bundle_get_val(kb, AUL_K_WIDGET_OPERATION);
+ if (!command)
+ return 0;
+
+ if (strcmp(command, "create") == 0)
+ return 0;
+
+ widget = __find_instance(widget_id, instance_id);
+ if (!widget) {
+ _E("invalid command: %s - target instance %s is not exist",
+ command, instance_id);
+ return -EREJECTED;
+ }
+
+ return 0;
+}
+
+int _widget_init(void)
+{
+ _D("widget init");
+ __restart_widget_tbl =
+ g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, __destroy_widget_info);
+
+ return 0;
+}
+
+void _widget_fini(void)
+{
+ _D("widget fini");
+
+
+ if (__restart_widget_tbl) {
+ g_hash_table_destroy(__restart_widget_tbl);
+ __restart_widget_tbl = NULL;
+ }
+
+ if (__widgets)
+ g_list_free_full(__widgets, __free_widget);
+}
+
+void _widget_verify_instance(bundle *kb, int pid, uid_t uid)
+{
+ const char *operation;
+ const char *instance_id;
+ const char *widget_id;
+ widget_t *widget;
+ struct widget_status_info info;
+
+ if (kb == NULL)
+ return;
+
+ operation = bundle_get_val(kb, AUL_K_WIDGET_OPERATION);
+ if (operation == NULL)
+ return;
+
+ if (strcmp(operation, "create") != 0)
+ return;
+
+ widget_id = bundle_get_val(kb, AUL_K_WIDGET_ID);
+ if (widget_id == NULL)
+ return;
+
+ instance_id = bundle_get_val(kb, AUL_K_WIDGET_INSTANCE_ID);
+ if (instance_id == NULL)
+ return;
+
+ widget = __find_instance(widget_id, instance_id);
+ if (widget)
+ return;
+
+ info.endpoint = "widget.status";
+ info.widget_id = widget_id;
+ info.instance_id = instance_id;
+ info.pkg_id = NULL;
+ info.is_fault = NULL;
+ info.status = AUL_WIDGET_INSTANCE_EVENT_CREATE_ABORTED;
+ info.pid = pid;
+ info.uid = uid;
+
+ __send_status_info(&info);
+}
+
+static bundle *__create_bundle(widget_t *widget)
+{
+ char buf[MAX_PID_STR_BUFSZ];
+ app_status_h app_status;
+ bundle *b;
+
+ app_status = _app_status_find(widget->pid);
+ if (app_status == NULL)
+ return NULL;
+
+ b = bundle_create();
+ if (b == NULL) {
+ _E("Out of memory");
+ return NULL;
+ }
+
+ snprintf(buf, sizeof(buf), "%d", widget->pid);
+ bundle_add_str(b, AUL_K_PID, buf);
+ bundle_add_str(b, AUL_K_APPID, _app_status_get_appid(app_status));
+ bundle_add_str(b, AUL_K_PKGID, _app_status_get_pkgid(app_status));
+ bundle_add_str(b, AUL_K_EXEC, _app_status_get_app_path(app_status));
+ bundle_add_str(b, AUL_K_WIDGET_ID, widget->widget_id);
+
+ return b;
+}
+
+static int __send_running_info(widget_t *widget, int fd)
+{
+ char buf[MAX_PID_STR_BUFSZ];
+ const char *instance_id;
+ unsigned int surf;
+ bundle_raw *b_raw = NULL;
+ int len = 0;
+ GList *iter;
+ bundle *b;
+ int r;
+
+ b = __create_bundle(widget);
+ if (b == NULL) {
+ _E("Failed to create bundle");
+ aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR,
+ NULL, 0, AUL_SOCK_NOREPLY);
+ return -1;
+ }
+
+ iter = widget->instances;
+ while (iter) {
+ instance_id = (const char *)iter->data;
+ surf = _screen_connector_get_surface_id(instance_id,
+ widget->uid);
+ snprintf(buf, sizeof(buf), "%u", surf);
+ bundle_del(b, AUL_K_WID);
+ bundle_add_str(b, AUL_K_WID, buf);
+ bundle_del(b, AUL_K_WIDGET_INSTANCE_ID);
+ bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
+
+ bundle_encode(b, &b_raw, &len);
+ if (b_raw == NULL) {
+ _E("Failed to encode bundle");
+ aul_sock_send_raw_with_fd(fd, APP_GET_INFO_ERROR,
+ NULL, 0, AUL_SOCK_NOREPLY);
+ bundle_free(b);
+ return -1;
+ }
+
+ r = aul_sock_send_raw_with_fd(fd, APP_GET_INFO_OK,
+ (unsigned char *)b_raw, len,
+ AUL_SOCK_ASYNC | AUL_SOCK_BUNDLE);
+ if (r < 0) {
+ _E("Failed to send raw data: %d", r);
+ free(b_raw);
+ bundle_free(b);
+ return -1;
+ }
+ free(b_raw);
+ b_raw = NULL;
+
+ iter = g_list_next(iter);
+ }
+ free(b_raw);
+ bundle_free(b);
+
+ return 0;
+}
+
+int _widget_send_running_info(request_h req)
+{
+ uid_t target_uid = _request_get_target_uid(req);
+ int fd = _request_remove_fd(req);
+ widget_t *widget;
+ GList *iter;
+ int count = 0;
+ int r;
+
+ iter = __widgets;
+ while (iter) {
+ widget = (widget_t *)iter->data;
+ if (widget && widget->uid == target_uid)
+ count += g_list_length(widget->instances);
+
+ iter = g_list_next(iter);
+ }
+
+ if (count == 0) {
+ _E("Widget doesn't exist");
+ _send_result_to_client(fd, -1);
+ return -1;
+ }
+ _send_result_to_client_v2(fd, count);
+
+ iter = __widgets;
+ while (iter) {
+ widget = (widget_t *)iter->data;
+ if (widget && widget->uid == target_uid) {
+ r = __send_running_info(widget, fd);
+ if (r < 0)
+ break;
+ }
+ iter = g_list_next(iter);
+ }
+ close(fd);
+
+ return 0;
+}